fixed_bigint/fixeduint/
string_conversion.rs

1use core::fmt::Write;
2use num_traits::{Num, ToPrimitive, Zero};
3
4use super::{make_empty_error, make_overflow_err, make_parse_int_err, FixedUInt, MachineWord};
5
6impl<T: MachineWord, const N: usize> num_traits::Num for FixedUInt<T, N> {
7    type FromStrRadixErr = core::num::ParseIntError;
8    fn from_str_radix(
9        input: &str,
10        radix: u32,
11    ) -> Result<Self, <Self as num_traits::Num>::FromStrRadixErr> {
12        if input.is_empty() {
13            return Err(make_empty_error());
14        }
15
16        if !(2..=16).contains(&radix) {
17            return Err(make_overflow_err()); // Invalid radix
18        }
19
20        let mut ret = Self::zero();
21        let range = match input.find(|c: char| c != '0') {
22            Some(x) => &input[x..],
23            _ => input,
24        };
25
26        for c in range.chars() {
27            let digit = match c.to_digit(radix) {
28                Some(d) => d,
29                None => return Err(make_parse_int_err()), // Invalid character for the radix
30            };
31
32            ret = num_traits::CheckedMul::checked_mul(&ret, &Self::from(radix as u8))
33                .ok_or(make_overflow_err())?;
34            ret = num_traits::CheckedAdd::checked_add(&ret, &Self::from(digit as u8))
35                .ok_or(make_overflow_err())?;
36        }
37
38        Ok(ret)
39    }
40}
41
42impl<T: MachineWord, const N: usize> core::fmt::UpperHex for FixedUInt<T, N>
43where
44    u8: core::convert::TryFrom<T>,
45{
46    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
47        self.hex_fmt(formatter, true)
48    }
49}
50
51impl<T: MachineWord, const N: usize> core::fmt::LowerHex for FixedUInt<T, N>
52where
53    u8: core::convert::TryFrom<T>,
54{
55    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
56        self.hex_fmt(formatter, false)
57    }
58}
59
60impl<T: MachineWord, const N: usize> core::fmt::Display for FixedUInt<T, N> {
61    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
62        const MAX_DIGITS: usize = 20;
63
64        if self.is_zero() {
65            return f.write_char('0');
66        }
67
68        // 20 is sized for u64
69        let mut digit_blocks = [[0u8; MAX_DIGITS]; N];
70        let mut digit_count = 0;
71        let mut number = *self;
72        let ten = Self::from(10u8);
73
74        // Extract digits into our storage
75        while !number.is_zero() && digit_count < N * MAX_DIGITS {
76            let (quotient, remainder) = number.div_rem(&ten);
77            let digit = remainder.to_u8().unwrap();
78
79            let block_idx = digit_count / MAX_DIGITS;
80            let digit_idx = digit_count % MAX_DIGITS;
81            digit_blocks[block_idx][digit_idx] = b'0' + digit;
82
83            digit_count += 1;
84            number = quotient;
85        }
86
87        // Write digits in reverse order
88        for i in (0..digit_count).rev() {
89            let block_idx = i / MAX_DIGITS;
90            let digit_idx = i % MAX_DIGITS;
91            f.write_char(digit_blocks[block_idx][digit_idx] as char)?;
92        }
93
94        Ok(())
95    }
96}
97
98impl<T: MachineWord, const N: usize> core::str::FromStr for FixedUInt<T, N> {
99    type Err = core::num::ParseIntError;
100
101    fn from_str(s: &str) -> Result<Self, Self::Err> {
102        Self::from_str_radix(s, 10)
103    }
104}