digit_sequence/integers/
from_ints.rs

1use crate::{CrateError, CrateResult, DigitSequence};
2use std::collections::LinkedList;
3
4macro_rules! impl_try_from_signed {
5    ($type: ty) => {
6        /// Conversion from a *signed* integer to a [DigitSequence]
7        /// is fallible - in particular, *negative* values
8        /// result in [CrateError::NegativeNumber].
9        impl TryFrom<$type> for DigitSequence {
10            type Error = CrateError;
11
12            fn try_from(value: $type) -> CrateResult<Self> {
13                if value < 0 {
14                    return Err(CrateError::NegativeNumber(value as i128));
15                }
16
17                Ok(convert_from_positive!(value))
18            }
19        }
20    };
21}
22
23macro_rules! impl_from_unsigned {
24    ($type: ty) => {
25        /// Conversion from an *unsigned* integer to a [DigitSequence]
26        /// is always infallible.
27        impl From<$type> for DigitSequence {
28            fn from(value: $type) -> DigitSequence {
29                convert_from_positive!(value)
30            }
31        }
32    };
33}
34
35macro_rules! convert_from_positive {
36    ($value: ident) => {{
37        let mut result = LinkedList::new();
38        let mut current_value = $value;
39
40        loop {
41            let digit = current_value % 10;
42
43            result.push_front(digit as u8);
44
45            current_value /= 10;
46
47            if current_value == 0 {
48                break;
49            }
50        }
51
52        DigitSequence(result.into_iter().collect())
53    }};
54}
55
56impl_try_from_signed!(i128);
57impl_try_from_signed!(i64);
58impl_try_from_signed!(i32);
59impl_try_from_signed!(i16);
60impl_try_from_signed!(i8);
61impl_try_from_signed!(isize);
62
63impl_from_unsigned!(u128);
64impl_from_unsigned!(u64);
65impl_from_unsigned!(u32);
66impl_from_unsigned!(u16);
67impl_from_unsigned!(u8);
68impl_from_unsigned!(usize);
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use crate::test_utils::{expect_digits_from, expect_try_digits_from};
74    use pretty_assertions::assert_eq;
75
76    #[test]
77    fn convert_0() {
78        let digit_sequence: DigitSequence = 0u8.into();
79
80        assert_eq!(digit_sequence, [0]);
81    }
82
83    #[test]
84    fn convert_negative_number() {
85        let result: CrateResult<DigitSequence> = (-4).try_into();
86
87        assert_eq!(result, Err(CrateError::NegativeNumber(-4)));
88    }
89
90    #[test]
91    fn convert_u8() {
92        expect_digits_from(107u8, &[1, 0, 7])
93    }
94
95    #[test]
96    fn convert_u16() {
97        expect_digits_from(107u16, &[1, 0, 7])
98    }
99
100    #[test]
101    fn convert_u32() {
102        expect_digits_from(107u32, &[1, 0, 7])
103    }
104
105    #[test]
106    fn convert_u64() {
107        expect_digits_from(107u64, &[1, 0, 7])
108    }
109
110    #[test]
111    fn convert_u128() {
112        expect_digits_from(107u128, &[1, 0, 7])
113    }
114
115    #[test]
116    fn convert_usize() {
117        expect_digits_from(107usize, &[1, 0, 7])
118    }
119
120    #[test]
121    fn convert_i8() {
122        expect_try_digits_from(107i8, &[1, 0, 7])
123    }
124
125    #[test]
126    fn convert_i16() {
127        expect_try_digits_from(107i16, &[1, 0, 7])
128    }
129
130    #[test]
131    fn convert_i32() {
132        expect_try_digits_from(107i32, &[1, 0, 7])
133    }
134
135    #[test]
136    fn convert_i64() {
137        expect_try_digits_from(107i64, &[1, 0, 7])
138    }
139
140    #[test]
141    fn convert_i128() {
142        expect_try_digits_from(107i128, &[1, 0, 7])
143    }
144
145    #[test]
146    fn convert_isize() {
147        expect_try_digits_from(107isize, &[1, 0, 7])
148    }
149}