numera/number/integer/pz/
sized.rs

1// numera::number::integer::pz::sized
2//
3//!
4//
5// TOC
6//
7// - macro
8//   - define_positive_integer_sized
9// - definitions
10//   - PositiveInteger[8|16|32|64|128]
11
12#[cfg(feature = "try_from")]
13use crate::number::integer::PositiveIntegers;
14use crate::{
15    error::{IntegerErrors, NumeraErrors, NumeraResult},
16    number::{
17        macros::impl_larger_smaller,
18        traits::{
19            Bound, ConstLowerBounded, ConstOne, ConstUpperBounded, Count, Countable, Ident,
20            LowerBounded, NonNegative, NonZero, Number, One, Positive, Sign, UpperBounded,
21        },
22    },
23};
24use core::{
25    fmt,
26    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8},
27};
28use devela::paste;
29
30/* macro */
31
32/// # What it does
33/// - defines an Integer of a concrete size.
34/// - implements Number: Bound + Count + Ident + Sign
35///
36/// # Args
37/// - `$name`: the base name of the integer. E.g. `PositiveInteger`.
38/// - `$abbr`: the base abbreviated name, E.g. `Pz`.
39/// - `$p`: the primitive prefix (i or u).
40///
41/// - `$doc_num`: the type of number.
42/// - `$doc_type`: adds to the type doc-comment.
43// - `$doc_new`: adds to the `new` constructor doc-comment.
44///
45/// - `$doc_sign`: an optional negative sign
46/// - `$doc_lower`: the lower bound of the number type.
47/// - `$doc_upper`: the upper bound of the number type.
48///
49/// - `$doc_det`: the determinant before the bit size. e.g. "An" (8-bit) or "A" 16-bit.
50/// - `$b`: the size in bits of the primitive used.
51macro_rules! define_positive_integer_sized {
52    // defines multiple integer types, with an inner primitive.
53    (multi $name:ident, $abbr:ident, $p:ident,
54     $doc_num:literal, $doc_type:literal, // $doc_new:literal,
55     $doc_sign:literal, $doc_lower:expr, $doc_upper:expr,
56        $(
57            (
58             $doc_det:literal, $b:expr,
59             larger: $larger:literal, $larger_b:literal,
60             smaller: $smaller:literal, $smaller_b:literal
61            )
62        ),+
63    ) => {
64        $(
65            define_positive_integer_sized![single $name, $abbr, $p,
66               $doc_num, $doc_type, // $doc_new,
67               $doc_sign, $doc_lower, $doc_upper,
68               ($doc_det, $b,
69                larger: $larger, $larger_b,
70                smaller: $smaller, $smaller_b
71               )];
72        )+
73    };
74    // defines a single integer type, with an inner primitive.
75    (single $name:ident, $abbr:ident, $p:ident,
76     $doc_num:literal, $doc_type:literal, // $doc_new:literal,
77     $doc_sign:literal, $doc_lower:expr, $doc_upper:expr,
78     (
79      $doc_det:literal, $b:expr,
80      larger: $larger:literal, $larger_b:literal,
81      smaller: $smaller:literal, $smaller_b:literal
82     )
83    ) => { paste! {
84        #[doc = $doc_det " "$b "-bit " $doc_num $doc_type ","]
85        #[doc = "also known as [`" [<$abbr$b>] "`][super::" [<$abbr$b>] "]."]
86        #[doc = "\n\nThe range of valid numeric values is $\\lbrack" $doc_sign
87        "1 \\dots$ [`" u$b
88        "::" $doc_upper "`]$\\rbrack$."]
89        #[doc = "\n\nIt is equivalent to the [`" [<NonZeroU$b>] "`] primitive."]
90        ///
91        /// Also known as a [*counting number*][0m], you can also use the alias
92        #[doc = "[`Counting" $b "`][super::Counting" $b "]."]
93        ///
94        /// [0m]: https://mathworld.wolfram.com/CountingNumber.html
95        #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
96        pub struct [<$name$b>](pub [<$p$b>]);
97
98        impl fmt::Display for [<$name$b>]  {
99            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100                write!(f, "{}", self.0)
101            }
102        }
103        impl fmt::Debug for [<$name$b>]  {
104            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105                write!(f, "{}({})", stringify!([<$abbr$b>]), self.0)
106            }
107        }
108
109        impl [<$name$b>]  {
110            #[doc = "Returns a new `" [<$name$b>] "`."]
111            ///
112            /// # Errors
113            /// If the given `value` is `0`.
114            //
115            // NOTE: accepting u* for converting to NonZeroU
116            #[inline]
117            pub const fn new(value: [<u$b>]) -> NumeraResult<Self> {
118                if let Some(n) = [<$p$b>]::new(value) {
119                    Ok(Self(n))
120                } else {
121                    Err(NumeraErrors::Integer(IntegerErrors::Zero))
122                }
123            }
124
125            #[doc = "Returns a new `" [<$name$b>] "`."]
126            ///
127            /// # Safety
128            /// The given `value` must not be 0.
129            ///
130            /// # Panics
131            /// Panics in debug if the `value` is 0.
132            #[inline]
133            #[cfg(not(feature = "safe"))]
134            #[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
135            pub const unsafe fn new_unchecked(value: [<u$b>]) -> Self {
136                debug_assert![value != 0];
137                Self([<$p$b>]::new_unchecked(value))
138            }
139        }
140
141        /* resizing */
142
143        // uses "try_from"
144        impl_larger_smaller![$name, $b, PositiveIntegers,
145            larger: $larger, $larger_b, smaller: $smaller, $smaller_b
146        ];
147
148        /* sign */
149
150        impl Sign for [<$name$b>] {
151            #[inline]
152            fn can_negative(&self) -> bool { false }
153            #[inline]
154            fn can_positive(&self) -> bool { true }
155            #[inline]
156            fn is_negative(&self) -> bool { false }
157            #[inline]
158            fn is_positive(&self) -> bool { true }
159        }
160        impl NonNegative for [<$name$b>] {}
161        impl Positive for [<$name$b>] {}
162
163        /* bound */
164
165        impl Bound for [<$name$b>] {
166            #[inline]
167            fn is_lower_bounded(&self) -> bool { true }
168            #[inline]
169            fn is_upper_bounded(&self) -> bool { true }
170            #[inline]
171            fn lower_bound(&self) -> Option<Self> { Some([<$name$b>]::MIN) }
172            #[inline]
173            fn upper_bound(&self) -> Option<Self> { Some([<$name$b>]::MAX) }
174        }
175        impl LowerBounded for [<$name$b>] {
176            #[inline]
177            fn new_min() -> Self { [<$name$b>]::MIN }
178        }
179        impl UpperBounded for [<$name$b>] {
180            #[inline]
181            fn new_max() -> Self { [<$name$b>]::MAX }
182        }
183        impl ConstLowerBounded for [<$name$b>] {
184            const MIN: Self = Self([<$p$b>]::MIN);
185        }
186        impl ConstUpperBounded for [<$name$b>] {
187            const MAX: Self = Self([<$p$b>]::MAX);
188        }
189
190        /* count */
191
192        impl Count for [<$name$b>] {
193            #[inline]
194            fn is_countable(&self) -> bool { true }
195        }
196
197        impl Countable for [<$name$b>] {
198            /// Returns the next countable value, skipping 0.
199            ///
200            /// # Errors
201            /// Errors if the operation results in overflow.
202            #[inline]
203            fn next(&self) -> NumeraResult<Self> {
204                let next = self.0.get().checked_add(1).ok_or(IntegerErrors::Overflow)?;
205
206                #[cfg(feature = "safe")]
207                return Ok(Self([<$p$b>]::new(next).unwrap()));
208
209                #[cfg(not(feature = "safe"))]
210                // SAFETY: we've checked the value
211                return Ok(Self(unsafe { [<$p$b>]::new_unchecked(next) }));
212            }
213            /// Returns the previous countable value, skipping 0.
214            ///
215            /// # Errors
216            /// Errors if the operation results in underflow.
217            #[inline]
218            fn previous(&self) -> NumeraResult<Self> {
219                let prev = self.0.get().checked_sub(1).ok_or(IntegerErrors::Underflow)?;
220
221                #[cfg(feature = "safe")]
222                return Ok(Self([<$p$b>]::new(prev).unwrap()));
223
224                #[cfg(not(feature = "safe"))]
225                // SAFETY: we've checked the value
226                return Ok(Self(unsafe { [<$p$b>]::new_unchecked(prev) }));
227            }
228        }
229
230        /* ident */
231
232        impl Ident for [<$name$b>] {
233            #[inline]
234            fn can_zero(&self) -> bool { false }
235            #[inline]
236            fn can_one(&self) -> bool { true }
237            #[inline]
238            fn can_neg_one(&self) -> bool { false }
239
240            #[inline]
241            fn is_zero(&self) -> bool { false }
242            #[inline]
243            fn is_one(&self) -> bool { self.0.get() == 1 }
244            #[inline]
245            fn is_neg_one(&self) -> bool { false }
246        }
247        impl NonZero for [<$name$b>] {}
248        impl ConstOne for [<$name$b>] {
249            #[cfg(feature = "safe")]
250            const ONE: Self = Self(
251                if let Some(n) = [<$p$b>]::new(1)
252                    { n } else { unreachable!() }
253            );
254
255            #[cfg(not(feature = "safe"))]
256            // SAFETY: constant value
257            const ONE: Self = Self(unsafe { [<$p$b>]::new_unchecked(1) });
258        }
259        impl One for [<$name$b>] {
260            #[inline]
261            fn new_one() -> Self {
262                #[cfg(feature = "safe")]
263                return Self([<$p$b>]::new(1).unwrap());
264
265                #[cfg(not(feature = "safe"))]
266                // SAFETY: constant value
267                return Self(unsafe { [<$p$b>]::new_unchecked(1) });
268            }
269        }
270
271        /* number */
272
273        impl Number for [<$name$b>] {
274            type InnerRepr = [<NonZeroU$b>];
275            type InnermostRepr = [<u$b>];
276
277            #[doc = "Returns a new `" [<$name$b>] "` from the inner representation."]
278            ///
279            /// # Errors
280            /// This function can't fail.
281            #[inline]
282            fn from_inner_repr(value: Self::InnerRepr) -> NumeraResult<Self> {
283                Ok(Self(value))
284            }
285
286            #[doc = "Returns a new `" [<$name$b>] "` from the inner representation."]
287            ///
288            /// # Safety
289            /// This function is safe.
290            #[inline]
291            #[cfg(not(feature = "safe"))]
292            #[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
293            unsafe fn from_inner_repr_unchecked(value: Self::InnerRepr) -> Self {
294                Self(value)
295            }
296
297            #[doc = "Returns a new `" [<$name$b>] "` from the innermost representation."]
298            ///
299            /// # Errors
300            /// If the given `value` is `0`.
301            #[inline]
302            fn from_innermost_repr(value: Self::InnermostRepr) -> NumeraResult<Self> {
303                Ok(Self([<$p$b>]::new(value).ok_or(IntegerErrors::Zero)?))
304            }
305
306            #[doc = "Returns a new `" [<$name$b>] "` from the innermost representation."]
307            ///
308            /// # Panics
309            /// In debug if the given `value` is `0`.
310            ///
311            /// # Safety
312            /// The given `value` must not be `0`.
313            #[inline]
314            #[cfg(not(feature = "safe"))]
315            #[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
316            unsafe fn from_innermost_repr_unchecked(value: Self::InnermostRepr) -> Self {
317                debug_assert![value != 0];
318                Self([<$p$b>]::new_unchecked(value))
319            }
320
321            #[inline]
322            fn into_inner_repr(self) -> Self::InnerRepr { self.0 }
323
324            #[inline]
325            fn into_innermost_repr(self) -> Self::InnermostRepr { self.0.get() }
326        }
327    }};
328}
329
330/* definitions */
331
332define_positive_integer_sized![multi PositiveInteger, Pz, NonZeroU,
333    "positive integer number", ", from the set $\\Z^+$ ($\\N _1$)",
334    // "",
335    "", MIN, MAX,
336    ("An", 8, larger: true, 16, smaller: false, 8),
337    ("A", 16, larger: true, 32, smaller: true, 8),
338    ("A", 32, larger: true, 64, smaller: true, 16),
339    ("A", 64, larger: true, 128, smaller: true, 32),
340    ("A", 128, larger: false, 128, smaller: true, 64)
341];