Overloaded Literals to construct your datatypes without boilerplate and with compile-time validation.

Features

Ships with implementations for std's various NonZero and Wrapping structs

Usage

Add the [macro@overloaded_literals] as attribute to a function. This will rewrite any literals to calls to a trait with the literal as generic const parameter. Because a trait is used, construction of any desired target type which implements the type happens automatically:

```rust use std::num::NonZeroI8; use overloadedliterals::overloadedliterals;

[overloaded_literals]

fn example() { let three: NonZeroI8 = 3; let result = three.saturatingmul(2); // <- This '2' also turns into a NonZero automatically because of the signature of saturating_mul. let six = 6; // <- And this '6' as well asserteq!(result, six); } example() ```

Trait implementations can perform compile-time validation (using 'const evaluation') on the passed literal. This means that invalid literals are rejected at compile-time with a descriptive error message:

```compilefail use std::num::NonZeroI8; use overloadedliterals::overloaded_literals;

[overloaded_literals]

fn mistake() -> NonZeroI8 { let oops: NonZeroI8 = 0; // <- compile error 'NonZero integer literal was 0'. oops.saturating_mul(2) } mistake(); ```

Implementing the traits

As an example, here are the trait implementations for a type EvenI32 which ensures that the value it stores is even, similarly to how [NonZeroI32] ensures that the contained value is non-zero.

```rust use overloadedliterals::{overloadedliterals, FromLiteralUnsigned, FromLiteralSigned};

[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]

pub struct EvenI32(i32);

impl EvenI32 { fn new(val: i32) -> Option { if val % 2 != 0 { None } else { Some(EvenI32(val)) } } }

// Called for 0 and positive literals: impl FromLiteralUnsigned for EvenI32 { const VALIDLITERAL: u128 = { if LIT % 2 != 0 { panic!("Odd EvenI32 integer literal") } else { LIT } }; fn intoself() -> Self { let raw = >::VALID_LITERAL as i32; EvenI32(raw) } }

// Called for negative literals: impl FromLiteralSigned for EvenI32 { const VALIDLITERAL: i128 = { if LIT % 2 != 0 { panic!("Odd EvenI32 integer literal") } else { LIT } }; fn intoself() -> Self { let raw = >::VALID_LITERAL as i32; EvenI32(raw) } }

[overloaded_literals]

fn example() { let x: EvenI32 = 100; // let y: EvenI32 = 7; // <- This would cause a compile error :-) } example() ```

Another full example, on how to accept a str literal for your datatype, can be found in the documentation of [FromLiteralStr].

Missing features

The following features are currently missing and would be straightforward additions to later versions of the library: - Support for char literals - Support for float literals (Requires some extra work since floats are not yet supported in generic const contexts.) - Support for raw byte str literals (Requires a similar abstraction as [TypeStr].) - Implementations of FromLiteralStr for CStr and other str-like types.