1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! Extends the traits from [`num_traits::identities`] to use an associated constant.
//!
//! [`num_traits::identities`]: https://rust-num.github.io/num/num_traits/identities/index.html
//!
//! # Examples
//!
//! ```rust
//! #![feature(const_fn)]
//!
//! # extern crate const_identities;
//! use const_identities::ConstZero;
//!
//! pub struct Newtype<T>(pub T);
//!
//! impl<T: ConstZero> Newtype<T> {
//!     pub const fn zero() -> Self {
//!         Newtype(T::ZERO)
//!     }
//! }
//!
//! assert_eq!(Newtype::<i32>::zero().0, 0);
//! ```

extern crate num_traits;
extern crate num_complex;

use std::ops;
use std::num::Wrapping;

use num_traits::{Num, identities::{Zero, One}};
use num_complex::Complex;

/// The additive identity element for `Self`, expressed as an associated constant.
pub trait ConstZero: Zero {
    /// The additive identity.
    const ZERO: Self;
}

/// The multiplicative identity element for `Self`, expressed as an associated constant.
pub trait ConstOne: One {
    /// The multiplicative identity.
    const ONE: Self;
}

macro_rules! const_zero_one {
    (
        ($zero:expr, $one:expr) => [
            $( $T:ident ),* $(,)*
        ]
    ) => {
        $(
            impl ConstZero for $T {
                const ZERO: Self = $zero;
            }

            impl ConstOne for $T {
                const ONE: Self = $one;
            }
         )*
    }
}

const_zero_one! {
    (0, 1) => [
        i8, i16, i32, i64, isize,
        u8, u16, u32, u64, usize,
    ]
}

const_zero_one! {
    (0., 1.) => [f32, f64]
}

impl<T> ConstZero for Wrapping<T>
    where T: ConstZero,
          Wrapping<T>: ops::Add<Output=Wrapping<T>>,
{
    const ZERO: Self = Wrapping(T::ZERO);
}

impl<T> ConstOne for Wrapping<T>
    where T: ConstOne,
          Wrapping<T>: ops::Mul<Output=Wrapping<T>>,
{
    const ONE: Self = Wrapping(T::ONE);
}

impl<T> ConstZero for Complex<T>
    where T: Clone + Num + ConstZero
{
    const ZERO: Self = Complex { re: T::ZERO, im: T::ZERO };
}

impl<T> ConstOne for Complex<T>
    where T: Clone + Num + ConstZero + ConstOne
{
    const ONE: Self = Complex { re: T::ONE, im: T::ZERO };
}