Skip to main content

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