1use atoi::FromRadix10SignedChecked;
4use itoa::Integer;
5
6use crate::error::Error;
7
8use self::private::{HexExtensions, Overflow};
9
10pub struct DecEncoder {
12 inner: itoa::Buffer,
13}
14
15impl DecEncoder {
16 #[inline]
18 pub fn new() -> Self {
19 Self {
20 inner: itoa::Buffer::new(),
21 }
22 }
23
24 pub fn encode<T>(&mut self, n: T) -> &[u8]
26 where
27 T: DecNumber,
28 {
29 self.inner.format(n).as_bytes()
30 }
31}
32
33impl Default for DecEncoder {
34 #[inline]
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40pub struct HexEncoder {
42 buffer: [u8; 32],
43}
44
45impl HexEncoder {
46 const LOWER_HEX_DIGITS: &[u8] = b"0123456789abcdef";
47
48 #[inline]
50 pub fn new() -> Self {
51 Self { buffer: [b'0'; 32] }
52 }
53
54 pub fn encode<T>(&mut self, mut n: T) -> &[u8]
56 where
57 T: HexNumber,
58 {
59 let mut idx = 31;
60
61 while n != T::ZERO {
62 let digit = n.pop_hex_digit();
63
64 self.buffer[idx] = Self::LOWER_HEX_DIGITS[digit as usize];
65
66 idx = idx.wrapping_sub(1);
67 }
68
69 if idx == 31 {
70 self.buffer[31] = b'0';
71 } else {
72 idx = idx.wrapping_add(1);
73 }
74
75 &self.buffer[idx..]
76 }
77}
78
79impl Default for HexEncoder {
80 #[inline]
81 fn default() -> Self {
82 Self::new()
83 }
84}
85
86pub fn decode_dec<T>(src: &[u8]) -> Result<T, Error>
88where
89 T: DecNumber,
90{
91 let is_valid = src
92 .iter()
93 .copied()
94 .enumerate()
95 .all(|(idx, b)| (idx == 0 && b == b'-') || b.is_ascii_digit());
96
97 if !is_valid || src.is_empty() {
98 return Err(Error::from_static_msg("invalid decimal number"));
99 }
100
101 atoi::atoi(src).ok_or_else(|| Error::from_static_msg("overflow"))
102}
103
104pub fn decode_hex<T>(src: &[u8]) -> Result<T, Error>
106where
107 T: HexNumber,
108{
109 let mut n = T::ZERO;
110
111 if src.is_empty() {
112 return Err(Error::from_static_msg("empty hex string"));
113 }
114
115 for &b in src {
116 let digit = if b.is_ascii_digit() {
117 b - b'0'
118 } else if (b'a'..=b'f').contains(&b) {
119 b - b'a' + 10
120 } else if (b'A'..=b'F').contains(&b) {
121 b - b'A' + 10
122 } else {
123 return Err(Error::from_static_msg("not a hex digit"));
124 };
125
126 n.push_hex_digit(digit)?;
127 }
128
129 Ok(n)
130}
131
132pub trait DecNumber: FromRadix10SignedChecked + Integer {}
134
135macro_rules! impl_dec_number {
136 ($t:ty) => {
137 impl DecNumber for $t {}
138 };
139}
140
141impl_dec_number!(i8);
142impl_dec_number!(i16);
143impl_dec_number!(i32);
144impl_dec_number!(i64);
145impl_dec_number!(i128);
146impl_dec_number!(isize);
147
148impl_dec_number!(u8);
149impl_dec_number!(u16);
150impl_dec_number!(u32);
151impl_dec_number!(u64);
152impl_dec_number!(u128);
153impl_dec_number!(usize);
154
155pub trait HexNumber: HexExtensions {}
157
158macro_rules! impl_hex_number {
159 ($t:ty) => {
160 impl HexExtensions for $t {
161 const ZERO: Self = 0;
162
163 fn pop_hex_digit(&mut self) -> u8 {
164 let digit = (*self & 0xf) as u8;
165
166 *self >>= 4;
167
168 digit
169 }
170
171 fn push_hex_digit(&mut self, digit: u8) -> Result<(), Overflow> {
172 if (*self >> ((std::mem::size_of::<$t>() << 3) - 4)) != 0 {
173 return Err(Overflow);
174 }
175
176 *self = (*self << 4) | ((digit & 0xf) as $t);
177
178 Ok(())
179 }
180 }
181
182 impl HexNumber for $t {}
183 };
184}
185
186impl_hex_number!(u8);
187impl_hex_number!(u16);
188impl_hex_number!(u32);
189impl_hex_number!(u64);
190impl_hex_number!(u128);
191impl_hex_number!(usize);
192
193mod private {
194 pub trait HexExtensions: PartialEq + Sized {
196 const ZERO: Self;
197
198 fn pop_hex_digit(&mut self) -> u8;
200
201 fn push_hex_digit(&mut self, digit: u8) -> Result<(), Overflow>;
203 }
204
205 pub struct Overflow;
207}
208
209impl From<Overflow> for Error {
210 fn from(_: Overflow) -> Self {
211 Error::from_static_msg("overflow")
212 }
213}