amplify_num/
smallint.rs

1// Rust language amplification library providing multiple generic trait
2// implementations, type wrappers, derive macros and other language enhancements
3//
4// Written in 2021-2024 by
5//     Dr. Maxim Orlovsky <orlovsky@ubideco.org>
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to
9// the public domain worldwide. This software is distributed without
10// any warranty.
11//
12// You should have received a copy of the MIT License
13// along with this software.
14// If not, see <https://opensource.org/licenses/MIT>.
15
16use core::convert::TryFrom;
17use core::ops::{
18    Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
19    Mul, MulAssign, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
20};
21
22use crate::error::{DivError, OverflowError};
23
24macro_rules! construct_smallint {
25    ($ty:ident, $inner:ident, $to:ident, $into:ident, $bits:literal, $max:expr, $doc:meta) => {
26        #[$doc]
27        #[derive(PartialEq, Eq, Debug, Copy, Clone, Default, PartialOrd, Ord, Hash)]
28        #[cfg_attr(
29            feature = "serde",
30            derive(Serialize, Deserialize),
31            serde(crate = "serde_crate", transparent)
32        )]
33        #[allow(non_camel_case_types)]
34        pub struct $ty($inner);
35
36        impl $ty {
37            /// Bit dimension
38            pub const BITS: u32 = $bits;
39
40            /// Minimum value
41            pub const MIN: Self = Self(0);
42
43            /// Maximal value
44            pub const MAX: Self = Self($max);
45
46            /// One value
47            pub const ONE: Self = Self(1);
48
49            /// One value
50            pub const ZERO: Self = Self(0);
51
52            /// Creates a new value from a provided `value.
53            ///
54            /// Panics if the value exceeds `Self::MAX`
55            pub const fn with(value: $inner) -> Self {
56                assert!(value <= $max, "provided value exceeds Self::MAX");
57                Self(value)
58            }
59
60            /// Returns inner `u8` representation, which is always less or equal to `Self::MAX`
61            pub const fn $to(&self) -> $inner {
62                self.0 as $inner
63            }
64
65            /// Returns inner `u8` representation, which is always less or equal to `Self::MAX`
66            pub const fn $into(self) -> $inner {
67                self.0 as $inner
68            }
69        }
70
71        impl ::core::convert::TryFrom<$inner> for $ty {
72            type Error = OverflowError<$inner>;
73            #[inline]
74            fn try_from(value: $inner) -> Result<Self, Self::Error> {
75                if value > $max {
76                    Err(OverflowError { max: $max, value })
77                } else {
78                    Ok(Self(value))
79                }
80            }
81        }
82
83        impl From<$ty> for $inner {
84            #[inline]
85            fn from(val: $ty) -> Self {
86                val.0
87            }
88        }
89
90        impl AsRef<$inner> for $ty {
91            #[inline]
92            fn as_ref(&self) -> &$inner {
93                &self.0
94            }
95        }
96
97        impl ::core::str::FromStr for $ty {
98            type Err = ::core::num::ParseIntError;
99            #[inline]
100            fn from_str(s: &str) -> Result<Self, Self::Err> {
101                Self::try_from($inner::from_str(s)?).map_err(|_| u8::from_str("257").unwrap_err())
102            }
103        }
104
105        impl ::core::fmt::Display for $ty {
106            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
107                self.0.fmt(f)
108            }
109        }
110
111        impl core::fmt::UpperHex for $ty {
112            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
113                core::fmt::UpperHex::fmt(&self.as_ref(), f)
114            }
115        }
116
117        impl core::fmt::LowerHex for $ty {
118            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
119                core::fmt::LowerHex::fmt(&self.as_ref(), f)
120            }
121        }
122
123        impl core::fmt::Octal for $ty {
124            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
125                core::fmt::Octal::fmt(&self.as_ref(), f)
126            }
127        }
128
129        impl core::fmt::Binary for $ty {
130            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
131                core::fmt::Binary::fmt(&self.as_ref(), f)
132            }
133        }
134
135        impl_op!($ty, $inner, Add, add, AddAssign, add_assign, +);
136        impl_op!($ty, $inner, Sub, sub, SubAssign, sub_assign, -);
137        impl_op!($ty, $inner, Mul, mul, MulAssign, mul_assign, *);
138        impl_op!($ty, $inner, Div, div, DivAssign, div_assign, /);
139        impl_op!($ty, $inner, Rem, rem, RemAssign, rem_assign, %);
140        impl_op!($ty, $inner, BitAnd, bitand, BitAndAssign, bitand_assign, &);
141        impl_op!($ty, $inner, BitOr, bitor, BitOrAssign, bitor_assign, |);
142        impl_op!($ty, $inner, BitXor, bitxor, BitXorAssign, bitxor_assign, ^);
143        impl_op!($ty, $inner, Shl, shl, ShlAssign, shl_assign, <<);
144        impl_op!($ty, $inner, Shr, shr, ShrAssign, shr_assign, >>);
145
146        impl $ty {
147            /// Checked integer addition. Computes `self + rhs`, returning `None` if
148            /// overflow occurred.
149            pub fn checked_add<T>(self, rhs: T) -> Option<Self> where T: Into<$inner> {
150                self.0.checked_add(rhs.into()).and_then(|val| Self::try_from(val).ok())
151            }
152            /// Saturating integer addition. Computes `self + rhs`, saturating at the
153            /// numeric bounds instead of overflowing.
154            pub fn saturating_add<T>(self, rhs: T) -> Self where T: Into<$inner> {
155                let res = self.0.saturating_add(rhs.into());
156                if res > Self::MAX.$to() {
157                    Self::MAX
158                } else {
159                    Self(res)
160                }
161            }
162            /// Calculates `self + rhs`
163            ///
164            /// Returns a tuple of the addition along with a boolean indicating whether
165            /// an arithmetic overflow would occur. If an overflow would have occurred
166            /// then the wrapped value is returned.
167            pub fn overflowing_add<T>(self, rhs: T) -> (Self, bool) where T: Into<$inner> {
168                let mut ret = self.0.overflowing_add(rhs.into());
169                if ret.0 > Self::MAX.0 {
170                    ret.0 %= Self::MAX.0;
171                    ret.1 = true;
172                }
173                (Self(ret.0), ret.1)
174            }
175            /// Wrapping (modular) addition. Computes `self + rhs`, wrapping around at
176            /// the boundary of the type.
177            pub fn wrapping_add<T>(self, rhs: T) -> Self where T: Into<$inner> {
178                #[allow(clippy::modulo_one)]
179                Self(self.0.wrapping_add(rhs.into()) % Self::MAX.0)
180            }
181
182            /// Checked integer subtraction. Computes `self - rhs`, returning `None` if
183            /// overflow occurred.
184            pub fn checked_sub<T>(self, rhs: T) -> Option<Self> where T: Into<$inner> {
185                self.0.checked_sub(rhs.into()).and_then(|val| Self::try_from(val).ok())
186            }
187            /// Saturating integer subtraction. Computes `self - rhs`, saturating at the
188            /// numeric bounds instead of overflowing.
189            pub fn saturating_sub<T>(self, rhs: T) -> Self where T: Into<$inner> {
190                let res = self.0.saturating_sub(rhs.into());
191                if res > Self::MAX.$to() {
192                    Self::MAX
193                } else {
194                    Self(res)
195                }
196            }
197            /// Calculates `self - rhs`
198            ///
199            /// Returns a tuple of the subtraction along with a boolean indicating whether
200            /// an arithmetic overflow would occur. If an overflow would have occurred
201            /// then the wrapped value is returned.
202            pub fn overflowing_sub<T>(self, rhs: T) -> (Self, bool) where T: Into<$inner> {
203                let mut ret = self.0.overflowing_sub(rhs.into());
204                if ret.0 > Self::MAX.0 {
205                    ret.0 %= Self::MAX.0;
206                    ret.1 = true;
207                }
208                (Self(ret.0), ret.1)
209            }
210            /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at
211            /// the boundary of the type.
212            pub fn wrapping_sub<T>(self, rhs: T) -> Self where T: Into<$inner> {
213                #[allow(clippy::modulo_one)]
214                Self(self.0.wrapping_sub(rhs.into()) % Self::MAX.0)
215            }
216
217            /// Checked integer multiplication. Computes `self * rhs`, returning `None` if
218            /// overflow occurred.
219            pub fn checked_mul<T>(self, rhs: T) -> Option<Self> where T: Into<$inner> {
220                self.0.checked_mul(rhs.into()).and_then(|val| Self::try_from(val).ok())
221            }
222            /// Saturating integer multiplication. Computes `self * rhs`, saturating at the
223            /// numeric bounds instead of overflowing.
224            pub fn saturating_mul<T>(self, rhs: T) -> Self where T: Into<$inner> {
225                let res = self.0.saturating_mul(rhs.into());
226                if res > Self::MAX.0 {
227                    Self::MAX
228                } else {
229                    Self(res)
230                }
231            }
232            /// Calculates `self * rhs`
233            ///
234            /// Returns a tuple of the multiplication along with a boolean indicating whether
235            /// an arithmetic overflow would occur. If an overflow would have occurred
236            /// then the wrapped value is returned.
237            pub fn overflowing_mul<T>(self, rhs: T) -> (Self, bool) where T: Into<$inner> {
238                let mut ret = self.0.overflowing_mul(rhs.into());
239                if ret.0 > Self::MAX.0 {
240                    ret.0 %= Self::MAX.0;
241                    ret.1 = true;
242                }
243                (Self(ret.0), ret.1)
244            }
245            /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
246            /// the boundary of the type.
247            pub fn wrapping_mul<T>(self, rhs: T) -> Self where T: Into<$inner> {
248                #[allow(clippy::modulo_one)]
249                Self(self.0.wrapping_mul(rhs.into()) % Self::MAX.0)
250            }
251
252            #[inline]
253            pub fn div_rem(self, other: Self) -> Result<(Self, Self), DivError> {
254                //quotient and remainder will always be smaller than self so they're going to be in bounds
255                if other == Self(0) {
256                    return Err(DivError::ZeroDiv)
257                }
258                let quotient = self / other;
259                Ok((quotient, self - (quotient * other)))
260            }
261        }
262    };
263}
264macro_rules! impl_op {
265    ($ty:ty, $inner:ty, $op:ident, $fn:ident, $op_assign:ident, $fn_assign:ident, $sign:tt) => {
266        impl<T> $op<T> for $ty where T: Into<$inner> {
267            type Output = $ty;
268            #[inline]
269            fn $fn(self, rhs: T) -> Self::Output {
270                Self::try_from((self.0).$fn(rhs.into())).expect(stringify!(
271                    "attempt to ",
272                    $fn,
273                    " with overflow"
274                ))
275            }
276        }
277        impl<T> $op<T> for &$ty where T: Into<$inner> {
278            type Output = $ty;
279            #[inline]
280            fn $fn(self, rhs: T) -> Self::Output {
281                *self $sign rhs
282            }
283        }
284
285        impl<T> $op_assign<T> for $ty where T: Into<$inner> {
286            #[inline]
287            fn $fn_assign(&mut self, rhs: T) {
288                self.0 = (*self $sign rhs).0
289            }
290        }
291    };
292}
293
294construct_smallint!(
295    u1,
296    u8,
297    to_u8,
298    into_u8,
299    1,
300    1,
301    doc = "1-bit unsigned integer in the range `0..1`. It can be used instead of `bool` when \
302           1-bit numeric (and not boolean) arithmetic is required"
303);
304construct_smallint!(
305    u2,
306    u8,
307    to_u8,
308    into_u8,
309    2,
310    3,
311    doc = "2-bit unsigned integer in the range `0..4`"
312);
313construct_smallint!(
314    u3,
315    u8,
316    to_u8,
317    into_u8,
318    3,
319    7,
320    doc = "3-bit unsigned integer in the range `0..8`"
321);
322construct_smallint!(
323    u4,
324    u8,
325    to_u8,
326    into_u8,
327    4,
328    15,
329    doc = "4-bit unsigned integer in the range `0..16`"
330);
331construct_smallint!(
332    u5,
333    u8,
334    to_u8,
335    into_u8,
336    5,
337    31,
338    doc = "5-bit unsigned integer in the range `0..32`"
339);
340construct_smallint!(
341    u6,
342    u8,
343    to_u8,
344    into_u8,
345    6,
346    63,
347    doc = "6-bit unsigned integer in the range `0..64`"
348);
349construct_smallint!(
350    u7,
351    u8,
352    to_u8,
353    into_u8,
354    7,
355    127,
356    doc = "7-bit unsigned integer in the range `0..128`"
357);
358construct_smallint!(
359    u24,
360    u32,
361    to_u32,
362    into_u32,
363    24,
364    0xFF_FF_FF,
365    doc = "24-bit unsigned integer in the range `0..16_777_216`"
366);
367construct_smallint!(
368    u40,
369    u64,
370    to_u64,
371    into_u64,
372    40,
373    0xFF_FFFF_FFFF,
374    doc = "40-bit unsigned integer in the range `0..2^40`"
375);
376construct_smallint!(
377    u48,
378    u64,
379    to_u64,
380    into_u64,
381    48,
382    0xFFFF_FFFF_FFFF,
383    doc = "48-bit unsigned integer in the range `0..2^48`"
384);
385construct_smallint!(
386    u56,
387    u64,
388    to_u64,
389    into_u64,
390    56,
391    0xFF_FFFF_FFFF_FFFF,
392    doc = "56-bit unsigned integer in the range `0..2^56`"
393);
394
395impl From<u1> for u2 {
396    fn from(value: u1) -> Self { Self(value.0) }
397}
398
399impl From<u1> for u3 {
400    fn from(value: u1) -> Self { Self(value.0) }
401}
402
403impl From<u2> for u3 {
404    fn from(value: u2) -> Self { Self(value.0) }
405}
406
407impl From<u1> for u4 {
408    fn from(value: u1) -> Self { Self(value.0) }
409}
410
411impl From<u2> for u4 {
412    fn from(value: u2) -> Self { Self(value.0) }
413}
414
415impl From<u3> for u4 {
416    fn from(value: u3) -> Self { Self(value.0) }
417}
418
419impl From<u1> for u5 {
420    fn from(value: u1) -> Self { Self(value.0) }
421}
422
423impl From<u2> for u5 {
424    fn from(value: u2) -> Self { Self(value.0) }
425}
426
427impl From<u3> for u5 {
428    fn from(value: u3) -> Self { Self(value.0) }
429}
430
431impl From<u4> for u5 {
432    fn from(value: u4) -> Self { Self(value.0) }
433}
434
435impl From<u1> for u6 {
436    fn from(value: u1) -> Self { Self(value.0) }
437}
438
439impl From<u2> for u6 {
440    fn from(value: u2) -> Self { Self(value.0) }
441}
442
443impl From<u3> for u6 {
444    fn from(value: u3) -> Self { Self(value.0) }
445}
446
447impl From<u4> for u6 {
448    fn from(value: u4) -> Self { Self(value.0) }
449}
450
451impl From<u5> for u6 {
452    fn from(value: u5) -> Self { Self(value.0) }
453}
454
455impl From<u1> for u7 {
456    fn from(value: u1) -> Self { Self(value.0) }
457}
458
459impl From<u2> for u7 {
460    fn from(value: u2) -> Self { Self(value.0) }
461}
462
463impl From<u3> for u7 {
464    fn from(value: u3) -> Self { Self(value.0) }
465}
466
467impl From<u4> for u7 {
468    fn from(value: u4) -> Self { Self(value.0) }
469}
470
471impl From<u5> for u7 {
472    fn from(value: u5) -> Self { Self(value.0) }
473}
474
475impl From<u6> for u7 {
476    fn from(value: u6) -> Self { Self(value.0) }
477}
478
479impl From<u24> for i32 {
480    fn from(val: u24) -> Self { val.0 as i32 }
481}
482
483impl From<u24> for i64 {
484    fn from(val: u24) -> Self { val.0 as i64 }
485}
486
487impl From<u24> for i128 {
488    fn from(val: u24) -> Self { val.0 as i128 }
489}
490
491impl From<u24> for isize {
492    fn from(val: u24) -> Self { val.0 as isize }
493}
494
495impl From<u24> for u64 {
496    fn from(val: u24) -> Self { val.0 as u64 }
497}
498
499impl From<u24> for u128 {
500    fn from(val: u24) -> Self { val.0 as u128 }
501}
502
503impl From<u24> for usize {
504    fn from(val: u24) -> Self { val.0 as usize }
505}
506
507impl From<u48> for i64 {
508    fn from(val: u48) -> Self { val.0 as i64 }
509}
510
511impl From<u40> for i128 {
512    fn from(val: u40) -> Self { val.0 as i128 }
513}
514
515impl From<u40> for isize {
516    fn from(val: u40) -> Self { val.0 as isize }
517}
518
519impl From<u40> for u128 {
520    fn from(val: u40) -> Self { val.0 as u128 }
521}
522
523impl From<u40> for usize {
524    fn from(val: u40) -> Self { val.0 as usize }
525}
526
527impl From<u48> for i128 {
528    fn from(val: u48) -> Self { val.0 as i128 }
529}
530
531impl From<u48> for isize {
532    fn from(val: u48) -> Self { val.0 as isize }
533}
534
535impl From<u48> for u128 {
536    fn from(val: u48) -> Self { val.0 as u128 }
537}
538
539impl From<u48> for usize {
540    fn from(val: u48) -> Self { val.0 as usize }
541}
542
543impl From<u56> for i64 {
544    fn from(val: u56) -> Self { val.0 as i64 }
545}
546
547impl From<u56> for i128 {
548    fn from(val: u56) -> Self { val.0 as i128 }
549}
550
551impl From<u56> for isize {
552    fn from(val: u56) -> Self { val.0 as isize }
553}
554
555impl From<u56> for u128 {
556    fn from(val: u56) -> Self { val.0 as u128 }
557}
558
559impl From<u56> for usize {
560    fn from(val: u56) -> Self { val.0 as usize }
561}
562
563impl u24 {
564    /// Create a native endian integer value from its representation as a byte
565    /// array in little endian.
566    pub fn from_le_bytes(bytes: [u8; 3]) -> Self {
567        let mut inner = [0u8; 4];
568        inner[..3].copy_from_slice(&bytes);
569        Self(u32::from_le_bytes(inner))
570    }
571
572    /// Return the memory representation of this integer as a byte array in
573    /// little-endian byte order.
574    pub fn to_le_bytes(self) -> [u8; 3] {
575        let mut inner = [0u8; 3];
576        inner.copy_from_slice(&self.0.to_le_bytes()[..3]);
577        inner
578    }
579
580    /// Create a native endian integer value from its representation as a byte
581    /// array in big endian.
582    pub fn from_be_bytes(bytes: [u8; 3]) -> Self {
583        let mut inner = [0u8; 4];
584        inner[1..].copy_from_slice(&bytes);
585        Self(u32::from_be_bytes(inner))
586    }
587
588    /// Return the memory representation of this integer as a byte array in
589    /// big-endian byte order.
590    pub fn to_be_bytes(self) -> [u8; 3] {
591        let mut inner = [0u8; 3];
592        inner.copy_from_slice(&self.0.to_be_bytes()[1..]);
593        inner
594    }
595
596    /// Converts into `i32` type.
597    pub const fn to_i32(&self) -> i32 { self.0 as i32 }
598
599    /// Converts into `i64` type.
600    pub const fn to_i64(&self) -> i64 { self.0 as i64 }
601
602    /// Converts into `i128` type.
603    pub const fn to_i128(&self) -> i128 { self.0 as i128 }
604
605    /// Converts into `isize` type.
606    pub const fn to_isize(&self) -> isize { self.0 as isize }
607
608    /// Converts into `u64` type.
609    pub const fn to_u64(&self) -> u64 { self.0 as u64 }
610
611    /// Converts into `i128` type.
612    pub const fn to_u128(&self) -> u128 { self.0 as u128 }
613
614    /// Converts into `usize` type.
615    pub const fn to_usize(&self) -> usize { self.0 as usize }
616
617    /// Converts into `i32` type.
618    pub const fn into_i32(self) -> i32 { self.0 as i32 }
619
620    /// Converts into `i64` type.
621    pub const fn into_i64(self) -> i64 { self.0 as i64 }
622
623    /// Converts into `i128` type.
624    pub const fn into_i128(self) -> i128 { self.0 as i128 }
625
626    /// Converts into `isize` type.
627    pub const fn into_isize(self) -> isize { self.0 as isize }
628
629    /// Converts into `u64` type.
630    pub const fn into_u64(self) -> u64 { self.0 as u64 }
631
632    /// Converts into `u128` type.
633    pub const fn into_u128(self) -> u128 { self.0 as u128 }
634
635    /// Converts into `usize` type.
636    pub const fn into_usize(self) -> usize { self.0 as usize }
637}
638
639macro_rules! impl_subu64 {
640    ($ty:ty, $len:literal) => {
641        impl $ty {
642            /// Create a native endian integer value from its representation as a byte
643            /// array in little endian.
644            pub fn from_le_bytes(bytes: [u8; $len]) -> Self {
645                let mut inner = [0u8; 8];
646                inner[..$len].copy_from_slice(&bytes);
647                Self(u64::from_le_bytes(inner))
648            }
649
650            /// Return the memory representation of this integer as a byte array in
651            /// little-endian byte order.
652            pub fn to_le_bytes(self) -> [u8; $len] {
653                let mut inner = [0u8; $len];
654                inner.copy_from_slice(&self.0.to_le_bytes()[..$len]);
655                inner
656            }
657
658            /// Create a native endian integer value from its representation as a byte
659            /// array in big endian.
660            pub fn from_be_bytes(bytes: [u8; $len]) -> Self {
661                let mut inner = [0u8; 8];
662                inner[(8 - $len)..].copy_from_slice(&bytes);
663                Self(u64::from_be_bytes(inner))
664            }
665
666            /// Return the memory representation of this integer as a byte array in
667            /// big-endian byte order.
668            pub fn to_be_bytes(self) -> [u8; $len] {
669                let mut inner = [0u8; $len];
670                inner.copy_from_slice(&self.0.to_be_bytes()[(8 - $len)..]);
671                inner
672            }
673
674            /// Converts into `i64` type.
675            pub const fn to_i64(&self) -> i64 { self.0 as i64 }
676
677            /// Converts into `i128` type.
678            pub const fn to_i128(&self) -> i128 { self.0 as i128 }
679
680            /// Converts into `isize` type.
681            pub const fn to_isize(&self) -> isize { self.0 as isize }
682
683            /// Converts into `i128` type.
684            pub const fn to_u128(&self) -> u128 { self.0 as u128 }
685
686            /// Converts into `usize` type.
687            pub const fn to_usize(&self) -> usize { self.0 as usize }
688
689            /// Converts into `i64` type.
690            pub const fn into_i64(self) -> i64 { self.0 as i64 }
691
692            /// Converts into `i128` type.
693            pub const fn into_i128(self) -> i128 { self.0 as i128 }
694
695            /// Converts into `isize` type.
696            pub const fn into_isize(self) -> isize { self.0 as isize }
697
698            /// Converts into `u128` type.
699            pub const fn into_u128(self) -> u128 { self.0 as u128 }
700
701            /// Converts into `usize` type.
702            pub const fn into_usize(self) -> usize { self.0 as usize }
703        }
704    };
705}
706impl_subu64!(u40, 5);
707impl_subu64!(u48, 6);
708impl_subu64!(u56, 7);
709
710#[cfg(test)]
711mod test {
712    use super::*;
713
714    #[test]
715    fn ubit_test() {
716        let mut u_1 = u1::try_from(u1::MAX.to_u8()).unwrap();
717        let mut u_2 = u2::try_from(u2::MAX.to_u8()).unwrap();
718        let mut u_3 = u3::try_from(u3::MAX.to_u8()).unwrap();
719        let mut u_4 = u4::try_from(u4::MAX.to_u8()).unwrap();
720        let mut u_5 = u5::try_from(u5::MAX.to_u8()).unwrap();
721        let mut u_6 = u6::try_from(u6::MAX.to_u8()).unwrap();
722        let mut u_7 = u7::try_from(u7::MAX.to_u8()).unwrap();
723        let mut u_24 = u24::try_from(u24::MAX.to_u32()).unwrap();
724
725        assert_eq!(u_1, u1::with(1));
726        assert_eq!(u_2, u2::with(3));
727        assert_eq!(u_3, u3::with(7));
728        assert_eq!(u_4, u4::with(15));
729        assert_eq!(u_5, u5::with(31));
730        assert_eq!(u_6, u6::with(63));
731        assert_eq!(u_7, u7::with(127));
732
733        assert_eq!(u_1.to_u8(), 1u8);
734        assert_eq!(u_2.to_u8(), 3u8);
735        assert_eq!(u_3.to_u8(), 7u8);
736        assert_eq!(u_4.to_u8(), 15u8);
737        assert_eq!(u_5.to_u8(), 31u8);
738        assert_eq!(u_6.to_u8(), 63u8);
739        assert_eq!(u_7.to_u8(), 127u8);
740        assert_eq!(u_24.to_u32(), (1 << 24) - 1);
741
742        u_1 -= 1;
743        u_2 -= 1;
744        u_3 -= 1;
745        u_4 -= 1;
746        u_5 -= 1;
747        u_6 -= 1;
748        u_7 -= 1;
749        u_24 -= 1u32;
750
751        assert_eq!(u_1.to_u8(), 0u8);
752        assert_eq!(u_2.to_u8(), 2u8);
753        assert_eq!(u_3.to_u8(), 6u8);
754        assert_eq!(u_4.to_u8(), 14u8);
755        assert_eq!(u_5.to_u8(), 30u8);
756        assert_eq!(u_6.to_u8(), 62u8);
757        assert_eq!(u_7.to_u8(), 126u8);
758        assert_eq!(u_24.to_u32(), (1 << 24) - 2);
759
760        u_1 /= 2;
761        u_1 *= 2;
762        u_1 += 1;
763
764        u_2 /= 2;
765        u_2 *= 2;
766        u_2 += 1;
767
768        u_3 /= 2;
769        u_3 *= 2;
770        u_3 += 1;
771
772        u_4 /= 2;
773        u_4 *= 2;
774        u_4 += 1;
775
776        u_5 /= 2;
777        u_5 *= 2;
778        u_5 += 1;
779
780        u_6 /= 2;
781        u_6 *= 2;
782        u_6 += 1;
783
784        u_7 /= 2;
785        u_7 *= 2;
786        u_7 += 1;
787
788        u_24 /= 2u32;
789        u_24 *= 2u32;
790        u_24 += 1u32;
791
792        assert_eq!(u_1.to_u8(), 1u8);
793        assert_eq!(u_2.to_u8(), 3u8);
794        assert_eq!(u_3.to_u8(), 7u8);
795        assert_eq!(u_4.to_u8(), 15u8);
796        assert_eq!(u_5.to_u8(), 31u8);
797        assert_eq!(u_6.to_u8(), 63u8);
798        assert_eq!(u_7.to_u8(), 127u8);
799        assert_eq!(u_24.to_u32(), (1 << 24) - 1);
800
801        assert_eq!(u_1.to_u8() % 2, 1);
802        assert_eq!(u_2.to_u8() % 2, 1);
803        assert_eq!(u_3.to_u8() % 2, 1);
804        assert_eq!(u_4.to_u8() % 2, 1);
805        assert_eq!(u_5.to_u8() % 2, 1);
806        assert_eq!(u_6.to_u8() % 2, 1);
807        assert_eq!(u_7.to_u8() % 2, 1);
808        assert_eq!(u_24.to_u32() % 2, 1);
809    }
810
811    #[test]
812    #[should_panic(expected = "OverflowError { max: 1, value: 2 }")]
813    fn u1_overflow_test() { u1::try_from(2).unwrap(); }
814
815    #[test]
816    #[should_panic(expected = "OverflowError { max: 3, value: 4 }")]
817    fn u2_overflow_test() { u2::try_from(4).unwrap(); }
818
819    #[test]
820    #[should_panic(expected = "OverflowError { max: 7, value: 8 }")]
821    fn u3_overflow_test() { u3::try_from(8).unwrap(); }
822
823    #[test]
824    #[should_panic(expected = "OverflowError { max: 15, value: 16 }")]
825    fn u4_overflow_test() { u4::try_from(16).unwrap(); }
826
827    #[test]
828    #[should_panic(expected = "OverflowError { max: 31, value: 32 }")]
829    fn u5_overflow_test() { u5::try_from(32).unwrap(); }
830
831    #[test]
832    #[should_panic(expected = "OverflowError { max: 63, value: 64 }")]
833    fn u6_overflow_test() { u6::try_from(64).unwrap(); }
834
835    #[test]
836    #[should_panic(expected = "OverflowError { max: 127, value: 128 }")]
837    fn u7_overflow_test() { u7::try_from(128).unwrap(); }
838
839    #[test]
840    #[should_panic(expected = "OverflowError { max: 16777215, value: 16777216 }")]
841    fn u24_overflow_test() { u24::try_from(1 << 24).unwrap(); }
842
843    #[test]
844    fn u24_endianess() {
845        let val: u32 = 0x00adbeef;
846        let le = [0xef, 0xbe, 0xad];
847        let v1 = u24::with(val);
848        assert_eq!(v1.to_u32(), val);
849        assert_eq!(v1.to_le_bytes(), le);
850        let v2 = u24::from_le_bytes(le);
851        assert_eq!(v2.to_le_bytes(), le);
852        assert_eq!(v2, v1);
853        assert_eq!(v2.to_u32(), v1.to_u32());
854    }
855
856    #[test]
857    fn smallint_div_rem_0() {
858        let u_2 = u2::MAX;
859        let u_2_2 = u2::try_from(2).unwrap();
860        let u_2_half = (u2::MAX / 2, u2::MAX % 2);
861        let u_2_zero = u2::ZERO;
862
863        assert_eq!(u2::div_rem(u_2, u_2_2), Ok(u_2_half));
864        assert_eq!(u2::div_rem(u_2, u_2_zero), Err(DivError::ZeroDiv));
865    }
866
867    #[test]
868    fn smallint_div_rem() {
869        let u_2 = u2::MAX;
870        let u_2_zero = u2::ZERO;
871        assert_eq!(u2::div_rem(u_2, u_2_zero), Err(DivError::ZeroDiv));
872    }
873
874    #[test]
875    fn fmt_test() {
876        let u_1 = u1::MAX;
877        let u_2 = u2::MAX;
878        let u_3 = u3::MAX;
879        let u_4 = u4::MAX;
880        let u_5 = u5::MAX;
881        let u_6 = u6::MAX;
882        let u_7 = u7::MAX;
883        let u_24 = u24::MAX;
884
885        // UpperHex
886        assert_eq!(format!("{:X}", u_1), "1");
887        assert_eq!(format!("{:X}", u_2), "3");
888        assert_eq!(format!("{:X}", u_3), "7");
889        assert_eq!(format!("{:X}", u_4), "F");
890        assert_eq!(format!("{:X}", u_5), "1F");
891        assert_eq!(format!("{:X}", u_6), "3F");
892        assert_eq!(format!("{:X}", u_7), "7F");
893        assert_eq!(format!("{:X}", u_24), "FFFFFF");
894        assert_eq!(format!("{:#X}", u_1), "0x1");
895        assert_eq!(format!("{:#X}", u_2), "0x3");
896        assert_eq!(format!("{:#X}", u_3), "0x7");
897        assert_eq!(format!("{:#X}", u_4), "0xF");
898        assert_eq!(format!("{:#X}", u_5), "0x1F");
899        assert_eq!(format!("{:#X}", u_6), "0x3F");
900        assert_eq!(format!("{:#X}", u_7), "0x7F");
901        assert_eq!(format!("{:#X}", u_24), "0xFFFFFF");
902
903        // LowerHex
904        assert_eq!(format!("{:x}", u_1), "1");
905        assert_eq!(format!("{:x}", u_2), "3");
906        assert_eq!(format!("{:x}", u_3), "7");
907        assert_eq!(format!("{:x}", u_4), "f");
908        assert_eq!(format!("{:x}", u_5), "1f");
909        assert_eq!(format!("{:x}", u_6), "3f");
910        assert_eq!(format!("{:x}", u_7), "7f");
911        assert_eq!(format!("{:x}", u_24), "ffffff");
912        assert_eq!(format!("{:#x}", u_1), "0x1");
913        assert_eq!(format!("{:#x}", u_2), "0x3");
914        assert_eq!(format!("{:#x}", u_3), "0x7");
915        assert_eq!(format!("{:#x}", u_4), "0xf");
916        assert_eq!(format!("{:#x}", u_5), "0x1f");
917        assert_eq!(format!("{:#x}", u_6), "0x3f");
918        assert_eq!(format!("{:#x}", u_7), "0x7f");
919        assert_eq!(format!("{:#x}", u_24), "0xffffff");
920
921        // Octal
922        assert_eq!(format!("{:o}", u_1), "1");
923        assert_eq!(format!("{:o}", u_2), "3");
924        assert_eq!(format!("{:o}", u_3), "7");
925        assert_eq!(format!("{:o}", u_4), "17");
926        assert_eq!(format!("{:o}", u_5), "37");
927        assert_eq!(format!("{:o}", u_6), "77");
928        assert_eq!(format!("{:o}", u_7), "177");
929        assert_eq!(format!("{:o}", u_24), "77777777");
930        assert_eq!(format!("{:#o}", u_1), "0o1");
931        assert_eq!(format!("{:#o}", u_2), "0o3");
932        assert_eq!(format!("{:#o}", u_3), "0o7");
933        assert_eq!(format!("{:#o}", u_4), "0o17");
934        assert_eq!(format!("{:#o}", u_5), "0o37");
935        assert_eq!(format!("{:#o}", u_6), "0o77");
936        assert_eq!(format!("{:#o}", u_7), "0o177");
937        assert_eq!(format!("{:#o}", u_24), "0o77777777");
938
939        // Binary
940        assert_eq!(format!("{:b}", u_1), "1");
941        assert_eq!(format!("{:b}", u_2), "11");
942        assert_eq!(format!("{:b}", u_3), "111");
943        assert_eq!(format!("{:b}", u_4), "1111");
944        assert_eq!(format!("{:b}", u_5), "11111");
945        assert_eq!(format!("{:b}", u_6), "111111");
946        assert_eq!(format!("{:b}", u_7), "1111111");
947        assert_eq!(format!("{:b}", u_24), "111111111111111111111111");
948        assert_eq!(format!("{:#b}", u_1), "0b1");
949        assert_eq!(format!("{:#b}", u_2), "0b11");
950        assert_eq!(format!("{:#b}", u_3), "0b111");
951        assert_eq!(format!("{:#b}", u_4), "0b1111");
952        assert_eq!(format!("{:#b}", u_5), "0b11111");
953        assert_eq!(format!("{:#b}", u_6), "0b111111");
954        assert_eq!(format!("{:#b}", u_7), "0b1111111");
955        assert_eq!(format!("{:#b}", u_24), "0b111111111111111111111111");
956    }
957}