1#![doc(html_root_url = "https://docs.rs/itoa/1.0.11")]
34#![no_std]
35#![allow(
36 clippy::cast_lossless,
37 clippy::cast_possible_truncation,
38 clippy::cast_possible_wrap,
39 clippy::cast_sign_loss,
40 clippy::expl_impl_clone_on_copy,
41 clippy::must_use_candidate,
42 clippy::needless_doctest_main,
43 clippy::unreadable_literal
44)]
45
46mod udiv128;
47
48use core::{
49 mem::{self, MaybeUninit},
50 ptr, slice, str,
51};
52
53pub struct Buffer {
64 bytes: [MaybeUninit<u8>; I128_MAX_LEN],
65}
66
67impl Default for Buffer {
68 #[inline]
69 fn default() -> Buffer {
70 Buffer::new()
71 }
72}
73
74impl Copy for Buffer {}
75
76impl Clone for Buffer {
77 #[inline]
78 #[allow(clippy::non_canonical_clone_impl)] fn clone(&self) -> Self {
80 Buffer::new()
81 }
82}
83
84impl Buffer {
85 #[inline]
88 #[cfg_attr(feature = "no-panic", no_panic)]
89 pub fn new() -> Buffer {
90 let bytes = [MaybeUninit::<u8>::uninit(); I128_MAX_LEN];
91 Buffer {
92 bytes,
93 }
94 }
95
96 #[cfg_attr(feature = "no-panic", no_panic)]
99 pub fn format<I: Integer>(&mut self, i: I) -> &str {
100 i.write(unsafe {
101 &mut *(&mut self.bytes as *mut [MaybeUninit<u8>; I128_MAX_LEN] as *mut <I as private::Sealed>::Buffer)
102 })
103 }
104}
105
106pub trait Integer: private::Sealed {}
110
111mod private {
113 pub trait Sealed: Copy {
114 type Buffer: 'static;
115 fn write(self, buf: &mut Self::Buffer) -> &str;
116 }
117}
118
119const DEC_DIGITS_LUT: &[u8] = b"\
120 0001020304050607080910111213141516171819\
121 2021222324252627282930313233343536373839\
122 4041424344454647484950515253545556575859\
123 6061626364656667686970717273747576777879\
124 8081828384858687888990919293949596979899";
125
126macro_rules! impl_Integer {
129 ($($max_len:expr => $t:ident),* as $conv_fn:ident) => {$(
130 impl Integer for $t {}
131
132 impl private::Sealed for $t {
133 type Buffer = [MaybeUninit<u8>; $max_len];
134
135 #[allow(unused_comparisons)]
136 #[inline]
137 #[cfg_attr(feature = "no-panic", no_panic)]
138 fn write(self, buf: &mut [MaybeUninit<u8>; $max_len]) -> &str {
139 let is_nonnegative = self >= 0;
140 let mut n = if is_nonnegative {
141 self as $conv_fn
142 } else {
143 (!(self as $conv_fn)).wrapping_add(1)
145 };
146 let mut curr = buf.len() as isize;
147 let buf_ptr = buf.as_mut_ptr() as *mut u8;
148 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
149
150 if mem::size_of::<$t>() >= 2 {
152 while n >= 10000 {
154 let rem = (n % 10000) as isize;
155 n /= 10000;
156
157 let d1 = (rem / 100) << 1;
158 let d2 = (rem % 100) << 1;
159 curr -= 4;
160 unsafe {
161 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
162 ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
163 }
164 }
165 }
166
167 let mut n = n as isize; if n >= 100 {
172 let d1 = (n % 100) << 1;
173 n /= 100;
174 curr -= 2;
175 unsafe {
176 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
177 }
178 }
179
180 if n < 10 {
182 curr -= 1;
183 unsafe {
184 *buf_ptr.offset(curr) = (n as u8) + b'0';
185 }
186 } else {
187 let d1 = n << 1;
188 curr -= 2;
189 unsafe {
190 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
191 }
192 }
193
194 if !is_nonnegative {
195 curr -= 1;
196 unsafe {
197 *buf_ptr.offset(curr) = b'-';
198 }
199 }
200
201 let len = buf.len() - curr as usize;
202 let bytes = unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) };
203 unsafe { str::from_utf8_unchecked(bytes) }
204 }
205 }
206 )*};
207}
208
209const I8_MAX_LEN: usize = 4;
210const U8_MAX_LEN: usize = 3;
211const I16_MAX_LEN: usize = 6;
212const U16_MAX_LEN: usize = 5;
213const I32_MAX_LEN: usize = 11;
214const U32_MAX_LEN: usize = 10;
215const I64_MAX_LEN: usize = 20;
216const U64_MAX_LEN: usize = 20;
217
218impl_Integer!(
219 I8_MAX_LEN => i8,
220 U8_MAX_LEN => u8,
221 I16_MAX_LEN => i16,
222 U16_MAX_LEN => u16,
223 I32_MAX_LEN => i32,
224 U32_MAX_LEN => u32
225 as u32);
226
227impl_Integer!(I64_MAX_LEN => i64, U64_MAX_LEN => u64 as u64);
228
229#[cfg(target_pointer_width = "16")]
230impl_Integer!(I16_MAX_LEN => isize, U16_MAX_LEN => usize as u16);
231
232#[cfg(target_pointer_width = "32")]
233impl_Integer!(I32_MAX_LEN => isize, U32_MAX_LEN => usize as u32);
234
235#[cfg(target_pointer_width = "64")]
236impl_Integer!(I64_MAX_LEN => isize, U64_MAX_LEN => usize as u64);
237
238macro_rules! impl_Integer128 {
239 ($($max_len:expr => $t:ident),*) => {$(
240 impl Integer for $t {}
241
242 impl private::Sealed for $t {
243 type Buffer = [MaybeUninit<u8>; $max_len];
244
245 #[allow(unused_comparisons)]
246 #[inline]
247 #[cfg_attr(feature = "no-panic", no_panic)]
248 fn write(self, buf: &mut [MaybeUninit<u8>; $max_len]) -> &str {
249 let is_nonnegative = self >= 0;
250 let n = if is_nonnegative {
251 self as u128
252 } else {
253 (!(self as u128)).wrapping_add(1)
255 };
256 let mut curr = buf.len() as isize;
257 let buf_ptr = buf.as_mut_ptr() as *mut u8;
258
259 let (n, rem) = udiv128::udivmod_1e19(n);
261 let buf1 = unsafe { buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit<u8>; U64_MAX_LEN] };
262 curr -= rem.write(unsafe { &mut *buf1 }).len() as isize;
263
264 if n != 0 {
265 let target = buf.len() as isize - 19;
267 unsafe {
268 ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
269 }
270 curr = target;
271
272 let (n, rem) = udiv128::udivmod_1e19(n);
274 let buf2 = unsafe { buf_ptr.offset(curr - U64_MAX_LEN as isize) as *mut [MaybeUninit<u8>; U64_MAX_LEN] };
275 curr -= rem.write(unsafe { &mut *buf2 }).len() as isize;
276
277 if n != 0 {
278 let target = buf.len() as isize - 38;
280 unsafe {
281 ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize);
282 }
283 curr = target;
284
285 curr -= 1;
288 unsafe {
289 *buf_ptr.offset(curr) = (n as u8) + b'0';
290 }
291 }
292 }
293
294 if !is_nonnegative {
295 curr -= 1;
296 unsafe {
297 *buf_ptr.offset(curr) = b'-';
298 }
299 }
300
301 let len = buf.len() - curr as usize;
302 let bytes = unsafe { slice::from_raw_parts(buf_ptr.offset(curr), len) };
303 unsafe { str::from_utf8_unchecked(bytes) }
304 }
305 }
306 )*};
307}
308
309const U128_MAX_LEN: usize = 39;
310const I128_MAX_LEN: usize = 40;
311
312impl_Integer128!(I128_MAX_LEN => i128, U128_MAX_LEN => u128);