num_format/impls/
integers.rs

1#![allow(trivial_numeric_casts)]
2
3use core::marker::PhantomData;
4use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
5use core::ptr;
6
7use crate::buffer::Buffer;
8use crate::constants::*;
9use crate::format::Format;
10use crate::grouping::Grouping;
11use crate::sealed::Sealed;
12use crate::to_formatted_str::ToFormattedStr;
13
14// unsigned integers
15
16impl ToFormattedStr for u8 {
17    #[doc(hidden)]
18    #[inline(always)]
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
27macro_rules! impl_unsigned {
28    ($type:ty, $max_len:expr) => {
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
43impl_unsigned!(u16, U16_MAX_LEN);
44impl_unsigned!(u32, U32_MAX_LEN);
45impl_unsigned!(usize, USIZE_MAX_LEN);
46impl_unsigned!(u64, U64_MAX_LEN);
47impl_unsigned!(u128, U128_MAX_LEN);
48
49impl Sealed for u8 {}
50impl Sealed for u16 {}
51impl Sealed for u32 {}
52impl Sealed for usize {}
53impl Sealed for u64 {}
54impl Sealed for u128 {}
55
56// signed integers
57
58macro_rules! impl_signed {
59    ($type:ty, $max_len:expr) => {
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
87impl_signed!(i8, I8_MAX_LEN);
88impl_signed!(i16, I16_MAX_LEN);
89impl_signed!(i32, I32_MAX_LEN);
90impl_signed!(isize, ISIZE_MAX_LEN);
91impl_signed!(i64, I64_MAX_LEN);
92impl_signed!(i128, I128_MAX_LEN);
93
94impl Sealed for i8 {}
95impl Sealed for i16 {}
96impl Sealed for i32 {}
97impl Sealed for isize {}
98impl Sealed for i64 {}
99impl Sealed for i128 {}
100
101// non-zero unsigned integers
102
103impl ToFormattedStr for NonZeroU8 {
104    #[doc(hidden)]
105    #[inline(always)]
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
114macro_rules! impl_non_zero {
115    ($type:ty, $related_type:ty, $max_len:expr) => {
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
130impl_non_zero!(NonZeroU16, u16, U16_MAX_LEN);
131impl_non_zero!(NonZeroU32, u32, U32_MAX_LEN);
132impl_non_zero!(NonZeroUsize, usize, USIZE_MAX_LEN);
133impl_non_zero!(NonZeroU64, u64, U64_MAX_LEN);
134impl_non_zero!(NonZeroU128, u128, U128_MAX_LEN);
135
136impl Sealed for NonZeroU8 {}
137impl Sealed for NonZeroU16 {}
138impl Sealed for NonZeroU32 {}
139impl Sealed for NonZeroUsize {}
140impl Sealed for NonZeroU64 {}
141impl Sealed for NonZeroU128 {}
142
143// helper functions
144
145#[inline(always)]
146fn run_core_algorithm<F>(mut n: u128, buf: &mut Buffer, format: &F) -> usize
147where
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
201struct Sep<'a> {
202    ptr: *const u8,
203    len: usize,
204    pos: isize,
205    step: isize,
206    phantom: PhantomData<&'a ()>,
207}
208
209#[inline(always)]
210fn 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)]
228fn 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}