zero_one/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![forbid(unsafe_code)]
3#![warn(missing_docs)]
4
5//! `const@Zero` and `const@One` ZSTs for use with generic code.
6//!
7//! These can be used in generic code where `0` and `1` literals don't work.
8//!
9//! ```
10//! # #![allow(non_upper_case_globals)]
11//! use zero_one::{Zero, One};
12//!
13//! assert_eq!(u64::from(Zero), 0);
14//! assert_eq!(i8::from(Zero), 0);
15//! assert_eq!(u64::from(One), 1);
16//! assert_eq!(i8::from(One), 1);
17//!
18//! assert_eq!(Zero, 0);
19//! assert_ne!(Zero, 1);
20//! assert_ne!(One, 0);
21//! assert_eq!(One, 1);
22//!
23//! assert!(Zero < 10);
24//! assert!(-10 < Zero);
25//! assert!(One < 10);
26//! assert!(-10 < One);
27//!
28//! assert!(matches!(Zero::try_from(0_u16), Ok(Zero)));
29//! assert!(matches!(Zero::try_from(1_i16), Err(_)));
30//! assert!(matches!(One::try_from(0_u16), Err(_)));
31//! assert!(matches!(One::try_from(1_i16), Ok(One)));
32//!
33//! assert_eq!(Zero.to_string(), "0");
34//! assert_eq!(One.to_string(), "1");
35//! ```
36//!
37//! Even outside generic code, they can make it easier to use some `std` types:
38//! ```
39//! use zero_one::{Zero, One};
40//! use std::num::*;
41//!
42//! assert_eq!(NonZeroU64::from(One), NonZeroU64::new(1).unwrap());
43//! assert_eq!(NonZeroI8::from(One), NonZeroI8::new(1).unwrap());
44//! ```
45//!
46//! They'll even work in macros that want to `as` cast things:
47//! ```
48//! use zero_one::{Zero, One};
49//!
50//! assert_eq!(Zero as u32, 0);
51//! assert_eq!(Zero as i128, 0);
52//! assert_eq!(One as u32, 1);
53//! assert_eq!(One as i128, 1);
54//! ```
55//!
56//! You can do math with them, too:
57//! ```
58//! use zero_one::{Zero, One};
59//!
60//! assert_eq!(Zero + 5, 5);
61//! assert_eq!(Zero | 5, 5);
62//! assert_eq!(One * 5, 5);
63//! assert_eq!(One + 5, 6);
64//!
65//! assert_eq!(Zero % One, Zero);
66//! assert_eq!(One - Zero, One);
67//! assert_eq!(Zero * 5, Zero);
68//! assert_eq!(Zero & 5, Zero);
69//!
70//! assert_eq!(10 + One, 11);
71//! assert_eq!(10 + Zero, 10);
72//! ```
73
74use core::cmp::{self, Eq, Ord, PartialEq, PartialOrd};
75use core::fmt::{self, Display, Formatter};
76use core::ops;
77
78/// The additive identity; the smallest natural number.
79#[allow(non_upper_case_globals)] // This is aping `struct Zero;`, so *shouldn't* be upper case.
80pub const Zero: Zero = Zero::Zero;
81
82/// The type whose only possible value is [`const@Zero`].
83#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
84pub enum Zero {
85    /// Yes, this is an enum.  But please don't mention the variant.
86    /// You should always just use [`const@Zero`] instead.
87    Zero = 0,
88}
89
90impl<T> ops::Add<T> for Zero {
91    type Output = T;
92    fn add(self, other: T) -> T { other }
93}
94
95impl<T> ops::Mul<T> for Zero {
96    type Output = Zero;
97    fn mul(self, _: T) -> Zero { Zero }
98}
99
100impl<T> ops::BitOr<T> for Zero {
101    type Output = T;
102    fn bitor(self, other: T) -> T { other }
103}
104
105impl<T> ops::BitAnd<T> for Zero {
106    type Output = Zero;
107    fn bitand(self, _: T) -> Zero { Zero }
108}
109
110impl Display for Zero {
111    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
112        <u8 as Display>::fmt(&0, f)
113    }
114}
115
116/// The multiplicative identity; the distance between adjacent natural numbers.
117#[allow(non_upper_case_globals)] // This is aping `struct One;`, so *shouldn't* be upper case.
118pub const One: One = One::One;
119
120/// The type whose only possible value is [`const@One`].
121#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
122pub enum One {
123    /// Yes, this is an enum.  But please don't mention the variant.
124    /// You should always just use [`const@One`] instead.
125    One = 1,
126}
127
128impl<T: ops::Add<One>> ops::Add<T> for One {
129    type Output = T::Output;
130    fn add(self, other: T) -> Self::Output {
131        other + self
132    }
133}
134
135impl<T> ops::Mul<T> for One {
136    type Output = T;
137    fn mul(self, other: T) -> T { other }
138}
139
140impl Display for One {
141    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
142        <u8 as Display>::fmt(&1, f)
143    }
144}
145
146macro_rules! impl_math_identities {
147    ($($trait:ident/$method:ident: $lhs:ident $rhs:ident -> $out:ident,)+) => {$(
148        impl ops::$trait<$rhs> for $lhs {
149            type Output = $out;
150            fn $method(self, _: $rhs) -> $out { $out }
151        }
152    )+};
153}
154
155impl_math_identities!{
156    // 0 + x -> x is covered by the blanket impl
157    // 1 + x -> x + 1
158    Sub/sub: Zero Zero -> Zero,
159    Sub/sub: One Zero -> One,
160    Sub/sub: One One -> Zero,
161    // 0 * x -> 0 is covered by the blanket impl
162    // 1 * x -> x is covered by the blanket impl
163    Div/div: Zero One -> Zero,
164    Div/div: One One -> One,
165    Rem/rem: Zero One -> Zero,
166    Rem/rem: One One -> Zero,
167
168    // 0 & x -> 0 is covered by the blanket impl
169    BitAnd/bitand: One Zero -> Zero,
170    BitAnd/bitand: One One -> One,
171    // 0 | x -> c is covered by the blanket impl
172    BitOr/bitor: One Zero -> One,
173    BitOr/bitor: One One -> One,
174    BitXor/bitxor: Zero Zero -> Zero,
175    BitXor/bitxor: Zero One -> One,
176    BitXor/bitxor: One Zero -> One,
177    BitXor/bitxor: One One -> Zero,
178    Shl/shl: Zero Zero -> Zero,
179    Shl/shl: Zero One -> Zero,
180    Shl/shl: One Zero -> One,
181    Shr/shr: Zero Zero -> Zero,
182    Shr/shr: One Zero -> One,
183    Shr/shr: Zero One -> Zero,
184    Shr/shr: One One -> Zero,
185}
186
187macro_rules! impl_for_integer {
188    ($($t:ty,)+) => {$(
189        impl From<Zero> for $t {
190            fn from(_: Zero) -> $t { 0 }
191        }
192        impl From<One> for $t {
193            fn from(_: One) -> $t { 1 }
194        }
195
196        impl TryFrom<$t> for Zero {
197            type Error = core::num::TryFromIntError;
198            fn try_from(other: $t) -> Result<Zero, Self::Error> {
199                if other == 0 {
200                    Ok(Zero)
201                } else {
202                    u8::try_from(-1).map(|_| unreachable!())
203                }
204            }
205        }
206        impl TryFrom<$t> for One {
207            type Error = core::num::TryFromIntError;
208            fn try_from(other: $t) -> Result<One, Self::Error> {
209                if other == 1 {
210                    Ok(One)
211                } else {
212                    u8::try_from(-1).map(|_| unreachable!())
213                }
214            }
215        }
216
217        impl PartialEq<$t> for Zero {
218            fn eq(&self, other: &$t) -> bool {
219                *other == 0
220            }
221        }
222        impl PartialEq<$t> for One {
223            fn eq(&self, other: &$t) -> bool {
224                *other == 1
225            }
226        }
227
228        impl PartialEq<Zero> for $t {
229            fn eq(&self, other: &Zero) -> bool {
230                *other == *self
231            }
232        }
233        impl PartialEq<One> for $t {
234            fn eq(&self, other: &One) -> bool {
235                *other == *self
236            }
237        }
238
239        impl PartialOrd<$t> for Zero {
240            fn partial_cmp(&self, other: &$t) -> Option<cmp::Ordering> {
241                <$t as PartialOrd>::partial_cmp(&0, other)
242            }
243        }
244        impl PartialOrd<$t> for One {
245            fn partial_cmp(&self, other: &$t) -> Option<cmp::Ordering> {
246                <$t as PartialOrd>::partial_cmp(&1, other)
247            }
248        }
249
250        impl PartialOrd<Zero> for $t {
251            fn partial_cmp(&self, _other: &Zero) -> Option<cmp::Ordering> {
252                <$t as PartialOrd>::partial_cmp(self, &0)
253            }
254        }
255        impl PartialOrd<One> for $t {
256            fn partial_cmp(&self, _other: &One) -> Option<cmp::Ordering> {
257                <$t as PartialOrd>::partial_cmp(self, &1)
258            }
259        }
260
261        impl ops::Add<Zero> for $t {
262            type Output = $t;
263            fn add(self, _: Zero) -> $t {
264                self + 0
265            }
266        }
267        impl ops::Add<One> for $t {
268            type Output = $t;
269            fn add(self, _: One) -> $t {
270                self + 1
271            }
272        }
273    )+};
274}
275
276impl_for_integer!{
277    i8, i16, i32, i64, i128, isize,
278    u8, u16, u32, u64, u128, usize,
279}
280
281macro_rules! impl_for_nonzero_integer {
282    ($($t:ty,)+) => {$(
283        #[allow(unused_imports)]
284        use core::num::*;
285
286        impl From<One> for $t {
287            fn from(_: One) -> $t { <$t>::new(1).unwrap() }
288        }
289
290        impl TryFrom<$t> for One {
291            type Error = TryFromIntError;
292            fn try_from(other: $t) -> Result<One, Self::Error> {
293                if other.get() == 1 {
294                    Ok(One)
295                } else {
296                    u8::try_from(-1).map(|_| unreachable!())
297                }
298            }
299        }
300    )+};
301}
302
303impl_for_nonzero_integer!{
304    NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
305    NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
306}
307
308impl ops::Neg for Zero {
309    type Output = Zero;
310    fn neg(self) -> Zero { Zero }
311}
312
313#[cfg(test)]
314mod tests {
315    use super::*;
316
317    #[test]
318    fn some_basics() {
319        assert_eq!(std::mem::size_of::<Zero>(), 0);
320        assert_eq!(std::mem::size_of::<One>(), 0);
321
322        assert_eq!(Zero as i8, 0);
323        assert_eq!(Zero as u128, 0);
324        assert_eq!(One as u8, 1);
325        assert_eq!(One as i128, 1);
326
327        assert_eq!(Zero + Zero, Zero);
328        assert_eq!(One * One, One);
329    }
330}