fixed_bigint/heapless/
string_conversion.rs1use super::HeaplessBigInt;
14use crate::MachineWord;
15use const_num_traits::{CarryingMul, Nct, ToPrimitive, Zero};
16use core::fmt::Write;
17
18impl<T, const CAP: usize> core::fmt::Display for HeaplessBigInt<T, CAP, Nct>
19where
20 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
21{
22 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23 const MAX_DIGITS: usize = 20;
27
28 if <Self as Zero>::is_zero(self) {
29 return f.write_char('0');
30 }
31
32 let mut digit_blocks = [[0u8; MAX_DIGITS]; CAP];
35 let mut digit_count = 0;
36 let mut number = *self;
37 let ten = Self::from(10u8);
38
39 while !<Self as Zero>::is_zero(&number) && digit_count < CAP * MAX_DIGITS {
40 let (quotient, remainder) = number.div_rem(&ten);
41 let digit = <T as ToPrimitive>::to_u8(&remainder.limbs[0]).unwrap_or(0);
43 digit_blocks[digit_count / MAX_DIGITS][digit_count % MAX_DIGITS] = b'0' + digit;
44 digit_count += 1;
45 number = quotient;
46 }
47
48 for i in (0..digit_count).rev() {
49 f.write_char(digit_blocks[i / MAX_DIGITS][i % MAX_DIGITS] as char)?;
50 }
51 Ok(())
52 }
53}
54
55impl<T, const CAP: usize> HeaplessBigInt<T, CAP, Nct>
56where
57 T: MachineWord,
58{
59 fn hex_fmt(
63 &self,
64 formatter: &mut core::fmt::Formatter<'_>,
65 uppercase: bool,
66 ) -> core::fmt::Result {
67 fn to_casedigit(byte: u8, uppercase: bool) -> Result<char, core::fmt::Error> {
68 let digit = core::char::from_digit(byte as u32, 16).ok_or(core::fmt::Error)?;
69 if uppercase {
70 digit.to_uppercase().next().ok_or(core::fmt::Error)
71 } else {
72 digit.to_lowercase().next().ok_or(core::fmt::Error)
73 }
74 }
75
76 let mut leading_zero = true;
77 let mut maybe_write = |nibble: char| -> core::fmt::Result {
78 leading_zero &= nibble == '0';
79 if !leading_zero {
80 formatter.write_char(nibble)?;
81 }
82 Ok(())
83 };
84
85 for index in (0..self.len as usize).rev() {
86 for &byte in self.limbs[index].to_be_bytes().as_ref() {
87 maybe_write(to_casedigit((byte & 0xf0) >> 4, uppercase)?)?;
88 maybe_write(to_casedigit(byte & 0x0f, uppercase)?)?;
89 }
90 }
91 Ok(())
92 }
93}
94
95impl<T, const CAP: usize> core::fmt::UpperHex for HeaplessBigInt<T, CAP, Nct>
96where
97 T: MachineWord,
98{
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 self.hex_fmt(f, true)
101 }
102}
103
104impl<T, const CAP: usize> core::fmt::LowerHex for HeaplessBigInt<T, CAP, Nct>
105where
106 T: MachineWord,
107{
108 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
109 self.hex_fmt(f, false)
110 }
111}
112
113#[cfg(feature = "num-traits")]
114impl<T, const CAP: usize> num_traits::Num for HeaplessBigInt<T, CAP, Nct>
115where
116 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
117{
118 type FromStrRadixErr = core::num::ParseIntError;
119
120 fn from_str_radix(input: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
121 use crate::fixeduint::{make_empty_error, make_overflow_err, make_parse_int_err};
122 use const_num_traits::{CheckedAdd, CheckedMul};
123
124 if input.is_empty() {
125 return Err(make_empty_error());
126 }
127 if !(2..=16).contains(&radix) {
128 return Err(make_overflow_err());
129 }
130
131 let mut ret = <Self as Zero>::zero().widened(CAP as u16);
136 let range = match input.find(|c: char| c != '0') {
137 Some(x) => &input[x..],
138 _ => input,
139 };
140 let radix_val = Self::from(radix as u8);
141 for c in range.chars() {
142 let digit = c.to_digit(radix).ok_or_else(make_parse_int_err)?;
143 ret = CheckedMul::checked_mul(ret, radix_val).ok_or_else(make_overflow_err)?;
144 ret = CheckedAdd::checked_add(ret, Self::from(digit as u8))
145 .ok_or_else(make_overflow_err)?;
146 }
147 Ok(ret)
148 }
149}
150
151#[cfg(feature = "num-traits")]
152impl<T, const CAP: usize> core::str::FromStr for HeaplessBigInt<T, CAP, Nct>
153where
154 T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
155{
156 type Err = core::num::ParseIntError;
157
158 fn from_str(s: &str) -> Result<Self, Self::Err> {
159 <Self as num_traits::Num>::from_str_radix(s, 10)
160 }
161}