1use crate::constants::ASCII_TO_INT_FACTOR;
2
3pub trait IntoAscii {
8 #[inline]
20 fn itoa(&self) -> Vec<u8>
21 where
22 Self: Copy,
23 {
24 let size = Self::digits10(*self);
25 let mut buff = vec![0; size];
26
27 self.int_to_bytes(&mut buff);
28 buff
29 }
30
31 fn digits10(self) -> usize;
33
34 fn int_to_bytes(self, buff: &mut [u8]);
37}
38
39#[rustfmt::skip]
40macro_rules! unsigned_into_ascii {
41 ($int:ty) => {
42 impl IntoAscii for $int {
43 #[inline]
44 fn digits10(mut self) -> usize {
45 let mut result = 1;
46 loop {
47 if self < 10 { break result;}
48 if self < 100 { break result + 1; }
49 if self < 1000 { break result + 2; }
50 if self < 10000 { break result + 3; }
51
52 self /= 10_000;
53 result += 4;
54 }
55 }
56
57 #[inline]
58 fn int_to_bytes(mut self, buff: &mut [u8]) {
59 let mut chunked = buff.rchunks_exact_mut(4);
60 for mut chunk in chunked.by_ref() {
61 let q = self / 10;
62 let q1 = self / 100;
63 let q2 = self / 1000;
64
65 let r = (self % 10) as u8 + ASCII_TO_INT_FACTOR;
66 let r1 = (q % 10) as u8 + ASCII_TO_INT_FACTOR;
67 let r2 = (q1 % 10) as u8 + ASCII_TO_INT_FACTOR;
68 let r3 = (q2 % 10) as u8 + ASCII_TO_INT_FACTOR;
69
70 match &mut chunk {
71 [b3, b2, b1, b] => {
72 *b = r;
73 *b1 = r1;
74 *b2 = r2;
75 *b3 = r3;
76 }
77 _ => unreachable!(),
78 }
79
80 self /= 10_000;
81 }
82
83 for byte in chunked.into_remainder().iter_mut().rev() {
84 let q = self / 10;
85 let r = (self % 10) as u8 + ASCII_TO_INT_FACTOR;
86 *byte = r;
87
88 if q == 0 {
90 break;
91 }
92
93 self = q;
94 }
95 }
96 }
97 };
98
99 (@u8) => {
100 impl IntoAscii for u8 {
101 #[inline]
102 fn digits10(self) -> usize {
103 if self < 10 {
104 1
105 } else if self < 100 {
106 2
107 } else {
108 3
109 }
110 }
111
112 #[inline]
113 fn int_to_bytes(mut self, buff: &mut [u8]) {
114 for byte in buff.iter_mut().rev() {
115 let q = self / 10;
116 let r = (self % 10) as u8 + ASCII_TO_INT_FACTOR;
117 *byte = r;
118
119 if self == 0 {
120 break;
121 }
122
123 self = q;
124 }
125 }
126 }
127 };
128}
129
130macro_rules! signed_into_ascii {
131 ($int:ty, $unsigned_version:ty) => {
132 impl IntoAscii for $int {
133 #[inline]
134 fn itoa(&self) -> Vec<u8>
135 where
136 Self: Copy,
137 {
138 let (n, size) = if self.is_negative() {
139 (self * -1, self.digits10() + 1)
140 } else {
141 (*self, self.digits10())
142 };
143
144 let mut buff = vec![b'-'; size];
145 (n as $unsigned_version).int_to_bytes(&mut buff);
146 buff
147 }
148
149 #[inline]
150 fn digits10(self) -> usize {
151 (self.abs() as $unsigned_version).digits10()
152 }
153
154 #[inline]
155 fn int_to_bytes(self, buff: &mut [u8]) {
156 if self.is_negative() {
157 (self.abs() as $unsigned_version).int_to_bytes(buff);
158 buff[0] = b'-';
159 } else {
160 (self as $unsigned_version).int_to_bytes(buff);
161 }
162 }
163 }
164 };
165}
166
167unsigned_into_ascii!(@u8);
168unsigned_into_ascii!(u16);
169unsigned_into_ascii!(u32);
170unsigned_into_ascii!(u64);
171unsigned_into_ascii!(usize);
172
173signed_into_ascii!(i8, u8);
174signed_into_ascii!(i16, u16);
175signed_into_ascii!(i32, u32);
176signed_into_ascii!(i64, u64);
177signed_into_ascii!(isize, usize);
178
179impl<'a, N: Copy> IntoAscii for &'a N
180where
181 N: IntoAscii,
182{
183 #[inline]
184 fn digits10(self) -> usize {
185 (*self).digits10()
186 }
187
188 #[inline]
189 fn int_to_bytes(self, buff: &mut [u8]) {
190 (*self).int_to_bytes(buff);
191 }
192}
193
194impl<'a, N: Copy> IntoAscii for &'a mut N
195where
196 N: IntoAscii,
197{
198 #[inline]
199 fn digits10(self) -> usize {
200 (*self).digits10()
201 }
202
203 #[inline]
204 fn int_to_bytes(self, buff: &mut [u8]) {
205 (*self).int_to_bytes(buff);
206 }
207}
208
209impl<N: Copy> IntoAscii for Box<N>
210where
211 N: IntoAscii,
212{
213 #[inline]
214 fn digits10(self) -> usize {
215 (*self).digits10()
216 }
217
218 #[inline]
219 fn int_to_bytes(self, buff: &mut [u8]) {
220 (*self).int_to_bytes(buff);
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::IntoAscii;
227
228 #[test]
229 fn itoa_usize() {
230 assert_eq!(
231 123_456_789usize.itoa(),
232 vec![b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9']
233 );
234 }
235
236 #[test]
237 fn itoa_isize() {
238 assert_eq!(
239 (-123_456_789isize).itoa(),
240 vec![b'-', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9']
241 );
242 }
243
244 #[test]
245 fn itoa_0usize() {
246 assert_eq!(0usize.itoa(), vec![b'0']);
247 }
248
249 #[test]
250 fn itoa_0isize() {
251 assert_eq!((-0isize).itoa(), vec![b'0']);
252 }
253
254 #[test]
255 fn digits10_usize() {
256 assert_eq!(123456789usize.digits10(), 9);
257 }
258
259 #[test]
260 fn digits10_isize() {
261 assert_eq!((-123456789isize).digits10(), 9);
262 }
263
264 #[test]
265 fn digits10_0usize() {
266 assert_eq!(0usize.digits10(), 1);
267 }
268
269 #[test]
270 fn digits10_0isize() {
271 assert_eq!((-0isize).digits10(), 1);
272 }
273}