num_convert/
convert_try_from_digits.rs

1use core::ops::Rem;
2
3/// Generic trait for converting integer type digits to some integer type.
4/// - Returns an error if the value is out of range.
5///
6/// # Usage
7/// Basic use of the trait.
8///
9/// ```
10/// use num_convert::TryFromDigits;
11///
12/// assert_eq!(<u8 as TryFromDigits<u16>>::from_digits(65_255_u16), Ok(255_u8));
13/// assert_eq!(<u8 as TryFromDigits<u32>>::from_digits(100_000_u32), Ok(0_u8));
14/// ```
15///
16/// # Examples
17///
18/// ```
19/// # use num_convert::TryFromDigits;
20/// assert_eq!(<u16>::from_digits(10_000_965_535_i64), Ok(65_535_u16));
21/// assert!(<u8>::from_digits(10_000_000_256_u64).is_err());
22/// ```
23pub trait TryFromDigits<T> {
24    /// Returns digits as a number into possible types.
25    fn from_digits(n: T) -> Result<Self, <Self as TryFrom<T>>::Error>
26    where
27        Self: TryFrom<T>;
28}
29
30macro_rules! try_from_digits_impls {
31    ( $($type:ty, $trait_name:ident);* ) => {
32        $(
33            impl<T> TryFromDigits<T> for $type
34            where
35                T: Rem<T, Output = T> + $trait_name,
36                Self: TryFrom<T>,
37            {
38                #[doc = concat!("Converts ", stringify!($type), " to digit range Self.")]
39                #[inline]
40                fn from_digits(n: T) -> Result<Self, <Self as TryFrom<T>>::Error>
41                {
42                    <Self as TryFrom<T>>::try_from(n % T::num())
43                }
44            }
45        )*
46    }
47}
48
49try_from_digits_impls! { i8,Thousands; u8, Thousands; i16, HundredThousands; u16, HundredThousands;
50i32, TenBillions; u32, TenBillions; i64, BigTen; u64, BigHundred; isize, BigTen; usize, BigHundred }
51
52trait Thousands {
53    fn num() -> Self;
54}
55
56macro_rules! thousands_impls {
57    ( $($type:ty),* ; $value:expr ) => {
58        $(
59            impl Thousands for $type {
60                #[inline]
61                fn num() -> Self {
62                    $value
63                }
64            }
65        )*
66    }
67}
68
69thousands_impls! { i16, u16, i32, u32, i64, u64, isize, usize, i128, u128; 1000 }
70
71trait HundredThousands {
72    fn num() -> Self;
73}
74
75macro_rules! hundred_thousands_impls {
76    ( $($type:ty),* ; $value:expr ) => {
77        $(
78            impl HundredThousands for $type {
79                #[inline]
80                fn num() -> Self {
81                    $value
82                }
83            }
84        )*
85    }
86}
87
88hundred_thousands_impls! { i32, u32, i64, u64, isize, usize, i128, u128; 100_000 }
89
90trait TenBillions {
91    fn num() -> Self;
92}
93
94macro_rules! ten_billions_impls {
95    ( $($type:ty),* ; $value:expr ) => {
96        $(
97            impl TenBillions for $type {
98                #[inline]
99                fn num() -> Self {
100                    $value
101                }
102            }
103        )*
104    }
105}
106
107ten_billions_impls! { i64, u64, isize, usize, i128, u128; 10_000_000_000 }
108
109trait BigTen {
110    fn num() -> Self;
111}
112
113trait BigHundred {
114    fn num() -> Self;
115}
116
117macro_rules! big_impls {
118    ( $( $trait_name:ident, $type:ty, $value:expr );* ) => {
119        $(
120            impl $trait_name for $type {
121                #[inline]
122                fn num() -> Self {
123                    $value
124                }
125            }
126        )*
127    }
128}
129
130big_impls! { BigTen, i128, 10_000_000_000_000_000_000; BigHundred, u128, 100_000_000_000_000_000_000 }
131big_impls! { BigTen, u128, 10_000_000_000_000_000_000; BigHundred, i128, 100_000_000_000_000_000_000 }
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use paste::paste;
137
138    macro_rules! try_from_digits {
139        ( $trait_name:ident; $($type:ty),* ; $value:expr ) => {
140            $( paste! {
141                #[test]
142                fn [<digit_$type _value_$value _test>]() {
143                    assert_eq!(<$type as $trait_name>::num(), $value);
144                }
145
146            })*
147        }
148    }
149
150    try_from_digits! { Thousands; i16, u16, i32, u32, i64, u64, isize, usize, i128, u128; 1000 }
151    try_from_digits! { HundredThousands; i32, u32, i64, u64, isize, usize, i128, u128; 100_000 }
152    try_from_digits! { TenBillions; i64, u64, isize, usize, i128, u128; 10_000_000_000 }
153    try_from_digits! { BigTen; i128; 10_000_000_000_000_000_000 }
154    try_from_digits! { BigTen; u128; 10_000_000_000_000_000_000 }
155    try_from_digits! { BigHundred; u128; 100_000_000_000_000_000_000 }
156    try_from_digits! { BigHundred; i128; 100_000_000_000_000_000_000 }
157}