devela/num/traits/
impls.rs

1// devela::num::trait::impls
2//
3//!
4//
5
6#[cfg(all(_float··, not(feature = "std")))]
7use crate::iif;
8#[allow(unused_imports)]
9use crate::num::{
10    niche::*,
11    Num,
12    NumError::{self, Invalid, Unspecified},
13    NumResult as Result,
14};
15use crate::paste;
16#[cfg(_float··)]
17use crate::{Add, Div, Mul, Neg, Rem, Sub};
18
19// $p:   the primitive type
20// $cap:  the capability feature that enables the given implementation. E.g "_int_i8".
21macro_rules! impl_num {
22    [] => {
23        impl_num![i i8:"_int_i8", i16:"_int_i16", i32:"_int_i32",
24            i64:"_int_i64", i128:"_int_i128", isize:"_int_isize"];
25        impl_num![u u8:"_int_u8", u16:"_int_u16", u32:"_int_u32",
26            u64:"_int_u64", u128:"_int_u128", usize:"_int_usize"];
27        impl_num![f f32:"_float_f32", f64:"_float_f64"];
28
29        // niche types
30        // impl_num![non_value i i8:"_non_value_i8", i16:"_non_value_i16", i32:"_non_value_i32",
31        //     i64:"_non_value_i64", i128:"_non_value_i128", isize:"_non_value_isize"];
32        //
33        // impl_num![non_value u u8:"_non_value_u8", u16:"_non_value_u16", u32:"_non_value_u32",
34        //     u64:"_non_value_u64", u128:"_non_value_u128", usize:"_non_value_usize"];
35    };
36
37    // Implements `Num` for signed integer types
38    // --------------------------------------------------------------------------------------------
39    (i $($p:ident : $cap:literal),+) => { $( impl_num![@i $p : $cap]; )+ };
40    (@i $p:ident : $cap:literal) => { paste! {
41        // i*
42        #[cfg(feature = $cap )]
43        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
44        impl Num for $p {
45            type Inner = $p;
46            type Out = $p;
47            type Rhs = $p;
48
49            // base
50            fn num_into(self) -> Self::Inner { self }
51            fn num_from(from: Self::Inner) -> Result<Self> { Ok(from) }
52            fn num_from_ref(from: &Self::Inner) -> Result<Self> { Ok(*from) }
53            fn num_set(&mut self, value: Self::Inner) -> Result<()> { *self = value; Ok(()) }
54            fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
55                *self = *value; Ok(())
56            }
57
58            // ident
59            fn num_is_zero(&self) -> Result<bool> { Ok(*self == 0) }
60            fn num_is_one(&self) -> Result<bool> { Ok(*self == 1) }
61            fn num_get_zero() -> Result<Self> { Self::num_from(0) }
62            fn num_get_one() -> Result<Self> { Self::num_from(1) }
63            fn num_set_zero(&mut self) -> Result<()> { *self = 0; Ok(()) }
64            fn num_set_one(&mut self) -> Result<()> { *self = 1; Ok(()) }
65
66            // ops
67            impl_num![op2_checked Self => add, mul, sub, div, rem];
68            impl_num![op1_checked Self => neg, abs];
69        }
70
71        // NonZeroI*
72        #[cfg(feature = $cap )]
73        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
74        impl Num for [<NonZero $p:camel>] {
75            type Inner = $p;
76            type Out = [<NonZero $p:camel>];
77            type Rhs = [<NonZero $p:camel>];
78
79            // base
80            fn num_into(self) -> Self::Inner { [< NonZero $p:camel >]::get(self) }
81            fn num_from(from: Self::Inner) -> Result<Self> { Self::new(from).ok_or(Invalid) }
82            fn num_from_ref(from: &Self::Inner) -> Result<Self> { Self::new(*from).ok_or(Invalid) }
83            fn num_set(&mut self, value: Self::Inner) -> Result<()> {
84                *self = Self::new(value).ok_or(Invalid)?; Ok(())
85            }
86            fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
87                *self = Self::new(*value).ok_or(Invalid)?; Ok(())
88            }
89
90            // ident
91            fn num_is_zero(&self) -> Result<bool> { Ok(false) }
92            fn num_is_one(&self) -> Result<bool> { self.get().num_is_one() }
93            fn num_get_zero() -> Result<Self> { NumError::ni() }
94            fn num_get_one() -> Result<Self> { Ok(Self::new(1).unwrap()) }
95            fn num_set_zero(&mut self) -> Result<()> { NumError::ni() }
96
97            /// # Features
98            /// Makes use of the `unsafe_niche` feature if enabled.
99            fn num_set_one(&mut self) -> Result<()> {
100                #[cfg(any(feature = "safe_num", not(feature = "unsafe_niche")))]
101                { *self = Self::new(1).unwrap(); Ok(()) }
102
103                #[cfg(all(not(feature = "safe_num"), feature = "unsafe_niche"))]
104                // SAFETY: we are using a constant
105                { *self = unsafe { Self::new_unchecked(1) }; Ok(()) }
106            }
107
108            // ops
109            impl_num![op2_checked Self => mul];
110            impl_num![op1_checked Self => neg, abs];
111            impl_num![op2_get_checked Self => add, sub, div, rem];
112        }
113    }};
114
115    // Implements `Num` for signed integer niche types
116    // --------------------------------------------------------------------------------------------
117    (non_value i $($p:ident : $cap:literal),+) => { $( impl_num![@non_value i $p : $cap]; )+ };
118    (@non_value i $p:ident : $cap:literal) => { paste! {
119        // NonValueI*
120        #[cfg(feature = $cap)]
121        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
122        impl<const V: $p> Num for [<NonValue $p:camel>]<V> {
123            type Inner = $p;
124            type Out =  [<NonValue $p:camel>]<V>;
125            type Rhs =  [<NonValue $p:camel>]<V>;
126            impl_num![custom_i_body];
127        }
128    }};
129
130    // Implements `Num` for unsigned integer types
131    // --------------------------------------------------------------------------------------------
132    (u $($p:ident : $cap:literal),+) => { $( impl_num![@u $p : $cap]; )+ };
133    (@u $p:ident : $cap:literal) => { paste! {
134        // u*
135        #[cfg(feature = $cap )]
136        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
137        impl Num for $p {
138            type Inner = $p;
139            type Out = $p;
140            type Rhs = $p;
141
142            // base
143            fn num_into(self) -> Self::Inner { self }
144            fn num_from(from: Self::Inner) -> Result<Self> { Ok(from) }
145            fn num_from_ref(from: &Self::Inner) -> Result<Self> { Ok(*from) }
146            fn num_set(&mut self, value: Self::Inner) -> Result<()> { *self = value; Ok(()) }
147            fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
148                *self = *value; Ok(())
149            }
150
151            // ident
152            fn num_is_zero(&self) -> Result<bool> { Ok(*self == 0) }
153            fn num_is_one(&self) -> Result<bool> { Ok(*self == 1) }
154            fn num_get_zero() -> Result<Self> { Self::num_from(0) }
155            fn num_get_one() -> Result<Self> { Self::num_from(1) }
156            fn num_set_zero(&mut self) -> Result<()> { *self = 0; Ok(()) }
157            fn num_set_one(&mut self) -> Result<()> { *self = 1; Ok(()) }
158
159            // ops
160            impl_num![op2_checked Self => add, mul, sub, div, rem];
161            impl_num![op1_checked Self => neg];
162            fn num_abs(self) -> Result<Self> { Ok(self) }
163            fn num_ref_abs(&self) -> Result<Self> { Ok(*self) }
164        }
165
166        // NonZeroU*
167        #[cfg(feature = $cap )]
168        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
169        impl Num for [<NonZero $p:camel>] {
170            type Inner = $p;
171            type Out = [<NonZero $p:camel>];
172            type Rhs = [<NonZero $p:camel>];
173
174            // base
175            fn num_into(self) -> Self::Inner { [< NonZero $p:camel >]::get(self) }
176            fn num_from(from: Self::Inner) -> Result<Self> { Self::new(from).ok_or(Invalid) }
177            fn num_from_ref(from: &Self::Inner) -> Result<Self> { Self::new(*from).ok_or(Invalid) }
178            fn num_set(&mut self, value: Self::Inner) -> Result<()> {
179                *self = Self::new(value).ok_or(Invalid)?; Ok(())
180            }
181            fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
182                *self = Self::new(*value).ok_or(Invalid)?; Ok(())
183            }
184
185            // ident
186            fn num_is_zero(&self) -> Result<bool> { Ok(false) }
187            fn num_is_one(&self) -> Result<bool> { Ok(self.get() == 1) }
188            fn num_get_zero() -> Result<Self> { NumError::ni() }
189            fn num_get_one() -> Result<Self> { Ok(Self::new(1).unwrap()) }
190            fn num_set_zero(&mut self) -> Result<()> { NumError::ni() }
191            /// # Features
192            /// Makes use of the `unsafe_niche` feature if enabled.
193            fn num_set_one(&mut self) -> Result<()> {
194                #[cfg(any(feature = "safe_num", not(feature = "unsafe_niche")))]
195                { *self = Self::new(1).unwrap(); Ok(()) }
196
197                #[cfg(all(not(feature = "safe_num"), feature = "unsafe_niche"))]
198                // SAFETY: we are using a constant
199                { *self = unsafe { Self::new_unchecked(1) }; Ok(()) }
200            }
201
202            // ops
203            impl_num![op2_checked Self => mul]; // add takes an u8 so goes below
204            impl_num![op2_get_checked Self => add, sub, div, rem];
205            impl_num![op1_none Self => neg]; // no neg for NonZeroU*
206            fn num_abs(self) -> Result<Self> { Ok(self) }
207            fn num_ref_abs(&self) -> Result<Self> { Ok(*self) }
208        }
209    }};
210
211    // Implements `Num` for unsigned integer types
212    // --------------------------------------------------------------------------------------------
213    (non_value u $($p:ident : $cap:literal),+) => { $( impl_num![@non_value u $p : $cap]; )+ };
214    (@non_value u $p:ident : $cap:literal) => { paste! {
215        // NonValueU*
216        #[cfg(feature = $cap)]
217        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
218        impl<const V: $p> Num for [<NonValue $p:camel>]<V> {
219            type Inner = $p;
220            type Out = [<NonValue $p:camel>]<V>;
221            type Rhs = [<NonValue $p:camel>]<V>;
222            impl_num![custom_u_body]; }
223    }};
224
225    // Implements `Num` for the floating-point types
226    // --------------------------------------------------------------------------------------------
227    (f $($p:ident : $cap:literal),+) => { $( impl_num![@f $p : $cap]; )+ };
228    (@f $p:ident : $cap:literal) => {
229        // f*
230        #[cfg(feature = $cap )]
231        #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
232        impl Num for $p { paste! {
233            type Inner = $p;
234            type Out = $p;
235            type Rhs = $p;
236
237            // base
238            fn num_into(self) -> Self::Inner { self }
239            fn num_from(from: Self::Inner) -> Result<Self> { Ok(from) }
240            fn num_from_ref(from: &Self::Inner) -> Result<Self> { Ok(*from) }
241            fn num_set(&mut self, value: Self::Inner) -> Result<()> { *self = value; Ok(()) }
242            fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
243                *self = *value; Ok(())
244            }
245
246            // ident
247            #[doc = "This implementation has a tolerance of 5 × [`EPSILON`][" $p "::EPSILON]"]
248            fn num_is_zero(&self) -> Result<bool> {
249                Ok(self.num_ref_abs()? < 5.0 * <$p>::EPSILON)
250            }
251            #[doc = "This implementation has a tolerance of 5 × [`EPSILON`][" $p "::EPSILON]"]
252            fn num_is_one(&self) -> Result<bool> {
253                Ok(self.num_sub(1.0)?.num_ref_abs()? < 5.0 * <$p>::EPSILON)
254            }
255            fn num_get_zero() -> Result<Self> { Self::num_from(0.0) }
256            fn num_get_one() -> Result<Self> { Self::num_from(1.0) }
257            fn num_set_zero(&mut self) -> Result<()> { *self = Self::num_from(0.0)?; Ok(()) }
258            fn num_set_one(&mut self) -> Result<()> { *self = Self::num_from(1.0)?; Ok(()) }
259
260            // ops
261            impl_num![op2_float Self => add, mul, sub, div, rem];
262            impl_num![op1_float Self => neg];
263
264            fn num_abs(self) -> Result<Self> {
265                #[cfg(feature = "std")]
266                return Ok($p::abs(self));
267                #[cfg(not(feature = "std"))]
268                Ok(iif![self >= 0.0; self; -self])
269            }
270            fn num_ref_abs(&self) -> Result<Self> {
271                #[cfg(feature = "std")]
272                return Ok($p::abs(*self));
273                #[cfg(not(feature = "std"))]
274                Ok(iif![*self >= 0.0; *self; -*self])
275            }
276        }}
277    };
278
279    // Inner helpers for the identical body of NonValue, NonRange, InRange
280    // with a common body and different ops for signed and unsigned
281    // ============================================================================================
282    (custom_i_body) => {
283        impl_num![custom_body];
284        // ops
285        impl_num![op2_get_checked Self => add, mul, sub, div, rem];
286        impl_num![op1_get_checked Self => neg, abs];
287    };
288    (custom_u_body) => {
289        impl_num![custom_body];
290        // ops
291        impl_num![op2_get_checked Self => add, mul, sub, div, rem];
292        impl_num![op1_get_checked Self => neg];
293        fn num_abs(self) -> Result<Self> { Ok(self) }
294        fn num_ref_abs(&self) -> Result<Self> { Ok(*self) }
295    };
296    (custom_body) => {
297        // base
298        fn num_into(self) -> Self::Inner { self.get() }
299        fn num_from(from: Self::Inner) -> Result<Self> { Self::new(from).ok_or(Invalid) }
300        fn num_from_ref(from: &Self::Inner) -> Result<Self> { Self::new(*from).ok_or(Invalid) }
301        fn num_set(&mut self, value: Self::Inner) -> Result<()> {
302            *self = Self::num_from(value)?; Ok(())
303        }
304        fn num_set_ref(&mut self, value: &Self::Inner) -> Result<()> {
305            *self = Self::num_from(*value)?; Ok(())
306        }
307
308        // ident
309        fn num_is_zero(&self) -> Result<bool> { Ok(self.get() == 0) }
310        fn num_is_one(&self) -> Result<bool> { Ok(self.get() == 1) }
311        fn num_get_zero() -> Result<Self> { Self::num_from(0) }
312        fn num_get_one() -> Result<Self> { Self::num_from(1) }
313        fn num_set_zero(&mut self) -> Result<()> { *self = Self::num_from(0)?; Ok(()) }
314        fn num_set_one(&mut self) -> Result<()> { *self = Self::num_from(1)?; Ok(()) }
315    };
316
317    // Inner helpers for unary and binary ops
318    // ============================================================================================
319
320    /* ops that returns `NotImplemented` */
321
322    // (this could be regarded as unnecessary since it's the same as the default implementantion,
323    // but it allows us to debug missing implementations while swithing the commented out blocks
324    // in the num module that provides non-automatic implementations for the trait methods)
325
326    (op1_none $Self:ty => $($op:ident),+) => {
327        // $( impl_num![@op1_none $Self => $op]; )+ // uncomment to DEBUG
328    };
329    (@op1_none $Self:ty => $op:ident) => { paste! {
330        fn [<num_ $op>](self) -> Result<$Self::Out> { NumError::ni() }
331        fn [<num_ref_ $op>](&self) -> Result<$Self::Out> { NumError::ni() }
332    }};
333    (op2_none $Self:ty => $($op:ident),+) => {
334        $( impl_num![@op2_none $Self => $op]; )+ };
335    (@op2_none $Self:ty => $op:ident) => {
336        fn [<num_ $op>](self, other: $Self) -> Result<$Self::Out> { NumError::ni() }
337        fn [<num_ref_ $op>](&self, other: &$Self) -> Result<$Self::Out> { NumError::ni() }
338        fn [<num_ref_ $op _assign>](&mut self, other: &$Self) -> Result<()> { NumError::ni() }
339    };
340
341    /* ops that call .checked() for i*, u*, and few for NonZero* */
342
343    (op1_checked $Self:ty => $($op:ident),+) => {
344        $( impl_num![@op1_checked $Self => $op]; )+ };
345    (@op1_checked $Self:ty => $op:ident) => { paste! {
346        fn [<num_ $op>](self) -> Result<$Self::Out> {
347            self.[<checked_$op>]().ok_or(Unspecified)
348        }
349        fn [<num_ref_ $op>](&self) -> Result<$Self::Out> {
350            self.[<checked_$op>]().ok_or(Unspecified)
351        }
352    }};
353    (op2_checked $Self:ty => $($op:ident),+) => {
354        $( impl_num![@op2_checked $Self => $op]; )+ };
355    (@op2_checked $Self:ty => $op:ident) => { paste! {
356        fn [<num_ $op>](self, other: $Self) -> Result<$Self::Out> {
357            self.[<checked_ $op>](other).ok_or(Unspecified)
358        }
359        fn [<num_ref_ $op>](&self, other: &$Self) -> Result<$Self::Out> {
360            self.[<checked_ $op>](*other).ok_or(Unspecified)
361        }
362        fn [<num_ref_ $op _assign>](&mut self, other: &$Self) -> Result<()> {
363            *self = self.[<checked_ $op>](*other).ok_or(Unspecified)?;
364            Ok(())
365        }
366    }};
367
368    /* ops that call .get().checked() for: NonZero*, NonValue*, [Non|In]Range* */
369
370    (op1_get_checked $Self:ty => $($op:ident),+) => {
371        $( impl_num![@op1_get_checked $Self => $op]; )+ };
372    (@op1_get_checked $Self:ty => $op:ident) => { paste! {
373        fn [<num_ $op>](self) -> Result<$Self::Out> {
374            $Self::new(self.get().[<checked_ $op>]().ok_or(Unspecified)?).ok_or(Unspecified)
375        }
376        fn [<num_ref_ $op>](&self) -> Result<$Self::Out> {
377            $Self::new(self.get().[<checked_ $op>]().ok_or(Unspecified)?).ok_or(Unspecified)
378        }
379    }};
380    (op2_get_checked $Self:ty => $($op:ident),+) => {
381        $( impl_num![@op2_get_checked $Self => $op]; )+ };
382    (@op2_get_checked $Self:ty => $op:ident) => { paste! {
383        fn [<num_ $op>](self, other: $Self) -> Result<$Self::Out> {
384            $Self::new(self.get().[<checked_ $op>](other.get()).ok_or(Unspecified)?)
385                .ok_or(Unspecified)
386        }
387        fn [<num_ref_ $op>](&self, other: &$Self) -> Result<$Self::Out> {
388            $Self::new(self.get().[<checked_ $op>](other.get()).ok_or(Unspecified)?)
389                .ok_or(Unspecified)
390        }
391        fn [<num_ref_ $op _assign>](&mut self, other: &$Self) -> Result<()> {
392            *self = $Self::new(self.get().[<checked_ $op>](other.get()).ok_or(Unspecified)?)
393                .ok_or(Unspecified)?;
394            Ok(())
395        }
396    }};
397
398    /* ops for floating-point f* types */
399
400    (op1_float $Self:ty => $($op:ident),+) => { $( impl_num![@op1_float $Self => $op]; )+ };
401    (@op1_float $Self:ty => $op:ident) => { paste! {
402        fn [<num_ $op>](self) -> Result<$Self::Out> { Ok([<$op:camel>]::[<$op>](self)) }
403        fn [<num_ref_ $op>](&self) -> Result<$Self::Out> { Ok([<$op:camel>]::[<$op>](self)) }
404    }};
405    (op2_float $Self:ty => $($op:ident),+) => { $( impl_num![@op2_float $Self => $op]; )+ };
406    (@op2_float $Self:ty => $op:ident) => { paste! {
407        fn [<num_ $op>](self, other: $Self) -> Result<$Self::Out> {
408            Ok([<$op:camel>]::[<$op>](self, other))
409        }
410        fn [<num_ref_ $op>](&self, other: &$Self) -> Result<$Self::Out> {
411            Ok([<$op:camel>]::[<$op>](self, *other))
412        }
413    }};
414
415    // Inner helpers for identities
416    // ============================================================================================
417    // ...
418}
419impl_num!();