Skip to main content

const_num_traits/
identities.rs

1use core::num::Wrapping;
2use core::ops::{Add, Mul};
3
4use core::num::Saturating;
5
6c0nst::c0nst! {
7/// Defines an additive identity element for `Self`.
8///
9/// This is a pure identity-*value* trait: it provides the `0` and a zero-test,
10/// but does **not** require [`Add`](core::ops::Add). The bundling of `Add` is
11/// upstream convention, not a law — `0` is equally the identity under
12/// subtraction (`a - 0 = a`) — so consumers state the operators they actually
13/// use explicitly (`T: Zero + Add`, `T: Zero + Sub`, …). Numeric code that
14/// needs the full operator set takes [`Num`](crate::Num).
15///
16/// # Laws
17///
18/// ```text
19/// a + 0 = a       ∀ a ∈ Self
20/// 0 + a = a       ∀ a ∈ Self
21/// ```
22pub c0nst trait Zero: Sized {
23    /// Returns the additive identity element of `Self`, `0`.
24    /// # Purity
25    ///
26    /// This function should return the same result at all times regardless of
27    /// external mutable state, for example values stored in TLS or in
28    /// `static mut`s.
29    // This cannot be an associated constant, because of bignums.
30    fn zero() -> Self;
31
32    /// Sets `self` to the additive identity element of `Self`, `0`.
33    fn set_zero(&mut self);
34
35    /// Returns `true` if `self` is equal to the additive identity.
36    fn is_zero(&self) -> bool;
37}
38}
39
40/// Defines an associated constant representing the additive identity element
41/// for `Self`.
42///
43/// This is a pure constant-carrier: it requires only that `Self` *has* a
44/// compile-time `0`, **not** that it implements [`Zero`] (and hence not
45/// [`Add`](core::ops::Add)). Keeping it decoupled lets capability-restricted
46/// types — e.g. a constant-time integer with bit ops but no arithmetic — supply
47/// the `0` constant that [`PrimBits`](crate::PrimBits) needs without being
48/// forced to implement addition. Numeric types still implement both.
49pub trait ConstZero: Sized {
50    /// The additive identity element of `Self`, `0`.
51    const ZERO: Self;
52}
53
54macro_rules! zero_impl {
55    ($t:ty, $v:expr) => {
56        c0nst::c0nst! {
57        c0nst impl Zero for $t {
58            #[inline]
59            fn zero() -> $t {
60                $v
61            }
62            #[inline]
63            fn set_zero(&mut self) {
64                *self = $v;
65            }
66            #[inline]
67            fn is_zero(&self) -> bool {
68                *self == $v
69            }
70        }
71        }
72
73        impl ConstZero for $t {
74            const ZERO: Self = $v;
75        }
76    };
77}
78
79zero_impl!(usize, 0);
80zero_impl!(u8, 0);
81zero_impl!(u16, 0);
82zero_impl!(u32, 0);
83zero_impl!(u64, 0);
84zero_impl!(u128, 0);
85
86zero_impl!(isize, 0);
87zero_impl!(i8, 0);
88zero_impl!(i16, 0);
89zero_impl!(i32, 0);
90zero_impl!(i64, 0);
91zero_impl!(i128, 0);
92
93zero_impl!(f32, 0.0);
94zero_impl!(f64, 0.0);
95
96c0nst::c0nst! {
97c0nst impl<T: [c0nst] Zero> Zero for Wrapping<T>
98where
99    Wrapping<T>: [c0nst] Add<Output = Wrapping<T>>,
100{
101    fn is_zero(&self) -> bool {
102        self.0.is_zero()
103    }
104
105    fn set_zero(&mut self) {
106        self.0.set_zero();
107    }
108
109    fn zero() -> Self {
110        Wrapping(T::zero())
111    }
112}
113}
114
115impl<T: ConstZero> ConstZero for Wrapping<T>
116where
117    Wrapping<T>: Add<Output = Wrapping<T>>,
118{
119    const ZERO: Self = Wrapping(T::ZERO);
120}
121
122c0nst::c0nst! {
123c0nst impl<T: [c0nst] Zero> Zero for Saturating<T>
124where
125    Saturating<T>: [c0nst] Add<Output = Saturating<T>>,
126{
127    fn is_zero(&self) -> bool {
128        self.0.is_zero()
129    }
130
131    fn set_zero(&mut self) {
132        self.0.set_zero();
133    }
134
135    fn zero() -> Self {
136        Saturating(T::zero())
137    }
138}
139}
140
141impl<T: ConstZero> ConstZero for Saturating<T>
142where
143    Saturating<T>: Add<Output = Saturating<T>>,
144{
145    const ZERO: Self = Saturating(T::ZERO);
146}
147
148c0nst::c0nst! {
149/// Defines a multiplicative identity element for `Self`.
150///
151/// A pure identity-*value* trait, decoupled from [`Mul`](core::ops::Mul) for the
152/// same reason as [`Zero`]: `1` is equally the identity under division
153/// (`a / 1 = a`), so privileging `Mul` is arbitrary. Consumers state what they
154/// need (`T: One + Mul`, `T: One + Div`, …); full numeric code takes
155/// [`Num`](crate::Num).
156///
157/// # Laws
158///
159/// ```text
160/// a * 1 = a       ∀ a ∈ Self
161/// 1 * a = a       ∀ a ∈ Self
162/// ```
163pub c0nst trait One: Sized {
164    /// Returns the multiplicative identity element of `Self`, `1`.
165    ///
166    /// # Purity
167    ///
168    /// This function should return the same result at all times regardless of
169    /// external mutable state, for example values stored in TLS or in
170    /// `static mut`s.
171    // This cannot be an associated constant, because of bignums.
172    fn one() -> Self;
173
174    /// Sets `self` to the multiplicative identity element of `Self`, `1`.
175    fn set_one(&mut self);
176
177    /// Returns `true` if `self` is equal to the multiplicative identity.
178    fn is_one(&self) -> bool;
179}
180}
181
182/// Defines an associated constant representing the multiplicative identity
183/// element for `Self`.
184///
185/// A pure constant-carrier, decoupled from [`One`] (and hence
186/// [`Mul`](core::ops::Mul)) for the same reason as [`ConstZero`]: a type can
187/// supply the compile-time `1` that [`PrimBits`](crate::PrimBits) needs without
188/// implementing multiplication. Numeric types still implement both.
189pub trait ConstOne: Sized {
190    /// The multiplicative identity element of `Self`, `1`.
191    const ONE: Self;
192}
193
194macro_rules! one_impl {
195    ($t:ty, $v:expr) => {
196        c0nst::c0nst! {
197        c0nst impl One for $t {
198            #[inline]
199            fn one() -> $t {
200                $v
201            }
202            #[inline]
203            fn set_one(&mut self) {
204                *self = $v;
205            }
206            #[inline]
207            fn is_one(&self) -> bool {
208                *self == $v
209            }
210        }
211        }
212
213        impl ConstOne for $t {
214            const ONE: Self = $v;
215        }
216    };
217}
218
219one_impl!(usize, 1);
220one_impl!(u8, 1);
221one_impl!(u16, 1);
222one_impl!(u32, 1);
223one_impl!(u64, 1);
224one_impl!(u128, 1);
225
226one_impl!(isize, 1);
227one_impl!(i8, 1);
228one_impl!(i16, 1);
229one_impl!(i32, 1);
230one_impl!(i64, 1);
231one_impl!(i128, 1);
232
233one_impl!(f32, 1.0);
234one_impl!(f64, 1.0);
235
236c0nst::c0nst! {
237c0nst impl<T: [c0nst] One> One for Wrapping<T>
238where
239    Wrapping<T>: [c0nst] Mul<Output = Wrapping<T>>,
240{
241    fn set_one(&mut self) {
242        self.0.set_one();
243    }
244
245    fn one() -> Self {
246        Wrapping(T::one())
247    }
248
249    fn is_one(&self) -> bool {
250        self.0.is_one()
251    }
252}
253}
254
255impl<T: ConstOne> ConstOne for Wrapping<T>
256where
257    Wrapping<T>: Mul<Output = Wrapping<T>>,
258{
259    const ONE: Self = Wrapping(T::ONE);
260}
261
262c0nst::c0nst! {
263c0nst impl<T: [c0nst] One> One for Saturating<T>
264where
265    Saturating<T>: [c0nst] Mul<Output = Saturating<T>>,
266{
267    fn set_one(&mut self) {
268        self.0.set_one();
269    }
270
271    fn one() -> Self {
272        Saturating(T::one())
273    }
274
275    fn is_one(&self) -> bool {
276        self.0.is_one()
277    }
278}
279}
280
281impl<T: ConstOne> ConstOne for Saturating<T>
282where
283    Saturating<T>: Mul<Output = Saturating<T>>,
284{
285    const ONE: Self = Saturating(T::ONE);
286}
287
288// Some helper functions provided for backwards compatibility.
289
290c0nst::c0nst! {
291/// Returns the additive identity, `0`.
292#[inline(always)]
293pub c0nst fn zero<T: [c0nst] Zero>() -> T {
294    Zero::zero()
295}
296}
297
298c0nst::c0nst! {
299/// Returns the multiplicative identity, `1`.
300#[inline(always)]
301pub c0nst fn one<T: [c0nst] One>() -> T {
302    One::one()
303}
304}
305
306#[test]
307fn wrapping_identities() {
308    macro_rules! test_wrapping_identities {
309        ($($t:ty)+) => {
310            $(
311                assert_eq!(zero::<$t>(), zero::<Wrapping<$t>>().0);
312                assert_eq!(one::<$t>(), one::<Wrapping<$t>>().0);
313                assert_eq!((0 as $t).is_zero(), Wrapping(0 as $t).is_zero());
314                assert_eq!((1 as $t).is_zero(), Wrapping(1 as $t).is_zero());
315            )+
316        };
317    }
318
319    test_wrapping_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
320}
321
322#[test]
323fn wrapping_is_zero() {
324    fn require_zero<T: Zero>(_: &T) {}
325    require_zero(&Wrapping(42));
326}
327#[test]
328fn wrapping_is_one() {
329    fn require_one<T: One>(_: &T) {}
330    require_one(&Wrapping(42));
331}
332
333#[test]
334fn saturating_identities() {
335    macro_rules! test_saturating_identities {
336        ($($t:ty)+) => {
337            $(
338                assert_eq!(zero::<$t>(), zero::<Saturating<$t>>().0);
339                assert_eq!(one::<$t>(), one::<Saturating<$t>>().0);
340                assert_eq!((0 as $t).is_zero(), Saturating(0 as $t).is_zero());
341                assert_eq!((1 as $t).is_zero(), Saturating(1 as $t).is_zero());
342            )+
343        };
344    }
345
346    test_saturating_identities!(isize i8 i16 i32 i64 usize u8 u16 u32 u64);
347}
348
349#[test]
350fn saturating_is_zero() {
351    fn require_zero<T: Zero>(_: &T) {}
352    require_zero(&Saturating(42));
353}
354#[test]
355fn saturating_is_one() {
356    fn require_one<T: One>(_: &T) {}
357    require_one(&Saturating(42));
358}