1 #![allow(trivial_numeric_casts)]
2 
3 use core::marker::PhantomData;
4 use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
5 use core::ptr;
6 
7 use crate::buffer::Buffer;
8 use crate::constants::{MAX_BUF_LEN, TABLE};
9 use crate::format::Format;
10 use crate::grouping::Grouping;
11 use crate::sealed::Sealed;
12 use crate::to_formatted_str::ToFormattedStr;
13 
14 // unsigned integers
15 
16 impl ToFormattedStr for u8 {
17     #[doc(hidden)]
18     #[inline(always)]
read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, _: &F) -> usize where F: Format,19     fn read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, _: &F) -> usize
20     where
21         F: Format,
22     {
23         buf.write_with_itoa(*self)
24     }
25 }
26 
27 macro_rules! impl_unsigned {
28     ($type:ty) => {
29         impl ToFormattedStr for $type {
30             #[doc(hidden)]
31             #[inline(always)]
32             fn read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, format: &F) -> usize
33             where
34                 F: Format,
35             {
36                 let n = *self as u128;
37                 run_core_algorithm(n, buf, format)
38             }
39         }
40     };
41 }
42 
43 impl_unsigned!(u16);
44 impl_unsigned!(u32);
45 impl_unsigned!(usize);
46 impl_unsigned!(u64);
47 impl_unsigned!(u128);
48 
49 impl Sealed for u8 {}
50 impl Sealed for u16 {}
51 impl Sealed for u32 {}
52 impl Sealed for usize {}
53 impl Sealed for u64 {}
54 impl Sealed for u128 {}
55 
56 // signed integers
57 
58 macro_rules! impl_signed {
59     ($type:ty) => {
60         impl ToFormattedStr for $type {
61             #[doc(hidden)]
62             #[inline(always)]
63             fn read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, format: &F) -> usize
64             where
65                 F: Format,
66             {
67                 if self.is_negative() {
68                     let n = (!(*self as u128)).wrapping_add(1); // make positive by adding 1 to the 2s complement
69                     let c = run_core_algorithm(n, buf, format);
70                     let minus_sign = format.minus_sign().into_str();
71                     let min_len = minus_sign.len();
72                     buf.pos -= min_len;
73                     for (i, byte) in minus_sign.as_bytes().iter().enumerate() {
74                         buf.inner[buf.pos + i] = *byte;
75                     }
76                     c + min_len
77                 } else {
78                     let n = *self as u128;
79                     let c = run_core_algorithm(n, buf, format);
80                     c
81                 }
82             }
83         }
84     };
85 }
86 
87 impl_signed!(i8);
88 impl_signed!(i16);
89 impl_signed!(i32);
90 impl_signed!(isize);
91 impl_signed!(i64);
92 impl_signed!(i128);
93 
94 impl Sealed for i8 {}
95 impl Sealed for i16 {}
96 impl Sealed for i32 {}
97 impl Sealed for isize {}
98 impl Sealed for i64 {}
99 impl Sealed for i128 {}
100 
101 // non-zero unsigned integers
102 
103 impl ToFormattedStr for NonZeroU8 {
104     #[doc(hidden)]
105     #[inline(always)]
read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, _: &F) -> usize where F: Format,106     fn read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, _: &F) -> usize
107     where
108         F: Format,
109     {
110         buf.write_with_itoa(self.get())
111     }
112 }
113 
114 macro_rules! impl_non_zero {
115     ($type:ty) => {
116         impl ToFormattedStr for $type {
117             #[doc(hidden)]
118             #[inline(always)]
119             fn read_to_buffer<'a, F>(&self, buf: &'a mut Buffer, format: &F) -> usize
120             where
121                 F: Format,
122             {
123                 let n = self.get() as u128;
124                 run_core_algorithm(n, buf, format)
125             }
126         }
127     };
128 }
129 
130 impl_non_zero!(NonZeroU16);
131 impl_non_zero!(NonZeroU32);
132 impl_non_zero!(NonZeroUsize);
133 impl_non_zero!(NonZeroU64);
134 impl_non_zero!(NonZeroU128);
135 
136 impl Sealed for NonZeroU8 {}
137 impl Sealed for NonZeroU16 {}
138 impl Sealed for NonZeroU32 {}
139 impl Sealed for NonZeroUsize {}
140 impl Sealed for NonZeroU64 {}
141 impl Sealed for NonZeroU128 {}
142 
143 // helper functions
144 
145 #[inline(always)]
run_core_algorithm<F>(mut n: u128, buf: &mut Buffer, format: &F) -> usize where F: Format,146 fn run_core_algorithm<F>(mut n: u128, buf: &mut Buffer, format: &F) -> usize
147 where
148     F: Format,
149 {
150     // Bail out early if we can just use itoa
151     // (i.e. if we don't have a separator)
152     let separator = format.separator().into_str();
153     let grouping = format.grouping();
154     if separator.is_empty() || grouping == Grouping::Posix {
155         return buf.write_with_itoa(n);
156     }
157 
158     // Reset our position to the end of the buffer
159     buf.pos = MAX_BUF_LEN;
160     buf.end = MAX_BUF_LEN;
161 
162     // Collect separator information
163     let mut sep = Sep {
164         ptr: separator.as_bytes().as_ptr(),
165         len: separator.len(),
166         pos: MAX_BUF_LEN as isize - 4,
167         step: match grouping {
168             Grouping::Standard => 4isize,
169             Grouping::Indian => 3isize,
170             Grouping::Posix => unreachable!(),
171         },
172         phantom: PhantomData,
173     };
174 
175     // Start the main algorithm
176     while n >= 10_000 {
177         let remainder = n % 10_000;
178         let table_index = ((remainder % 100) << 1) as isize;
179         write_two_bytes(buf, &mut sep, table_index);
180         let table_index = ((remainder / 100) << 1) as isize;
181         write_two_bytes(buf, &mut sep, table_index);
182         n /= 10_000;
183     }
184     let mut n = n as isize;
185     while n >= 100 {
186         let table_index = (n % 100) << 1;
187         write_two_bytes(buf, &mut sep, table_index);
188         n /= 100;
189     }
190     if n >= 10 {
191         let table_index = n << 1;
192         write_two_bytes(buf, &mut sep, table_index);
193     } else {
194         let table_index = n << 1;
195         write_one_byte(buf, &mut sep, table_index + 1);
196     }
197 
198     buf.end - buf.pos
199 }
200 
201 struct Sep<'a> {
202     ptr: *const u8,
203     len: usize,
204     pos: isize,
205     step: isize,
206     phantom: PhantomData<&'a ()>,
207 }
208 
209 #[inline(always)]
write_one_byte(buf: &mut Buffer, sep: &mut Sep, table_index: isize)210 fn write_one_byte(buf: &mut Buffer, sep: &mut Sep, table_index: isize) {
211     buf.pos -= 1;
212     if sep.pos == (buf.pos as isize) {
213         buf.pos -= sep.len - 1;
214         unsafe { ptr::copy_nonoverlapping(sep.ptr, buf.as_mut_ptr().add(buf.pos), sep.len) }
215         sep.pos -= sep.step + (sep.len as isize - 1);
216         buf.pos -= 1;
217     }
218     unsafe {
219         ptr::copy_nonoverlapping(
220             TABLE.as_ptr().offset(table_index),
221             buf.as_mut_ptr().add(buf.pos),
222             1,
223         )
224     };
225 }
226 
227 #[inline(always)]
write_two_bytes(buf: &mut Buffer, sep: &mut Sep, table_index: isize)228 fn write_two_bytes(buf: &mut Buffer, sep: &mut Sep, table_index: isize) {
229     write_one_byte(buf, sep, table_index + 1);
230     write_one_byte(buf, sep, table_index);
231 }
232