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