overloadedliterals   ![Latest Version] ![License] ![requires] ![testsbadge]

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 and CStr.

Usage

Add the overloaded_literals 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:

```rust 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 raw byte str literals (Requires a similar abstraction as TypeStr.)