1use core::{
7 mem,
8 num,
9 ptr,
10};
11
12use super::traits::IntoRepr;
13use super::Repr;
14use crate::{
15 ToCompactStringError,
16 UnwrapWithMsg,
17};
18
19const DEC_DIGITS_LUT: &[u8] = b"\
20 0001020304050607080910111213141516171819\
21 2021222324252627282930313233343536373839\
22 4041424344454647484950515253545556575859\
23 6061626364656667686970717273747576777879\
24 8081828384858687888990919293949596979899";
25
26macro_rules! impl_IntoRepr {
28 ($t:ident, $conv_ty:ident) => {
29 impl IntoRepr for $t {
30 fn into_repr(self) -> Result<Repr, ToCompactStringError> {
31 let num_digits = NumChars::num_chars(self);
35 let mut repr = Repr::with_capacity(num_digits).unwrap_with_msg();
36
37 #[allow(unused_comparisons)]
38 let is_nonnegative = self >= 0;
39 let mut n = if is_nonnegative {
40 self as $conv_ty
41 } else {
42 (!(self as $conv_ty)).wrapping_add(1)
44 };
45 let mut curr = num_digits as isize;
46
47 unsafe { repr.set_len(num_digits) };
49 let buf_ptr = unsafe { repr.as_mut_buf().as_mut_ptr() };
51
52 let lut_ptr = DEC_DIGITS_LUT.as_ptr();
53
54 unsafe {
55 if mem::size_of::<$t>() >= 2 {
57 while n >= 10000 {
59 let rem = (n % 10000) as isize;
60 n /= 10000;
61
62 let d1 = (rem / 100) << 1;
63 let d2 = (rem % 100) << 1;
64 curr -= 4;
65 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
66 ptr::copy_nonoverlapping(
67 lut_ptr.offset(d2),
68 buf_ptr.offset(curr + 2),
69 2,
70 );
71 }
72 }
73
74 let mut n = n as isize; if n >= 100 {
79 let d1 = (n % 100) << 1;
80 n /= 100;
81 curr -= 2;
82 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
83 }
84
85 if n < 10 {
87 curr -= 1;
88 *buf_ptr.offset(curr) = (n as u8) + b'0';
89 } else {
90 let d1 = n << 1;
91 curr -= 2;
92 ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
93 }
94
95 if !is_nonnegative {
96 curr -= 1;
97 *buf_ptr.offset(curr) = b'-';
98 }
99 }
100
101 debug_assert_eq!(curr, 0);
103
104 Ok(repr)
105 }
106 }
107 };
108}
109
110impl_IntoRepr!(u8, u32);
111impl_IntoRepr!(i8, u32);
112impl_IntoRepr!(u16, u32);
113impl_IntoRepr!(i16, u32);
114impl_IntoRepr!(u32, u32);
115impl_IntoRepr!(i32, u32);
116impl_IntoRepr!(u64, u64);
117impl_IntoRepr!(i64, u64);
118
119#[cfg(target_pointer_width = "32")]
120impl_IntoRepr!(usize, u32);
121#[cfg(target_pointer_width = "32")]
122impl_IntoRepr!(isize, u32);
123
124#[cfg(target_pointer_width = "64")]
125impl_IntoRepr!(usize, u64);
126#[cfg(target_pointer_width = "64")]
127impl_IntoRepr!(isize, u64);
128
129impl IntoRepr for u128 {
133 #[inline]
134 fn into_repr(self) -> Result<Repr, ToCompactStringError> {
135 let mut buffer = itoa::Buffer::new();
136 Ok(Repr::new(buffer.format(self))?)
137 }
138}
139
140impl IntoRepr for i128 {
141 #[inline]
142 fn into_repr(self) -> Result<Repr, ToCompactStringError> {
143 let mut buffer = itoa::Buffer::new();
144 Ok(Repr::new(buffer.format(self))?)
145 }
146}
147
148macro_rules! impl_NonZero_IntoRepr {
150 ($t:path) => {
151 impl IntoRepr for $t {
152 #[inline]
153 fn into_repr(self) -> Result<Repr, ToCompactStringError> {
154 self.get().into_repr()
155 }
156 }
157 };
158}
159
160impl_NonZero_IntoRepr!(num::NonZeroU8);
161impl_NonZero_IntoRepr!(num::NonZeroI8);
162impl_NonZero_IntoRepr!(num::NonZeroU16);
163impl_NonZero_IntoRepr!(num::NonZeroI16);
164impl_NonZero_IntoRepr!(num::NonZeroU32);
165impl_NonZero_IntoRepr!(num::NonZeroI32);
166impl_NonZero_IntoRepr!(num::NonZeroU64);
167impl_NonZero_IntoRepr!(num::NonZeroI64);
168impl_NonZero_IntoRepr!(num::NonZeroUsize);
169impl_NonZero_IntoRepr!(num::NonZeroIsize);
170impl_NonZero_IntoRepr!(num::NonZeroU128);
171impl_NonZero_IntoRepr!(num::NonZeroI128);
172
173trait NumChars {
215 fn num_chars(val: Self) -> usize;
216}
217
218impl NumChars for u8 {
219 #[inline(always)]
220 fn num_chars(val: u8) -> usize {
221 match val {
222 u8::MIN..=9 => 1,
223 10..=99 => 2,
224 100..=u8::MAX => 3,
225 }
226 }
227}
228
229impl NumChars for i8 {
230 #[inline(always)]
231 fn num_chars(val: i8) -> usize {
232 match val {
233 i8::MIN..=-100 => 4,
234 -99..=-10 => 3,
235 -9..=-1 => 2,
236 0..=9 => 1,
237 10..=99 => 2,
238 100..=i8::MAX => 3,
239 }
240 }
241}
242
243impl NumChars for u16 {
244 #[inline(always)]
245 fn num_chars(val: u16) -> usize {
246 match val {
247 u16::MIN..=9 => 1,
248 10..=99 => 2,
249 100..=999 => 3,
250 1000..=9999 => 4,
251 10000..=u16::MAX => 5,
252 }
253 }
254}
255
256impl NumChars for i16 {
257 #[inline(always)]
258 fn num_chars(val: i16) -> usize {
259 match val {
260 i16::MIN..=-10000 => 6,
261 -9999..=-1000 => 5,
262 -999..=-100 => 4,
263 -99..=-10 => 3,
264 -9..=-1 => 2,
265 0..=9 => 1,
266 10..=99 => 2,
267 100..=999 => 3,
268 1000..=9999 => 4,
269 10000..=i16::MAX => 5,
270 }
271 }
272}
273
274impl NumChars for u32 {
275 #[inline(always)]
276 fn num_chars(val: u32) -> usize {
277 match val {
278 u32::MIN..=9 => 1,
279 10..=99 => 2,
280 100..=999 => 3,
281 1000..=9999 => 4,
282 10000..=99999 => 5,
283 100000..=999999 => 6,
284 1000000..=9999999 => 7,
285 10000000..=99999999 => 8,
286 100000000..=999999999 => 9,
287 1000000000..=u32::MAX => 10,
288 }
289 }
290}
291
292impl NumChars for i32 {
293 #[inline(always)]
294 fn num_chars(val: i32) -> usize {
295 match val {
296 i32::MIN..=-1000000000 => 11,
297 -999999999..=-100000000 => 10,
298 -99999999..=-10000000 => 9,
299 -9999999..=-1000000 => 8,
300 -999999..=-100000 => 7,
301 -99999..=-10000 => 6,
302 -9999..=-1000 => 5,
303 -999..=-100 => 4,
304 -99..=-10 => 3,
305 -9..=-1 => 2,
306 0..=9 => 1,
307 10..=99 => 2,
308 100..=999 => 3,
309 1000..=9999 => 4,
310 10000..=99999 => 5,
311 100000..=999999 => 6,
312 1000000..=9999999 => 7,
313 10000000..=99999999 => 8,
314 100000000..=999999999 => 9,
315 1000000000..=i32::MAX => 10,
316 }
317 }
318}
319
320impl NumChars for u64 {
321 #[inline(always)]
322 fn num_chars(val: u64) -> usize {
323 match val {
324 u64::MIN..=9 => 1,
325 10..=99 => 2,
326 100..=999 => 3,
327 1000..=9999 => 4,
328 10000..=99999 => 5,
329 100000..=999999 => 6,
330 1000000..=9999999 => 7,
331 10000000..=99999999 => 8,
332 100000000..=999999999 => 9,
333 1000000000..=9999999999 => 10,
334 10000000000..=99999999999 => 11,
335 100000000000..=999999999999 => 12,
336 1000000000000..=9999999999999 => 13,
337 10000000000000..=99999999999999 => 14,
338 100000000000000..=999999999999999 => 15,
339 1000000000000000..=9999999999999999 => 16,
340 10000000000000000..=99999999999999999 => 17,
341 100000000000000000..=999999999999999999 => 18,
342 1000000000000000000..=9999999999999999999 => 19,
343 10000000000000000000..=u64::MAX => 20,
344 }
345 }
346}
347
348impl NumChars for i64 {
349 #[inline(always)]
350 fn num_chars(val: i64) -> usize {
351 match val {
352 i64::MIN..=-1000000000000000000 => 20,
353 -999999999999999999..=-100000000000000000 => 19,
354 -99999999999999999..=-10000000000000000 => 18,
355 -9999999999999999..=-1000000000000000 => 17,
356 -999999999999999..=-100000000000000 => 16,
357 -99999999999999..=-10000000000000 => 15,
358 -9999999999999..=-1000000000000 => 14,
359 -999999999999..=-100000000000 => 13,
360 -99999999999..=-10000000000 => 12,
361 -9999999999..=-1000000000 => 11,
362 -999999999..=-100000000 => 10,
363 -99999999..=-10000000 => 9,
364 -9999999..=-1000000 => 8,
365 -999999..=-100000 => 7,
366 -99999..=-10000 => 6,
367 -9999..=-1000 => 5,
368 -999..=-100 => 4,
369 -99..=-10 => 3,
370 -9..=-1 => 2,
371 0..=9 => 1,
372 10..=99 => 2,
373 100..=999 => 3,
374 1000..=9999 => 4,
375 10000..=99999 => 5,
376 100000..=999999 => 6,
377 1000000..=9999999 => 7,
378 10000000..=99999999 => 8,
379 100000000..=999999999 => 9,
380 1000000000..=9999999999 => 10,
381 10000000000..=99999999999 => 11,
382 100000000000..=999999999999 => 12,
383 1000000000000..=9999999999999 => 13,
384 10000000000000..=99999999999999 => 14,
385 100000000000000..=999999999999999 => 15,
386 1000000000000000..=9999999999999999 => 16,
387 10000000000000000..=99999999999999999 => 17,
388 100000000000000000..=999999999999999999 => 18,
389 1000000000000000000..=i64::MAX => 19,
390 }
391 }
392}
393
394impl NumChars for usize {
395 fn num_chars(val: usize) -> usize {
396 #[cfg(target_pointer_width = "32")]
397 {
398 u32::num_chars(val as u32)
399 }
400
401 #[cfg(target_pointer_width = "64")]
402 {
403 u64::num_chars(val as u64)
404 }
405 }
406}
407
408impl NumChars for isize {
409 fn num_chars(val: isize) -> usize {
410 #[cfg(target_pointer_width = "32")]
411 {
412 i32::num_chars(val as i32)
413 }
414
415 #[cfg(target_pointer_width = "64")]
416 {
417 i64::num_chars(val as i64)
418 }
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use alloc::string::ToString;
425
426 use super::IntoRepr;
427
428 #[test]
429 fn test_from_u8_sanity() {
430 let vals = [u8::MIN, u8::MIN + 1, 0, 42, u8::MAX - 1, u8::MAX];
431
432 for x in &vals {
433 let repr = u8::into_repr(*x).unwrap();
434 assert_eq!(repr.as_str(), x.to_string());
435 }
436 }
437
438 #[test]
439 fn test_from_i8_sanity() {
440 let vals = [i8::MIN, i8::MIN + 1, 0, 42, i8::MAX - 1, i8::MAX];
441
442 for x in &vals {
443 let repr = i8::into_repr(*x).unwrap();
444 assert_eq!(repr.as_str(), x.to_string());
445 }
446 }
447
448 #[test]
449 fn test_from_u16_sanity() {
450 let vals = [u16::MIN, u16::MIN + 1, 0, 42, u16::MAX - 1, u16::MAX];
451
452 for x in &vals {
453 let repr = u16::into_repr(*x).unwrap();
454 assert_eq!(repr.as_str(), x.to_string());
455 }
456 }
457
458 #[test]
459 fn test_from_i16_sanity() {
460 let vals = [i16::MIN, i16::MIN + 1, 0, 42, i16::MAX - 1, i16::MAX];
461
462 for x in &vals {
463 let repr = i16::into_repr(*x).unwrap();
464 assert_eq!(repr.as_str(), x.to_string());
465 }
466 }
467
468 #[test]
469 fn test_from_u32_sanity() {
470 let vals = [u32::MIN, u32::MIN + 1, 0, 42, u32::MAX - 1, u32::MAX];
471
472 for x in &vals {
473 let repr = u32::into_repr(*x).unwrap();
474 assert_eq!(repr.as_str(), x.to_string());
475 }
476 }
477
478 #[test]
479 fn test_from_i32_sanity() {
480 let vals = [i32::MIN, i32::MIN + 1, 0, 42, i32::MAX - 1, i32::MAX];
481
482 for x in &vals {
483 let repr = i32::into_repr(*x).unwrap();
484 assert_eq!(repr.as_str(), x.to_string());
485 }
486 }
487
488 #[test]
489 fn test_from_u64_sanity() {
490 let vals = [u64::MIN, u64::MIN + 1, 0, 42, u64::MAX - 1, u64::MAX];
491
492 for x in &vals {
493 let repr = u64::into_repr(*x).unwrap();
494 assert_eq!(repr.as_str(), x.to_string());
495 }
496 }
497
498 #[test]
499 fn test_from_i64_sanity() {
500 let vals = [i64::MIN, i64::MIN + 1, 0, 42, i64::MAX - 1, i64::MAX];
501
502 for x in &vals {
503 let repr = i64::into_repr(*x).unwrap();
504 assert_eq!(repr.as_str(), x.to_string());
505 }
506 }
507
508 #[test]
509 fn test_from_usize_sanity() {
510 let vals = [
511 usize::MIN,
512 usize::MIN + 1,
513 0,
514 42,
515 usize::MAX - 1,
516 usize::MAX,
517 ];
518
519 for x in &vals {
520 let repr = usize::into_repr(*x).unwrap();
521 assert_eq!(repr.as_str(), x.to_string());
522 }
523 }
524
525 #[test]
526 fn test_from_isize_sanity() {
527 let vals = [
528 isize::MIN,
529 isize::MIN + 1,
530 0,
531 42,
532 isize::MAX - 1,
533 isize::MAX,
534 ];
535
536 for x in &vals {
537 let repr = isize::into_repr(*x).unwrap();
538 assert_eq!(repr.as_str(), x.to_string());
539 }
540 }
541
542 #[test]
543 fn test_from_u128_sanity() {
544 let vals = [u128::MIN, u128::MIN + 1, 0, 42, u128::MAX - 1, u128::MAX];
545
546 for x in &vals {
547 let repr = u128::into_repr(*x).unwrap();
548 assert_eq!(repr.as_str(), x.to_string());
549 }
550 }
551
552 #[test]
553 fn test_from_i128_sanity() {
554 let vals = [i128::MIN, i128::MIN + 1, 0, 42, i128::MAX - 1, i128::MAX];
555
556 for x in &vals {
557 let repr = i128::into_repr(*x).unwrap();
558 assert_eq!(repr.as_str(), x.to_string());
559 }
560 }
561}