numera/number/integer/nz/ops/
mod.rs

1// numera::number::integer::nz::ops
2//
3//!
4//
5
6use super::*;
7use core::{
8    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8},
9    ops::{Add, Rem, Sub}, // Div, Mul, Neg
10};
11
12// impl ops (will panic on overflow, and when result is 0)
13macro_rules! impl_integer_ops {
14    // impl all ops for multiple integer types
15    ($($t:ident, $inner:ident),+) => {
16        $(
17            impl_integer_ops![ops: $t, $inner];
18        )+
19    };
20
21    // impl all ops for a single integer type
22    //
23    // $t: integer type. e.g. NegativeInteger8
24    (ops: $t:ident, $inner:ident) => {
25        impl_integer_ops![bin_ops: $t, $inner, Add, add, Sub, sub, Rem, rem];
26    };
27
28    // impl multiple binary ops for a single integer type
29    //
30    // $t: integer type. e.g. Integer8
31    // $(
32    //   $op: operation. e.g. Add
33    //   $fn: operation fn. e.g. add
34    // )
35    (bin_ops: $t:ident, $inner:ident, $($op:ident, $fn:ident),+) => {
36        $(
37            impl_integer_ops![bin_op: $t, $inner, $op, $fn];
38        )+
39    };
40
41    // impl a binary op for a single integer type
42    //
43    // $t: integer type. e.g. NegativeInteger8
44    // $inner: inner primitive type. e.g. NonZeroU8
45    // $op: operation. e.g. Add
46    // $fn: operation fn. e.g. add
47    (bin_op: $t:ident, $inner:ident, $op:ident, $fn:ident) => {
48        impl $op for $t {
49            type Output = $t;
50
51            fn $fn(self, rhs: Self::Output) -> Self::Output {
52                $t($inner::new(self.0.get().$fn(rhs.0.get())).expect("Invalid value 0."))
53            }
54        }
55    };
56
57    // impl open negation
58    //
59    // $t: integer type. e.g. Integer8
60    (un_op: $t:ident, $inner:ident, $op:ident, $fn:ident) => {
61        impl $op for $t {
62            type Output = $t;
63
64            fn $fn(self) -> Self::Output {
65                $t($inner::new(self.0.get().$fn()).expect("Invalid value 0."))
66            }
67        }
68    };
69}
70impl_integer_ops![
71    NegativeInteger8,
72    NonZeroU8,
73    NegativeInteger16,
74    NonZeroU16,
75    NegativeInteger32,
76    NonZeroU32,
77    NegativeInteger64,
78    NonZeroU64,
79    NegativeInteger128,
80    NonZeroU128
81];
82
83#[cfg(test)]
84mod tests {
85    use crate::all::*;
86
87    #[test]
88    fn nz_ops() -> NumeraResult<()> {
89        // assert![Nz8::new(5).is_err()]; // not an error currently
90        let _n5 = Nz8::new_neg(5)?;
91        let _n7 = Nz8::new_neg(7)?;
92
93        assert_eq![_n7 + _n5, Nz8::new_neg(12)?];
94        assert_eq![_n7 - _n5, Nz8::new_neg(2)?];
95
96        #[cfg(feature = "std")]
97        {
98            use std::panic::catch_unwind;
99
100            // positive
101            assert![catch_unwind(|| _n5 - _n7).is_err()];
102            // zero
103            assert![catch_unwind(|| _n7 - _n7).is_err()];
104        }
105        Ok(())
106    }
107    #[test]
108    #[should_panic]
109    fn nz_ops_panic_underflow() {
110        let _min = Nz8::MIN;
111        let _res = _min + Nz8::new_neg(8).expect("new_neg(8)");
112        assert_eq![_res, Nz8::new_neg(2).unwrap()];
113    }
114    #[test]
115    #[should_panic]
116    fn nz_ops_panic_overflow() {
117        let _max = Nz8::MAX;
118        let _ = _max - Nz8::new_neg(9).expect("new_neg(9)");
119    }
120}