polymorphic-constant 0.1.1

A macro to define a numerical constant in multiple types at once
Documentation
# Polymorphic Constant

A macro to generate numerical constants in multiple types at once.

You can have the number Pi be available in f64 or f32

It was designed with three goals in mind:

* Catch all overflow errors on compile-time
* Minimize the code footprint
* Be readable and easy to use

This is meant as a temporary fix to the year-long debate over [Rust Pre-RFC #1337](https://internals.rust-lang.org/t/pre-rfc-untyped-constants/1337/)

## Syntax

```rust
    use polymorphic_constant::polymorphic_constant;

    polymorphic_constant! {
        static PI: f32 | f64 = 3.141592653589793;
    }

    // Which can then be used as

    fn pi_squared () -> f64 {
        PI.f64 * PI.f64
    }
```

A few features are supported:

```rust
    use polymorphic_constant::polymorphic_constant;

    polymorphic_constant! {

        /// Doc comment attributes
        static PI: f32 | f64 = 3.141592653589793;

        // Visibility modifiers (for both constant and type)
        pub (crate) static E: f32 | f64 = 2.7182818284590452;

        // Nonzero numeric types (NonZeroI32, NonZeroU8, etc)
        static ASCII_LINE_RETURN: u8 | nz_u8 = 10;
    }

    // You can handle constants like any static struct
    static PI_COPY: PI = PI;
    static PI_F32: f32 = PI.f32;
    
    // Into is implemented for every variant of the constant
    fn times_pi<T: std::ops::Mul<T>> (value: T) -> <T as std::ops::Mul>::Output
    where
        PI: Into<T>,
    {
        value * PI.into()
    }

    assert_eq!(times_pi(2.0), 6.283185307179586f64);
```

## Safety

This system ensures that you keep all the safeties and warnings given by rust, but no more

Any incompatible type will prevent compilation:

* Float literals cannot be stored if it would convert them to infinity
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAILS: f32 | f64 =  3141592653589793238462643383279502884197.0;
    # }
```

* Literals cannot be stored in a type too small to hold them
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAILS: u64 | nz_i8 = 128;
    # }
```

* Negative numbers cannot be stored in unsigned types
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAILS: i64 | u8 = -1;
    # }
```

* 0 cannot be stored in non-zero types
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAILS: nz_u8 | nz_u16 | nz_u32 = 0;
    # }
```

* However, floats may lose precision, and a lot of it
```rust
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static SUCCEEDS: f32 = 3.141592653589793238462643383279;
    # }
```

## Warnings

Currently, the same constant cannot hold both int and float variants
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAIL: i32 = 0.1;
    # }
```
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAIL: f32 = 0;
    # }
```

The constant also has to be initialized with an untyped literal
```compile_fail
    # use polymorphic_constant::polymorphic_constant;
    
    # polymorphic_constant! {
        static FAIL: i32 = 0u32;
    # }
```

It is still unclear if accepting the examples above could be dangerous,
thus the conservative choice.

## Example

```
use polymorphic_constant::polymorphic_constant;

polymorphic_constant! {
    static HEIGHT: i8 | u8 | i16 | u16 | i32 | u32 = 16;
    static WIDTH: i8 | u8 | i16 | u16 | i32 | u32 = 32;
}

fn main() {
    let size = HEIGHT.i16 * WIDTH.i16;

    assert_eq!(size, 16 * 32);

    let height_copy:i32 = HEIGHT.into();

    assert_eq!(HEIGHT.i32, height_copy);
}
```

## Support

I would love any feedback on usage, for future ameliorations and features.