digit_sequence/integers/
to_ints.rs

1use crate::{CrateError, CrateResult, DigitSequence};
2
3macro_rules! impl_try_to_unsigned {
4    ($type: ty) => {
5        /// Conversion from a [DigitSequence] is only available to
6        /// *unsigned* integers.
7        ///
8        /// It is always fallible - because
9        /// it might result in a [CrateError::Overflow].
10        impl TryFrom<DigitSequence> for $type {
11            type Error = CrateError;
12
13            fn try_from(sequence: DigitSequence) -> CrateResult<Self> {
14                (&sequence).try_into()
15            }
16        }
17
18        /// Conversion from a &[DigitSequence] is only available to
19        /// *unsigned* integers.
20        ///
21        /// It is always fallible - because
22        /// it might result in a [CrateError::Overflow].
23        impl TryFrom<&DigitSequence> for $type {
24            type Error = CrateError;
25
26            fn try_from(sequence: &DigitSequence) -> CrateResult<Self> {
27                let mut result = 0 as Self;
28
29                let enumerated_increasing_digits = sequence.iter().rev().enumerate();
30
31                for (index, &digit) in enumerated_increasing_digits {
32                    let power_of_ten: u32 = index.try_into().or(Err(CrateError::Overflow))?;
33
34                    let magnitude = (10 as Self)
35                        .checked_pow(power_of_ten)
36                        .ok_or(CrateError::Overflow)?;
37
38                    let addition_term = (digit as Self)
39                        .checked_mul(magnitude)
40                        .ok_or(CrateError::Overflow)?;
41
42                    result = result
43                        .checked_add(addition_term)
44                        .ok_or(CrateError::Overflow)?;
45                }
46
47                Ok(result)
48            }
49        }
50    };
51}
52
53impl_try_to_unsigned!(u128);
54impl_try_to_unsigned!(u64);
55impl_try_to_unsigned!(u32);
56impl_try_to_unsigned!(u16);
57impl_try_to_unsigned!(u8);
58impl_try_to_unsigned!(usize);
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use crate::test_utils::*;
64    use pretty_assertions::assert_eq;
65
66    #[test]
67    fn roundtrip_convert_0() {
68        expect_try_roundtrip_conversion(0u8);
69    }
70
71    #[test]
72    fn roundtrip_convert_u8() {
73        expect_try_roundtrip_conversion(90u8);
74    }
75
76    #[test]
77    fn roundtrip_convert_u16() {
78        expect_try_roundtrip_conversion(90u16);
79    }
80
81    #[test]
82    fn roundtrip_convert_u32() {
83        expect_try_roundtrip_conversion(90u32);
84    }
85
86    #[test]
87    fn roundtrip_convert_u64() {
88        expect_try_roundtrip_conversion(90u64);
89    }
90
91    #[test]
92    fn roundtrip_convert_u128() {
93        expect_try_roundtrip_conversion(90u128);
94    }
95
96    #[test]
97    fn roundtrip_convert_usize() {
98        expect_try_roundtrip_conversion(90usize);
99    }
100
101    #[test]
102    fn convert_u128_max() {
103        expect_try_roundtrip_conversion(u128::MAX);
104    }
105
106    fn expect_unsigned_overflow(source: &str) {
107        let sequence: DigitSequence = source.parse().unwrap();
108        let conversion_result: CrateResult<u128> = sequence.try_into();
109
110        assert_eq!(conversion_result, Err(CrateError::Overflow));
111    }
112
113    #[test]
114    fn convert_u128_max_plus_one_to_u128() {
115        expect_unsigned_overflow("340282366920938463463374607431768211456");
116    }
117
118    #[test]
119    fn convert_huge_sequence_of_1s_to_u128() {
120        expect_unsigned_overflow("1".repeat(100).as_str());
121    }
122
123    #[test]
124    fn convert_a_1_of_huge_magnitude_to_u128() {
125        expect_unsigned_overflow(&format!("1{}", "0".repeat(100)));
126    }
127
128    #[test]
129    fn roundtrip_convert_0_via_ref() {
130        expect_try_roundtrip_conversion_via_ref(0u8);
131    }
132
133    #[test]
134    fn roundtrip_convert_u8_via_ref() {
135        expect_try_roundtrip_conversion_via_ref(90u8);
136    }
137
138    #[test]
139    fn roundtrip_convert_u16_via_ref() {
140        expect_try_roundtrip_conversion_via_ref(90u16);
141    }
142
143    #[test]
144    fn roundtrip_convert_u32_via_ref() {
145        expect_try_roundtrip_conversion_via_ref(90u32);
146    }
147
148    #[test]
149    fn roundtrip_convert_u64_via_ref() {
150        expect_try_roundtrip_conversion_via_ref(90u64);
151    }
152
153    #[test]
154    fn roundtrip_convert_u128_via_ref() {
155        expect_try_roundtrip_conversion_via_ref(90u128);
156    }
157
158    #[test]
159    fn roundtrip_convert_usize_via_ref() {
160        expect_try_roundtrip_conversion_via_ref(90usize);
161    }
162
163    #[test]
164    fn convert_u128_max_via_ref() {
165        expect_try_roundtrip_conversion_via_ref(u128::MAX);
166    }
167
168    fn expect_unsigned_overflow_via_ref(source: &str) {
169        let sequence: DigitSequence = source.parse().unwrap();
170        let reference = &sequence;
171        let conversion_result: CrateResult<u128> = reference.try_into();
172
173        assert_eq!(conversion_result, Err(CrateError::Overflow));
174    }
175
176    #[test]
177    fn convert_u128_max_plus_one_to_u128_via_ref() {
178        expect_unsigned_overflow_via_ref("340282366920938463463374607431768211456");
179    }
180
181    #[test]
182    fn convert_huge_sequence_of_1s_to_u128_via_ref() {
183        expect_unsigned_overflow_via_ref(&"1".repeat(100));
184    }
185
186    #[test]
187    fn convert_a_1_of_huge_magnitude_to_u128_via_ref() {
188        expect_unsigned_overflow_via_ref(&format!("1{}", "0".repeat(100)));
189    }
190}