lean_string/repr/
num_to_repr.rs

1use super::*;
2use core::num::NonZero;
3
4pub(super) trait NumToRepr {
5    fn into_repr(self) -> Result<Repr, ReserveError>;
6}
7
8impl NumToRepr for f32 {
9    #[inline]
10    fn into_repr(self) -> Result<Repr, ReserveError> {
11        Repr::from_str(ryu::Buffer::new().format(self))
12    }
13}
14
15impl NumToRepr for f64 {
16    #[inline]
17    fn into_repr(self) -> Result<Repr, ReserveError> {
18        Repr::from_str(ryu::Buffer::new().format(self))
19    }
20}
21
22impl NumToRepr for u128 {
23    #[inline]
24    fn into_repr(self) -> Result<Repr, ReserveError> {
25        Repr::from_str(itoa::Buffer::new().format(self))
26    }
27}
28
29impl NumToRepr for i128 {
30    #[inline]
31    fn into_repr(self) -> Result<Repr, ReserveError> {
32        Repr::from_str(itoa::Buffer::new().format(self))
33    }
34}
35
36// NOTE:
37// Following integer impl for `IntoRepr` are adapted from `core::fmt::Display::fmt` for integers.
38// https://github.com/rust-lang/rust/blob/a2bcfae5c5d05dd7806a79194cda39108ed6cd7d/library/core/src/fmt/num.rs#L195-L305
39
40const DEC_DIGITS_LUT: &[u8; 200] = b"\
41      0001020304050607080910111213141516171819\
42      2021222324252627282930313233343536373839\
43      4041424344454647484950515253545556575859\
44      6061626364656667686970717273747576777879\
45      8081828384858687888990919293949596979899";
46
47macro_rules! impl_NumToRepr_for_integers {
48    ($($t:ty),* ; as $u:ty) => {$(
49        impl NumToRepr for $t {
50            fn into_repr(self) -> Result<Repr, ReserveError> {
51                let digits_count = DigitCount::digit_count(self);
52
53                #[allow(unused_comparisons)]
54                let is_nonnegative = self >= 0;
55                let mut n = if is_nonnegative {
56                    self as $u
57                } else {
58                    // we use add 1 to it's 2's complement because we can't use -self for unsigned
59                    // integers.
60                    (!(self as $u)).wrapping_add(1)
61                };
62
63                let mut repr = Repr::with_capacity(digits_count)?;
64
65                // SAFETY: Since we have just created `repr` with the capacity, it is not
66                // StaticBuffer and it is unique if it is HeapBuffer.
67                let buf_ptr = unsafe { repr.as_slice_mut().as_mut_ptr() };
68
69                let lut_ptr = DEC_DIGITS_LUT.as_ptr();
70                let mut curr = digits_count;
71
72                // SAFETY:
73                // - Since `d1` and `d2` are always less than or equal to `198`, we can copy from
74                //   `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`.
75                // - Since `n` is always non-negative, this means that `curr > 0` so
76                //   `buf_ptr[curr..curr + 1]` is safe to access.
77                unsafe {
78                    // need at least 16 bits for the 4-characters-at-a-time to work.
79                    // This block will be removed for smaller types at compile time and in the
80                    // worst case, it will prevent to have the `10000` literal to overflow for `i8
81                    // and `u8`.
82                    if size_of::<$t>() >= 2 {
83                        // eagerly decode 4 characters at a time
84                        while n >= 10000 {
85                            let rem = (n % 10000) as usize;
86                            n /= 10000;
87
88                            let d1 = (rem / 100) << 1;
89                            let d2 = (rem % 100) << 1;
90                            curr -= 4;
91
92                            // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since
93                            // otherwise `curr < 0`. But then `n` was originally at least `10000^10`
94                            // which is `10^40 > 2^128 > n`.
95                            ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
96                            ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2);
97                        }
98                    }
99
100                    // if we reach here numbers are <= 9999, so at most 4 chars long
101                    let mut n = n as usize;
102
103                    // decode 2 more chars, if > 2 chars
104                    if n >= 100 {
105                        let d1 = (n % 100) << 1;
106                        n /= 100;
107                        curr -= 2;
108                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
109                    }
110
111                    // if we reach here numbers are <= 100, so at most 2 chars long
112                    // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough.
113                    // decode last 1 or 2 chars
114                    if n < 10 {
115                        curr -= 1;
116                        *buf_ptr.add(curr) = (n as u8) + b'0';
117                    } else {
118                        let d1 = n << 1;
119                        curr -= 2;
120                        ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2);
121                    }
122
123                    if !is_nonnegative {
124                        curr -= 1;
125                        *buf_ptr.add(curr) = b'-';
126                    }
127
128                    repr.set_len(digits_count);
129                }
130
131                debug_assert_eq!(curr, 0);
132
133                Ok(repr)
134            }
135        }
136    )*};
137}
138
139#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))]
140impl_NumToRepr_for_integers!(
141    i8, u8, i16, u16, i32, u32, isize, usize;
142    as u64
143);
144
145#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))]
146impl_NumToRepr_for_integers!(
147    i8, u8, i16, u16, i32, u32, isize, usize;
148    as u32
149);
150
151impl_NumToRepr_for_integers!(
152    i64, u64;
153    as u64
154);
155
156// NOTE: ZeroablePrimitive is unstable
157macro_rules! impl_IntoRepr_for_nonzero_integers {
158    ($($itype:ty),* $(,)?) => {$(
159        impl NumToRepr for $itype {
160            #[inline]
161            fn into_repr(self) -> Result<Repr, ReserveError> {
162                self.get().into_repr()
163            }
164        }
165    )*};
166}
167impl_IntoRepr_for_nonzero_integers!(
168    NonZero<i8>,
169    NonZero<u8>,
170    NonZero<i16>,
171    NonZero<u16>,
172    NonZero<i32>,
173    NonZero<u32>,
174    NonZero<i64>,
175    NonZero<u64>,
176    NonZero<i128>,
177    NonZero<u128>,
178    NonZero<isize>,
179    NonZero<usize>,
180);
181
182trait DigitCount {
183    fn digit_count(self) -> usize;
184}
185
186impl DigitCount for u8 {
187    #[inline(always)]
188    fn digit_count(self) -> usize {
189        match self {
190            u8::MIN..=9 => 1,
191            10..=99 => 2,
192            100..=u8::MAX => 3,
193        }
194    }
195}
196
197impl DigitCount for i8 {
198    #[inline(always)]
199    fn digit_count(self) -> usize {
200        match self {
201            i8::MIN..=-100 => 4,
202            -99..=-10 => 3,
203            -9..=-1 => 2,
204            0..=9 => 1,
205            10..=99 => 2,
206            100..=i8::MAX => 3,
207        }
208    }
209}
210
211impl DigitCount for u16 {
212    #[inline(always)]
213    fn digit_count(self) -> usize {
214        match self {
215            u16::MIN..=9 => 1,
216            10..=99 => 2,
217            100..=999 => 3,
218            1000..=9999 => 4,
219            10000..=u16::MAX => 5,
220        }
221    }
222}
223
224impl DigitCount for i16 {
225    #[inline(always)]
226    fn digit_count(self) -> usize {
227        match self {
228            i16::MIN..=-10000 => 6,
229            -9999..=-1000 => 5,
230            -999..=-100 => 4,
231            -99..=-10 => 3,
232            -9..=-1 => 2,
233            0..=9 => 1,
234            10..=99 => 2,
235            100..=999 => 3,
236            1000..=9999 => 4,
237            10000..=i16::MAX => 5,
238        }
239    }
240}
241
242impl DigitCount for u32 {
243    #[inline(always)]
244    fn digit_count(self) -> usize {
245        match self {
246            u32::MIN..=9 => 1,
247            10..=99 => 2,
248            100..=999 => 3,
249            1000..=9999 => 4,
250            10000..=99999 => 5,
251            100000..=999999 => 6,
252            1000000..=9999999 => 7,
253            10000000..=99999999 => 8,
254            100000000..=999999999 => 9,
255            1000000000..=u32::MAX => 10,
256        }
257    }
258}
259
260impl DigitCount for i32 {
261    #[inline(always)]
262    fn digit_count(self) -> usize {
263        match self {
264            i32::MIN..=-1000000000 => 11,
265            -999999999..=-100000000 => 10,
266            -99999999..=-10000000 => 9,
267            -9999999..=-1000000 => 8,
268            -999999..=-100000 => 7,
269            -99999..=-10000 => 6,
270            -9999..=-1000 => 5,
271            -999..=-100 => 4,
272            -99..=-10 => 3,
273            -9..=-1 => 2,
274            0..=9 => 1,
275            10..=99 => 2,
276            100..=999 => 3,
277            1000..=9999 => 4,
278            10000..=99999 => 5,
279            100000..=999999 => 6,
280            1000000..=9999999 => 7,
281            10000000..=99999999 => 8,
282            100000000..=999999999 => 9,
283            1000000000..=i32::MAX => 10,
284        }
285    }
286}
287
288impl DigitCount for u64 {
289    #[inline(always)]
290    fn digit_count(self) -> usize {
291        match self {
292            u64::MIN..=9 => 1,
293            10..=99 => 2,
294            100..=999 => 3,
295            1000..=9999 => 4,
296            10000..=99999 => 5,
297            100000..=999999 => 6,
298            1000000..=9999999 => 7,
299            10000000..=99999999 => 8,
300            100000000..=999999999 => 9,
301            1000000000..=9999999999 => 10,
302            10000000000..=99999999999 => 11,
303            100000000000..=999999999999 => 12,
304            1000000000000..=9999999999999 => 13,
305            10000000000000..=99999999999999 => 14,
306            100000000000000..=999999999999999 => 15,
307            1000000000000000..=9999999999999999 => 16,
308            10000000000000000..=99999999999999999 => 17,
309            100000000000000000..=999999999999999999 => 18,
310            1000000000000000000..=9999999999999999999 => 19,
311            10000000000000000000..=u64::MAX => 20,
312        }
313    }
314}
315
316impl DigitCount for i64 {
317    #[inline(always)]
318    fn digit_count(self) -> usize {
319        match self {
320            i64::MIN..=-1000000000000000000 => 20,
321            -999999999999999999..=-100000000000000000 => 19,
322            -99999999999999999..=-10000000000000000 => 18,
323            -9999999999999999..=-1000000000000000 => 17,
324            -999999999999999..=-100000000000000 => 16,
325            -99999999999999..=-10000000000000 => 15,
326            -9999999999999..=-1000000000000 => 14,
327            -999999999999..=-100000000000 => 13,
328            -99999999999..=-10000000000 => 12,
329            -9999999999..=-1000000000 => 11,
330            -999999999..=-100000000 => 10,
331            -99999999..=-10000000 => 9,
332            -9999999..=-1000000 => 8,
333            -999999..=-100000 => 7,
334            -99999..=-10000 => 6,
335            -9999..=-1000 => 5,
336            -999..=-100 => 4,
337            -99..=-10 => 3,
338            -9..=-1 => 2,
339            0..=9 => 1,
340            10..=99 => 2,
341            100..=999 => 3,
342            1000..=9999 => 4,
343            10000..=99999 => 5,
344            100000..=999999 => 6,
345            1000000..=9999999 => 7,
346            10000000..=99999999 => 8,
347            100000000..=999999999 => 9,
348            1000000000..=9999999999 => 10,
349            10000000000..=99999999999 => 11,
350            100000000000..=999999999999 => 12,
351            1000000000000..=9999999999999 => 13,
352            10000000000000..=99999999999999 => 14,
353            100000000000000..=999999999999999 => 15,
354            1000000000000000..=9999999999999999 => 16,
355            10000000000000000..=99999999999999999 => 17,
356            100000000000000000..=999999999999999999 => 18,
357            1000000000000000000..=i64::MAX => 19,
358        }
359    }
360}
361
362#[cfg(target_pointer_width = "64")]
363impl DigitCount for usize {
364    #[inline(always)]
365    fn digit_count(self) -> usize {
366        DigitCount::digit_count(self as u64)
367    }
368}
369
370#[cfg(target_pointer_width = "32")]
371impl DigitCount for usize {
372    #[inline(always)]
373    fn digit_count(self) -> usize {
374        DigitCount::digit_count(self as u32)
375    }
376}
377
378#[cfg(target_pointer_width = "64")]
379impl DigitCount for isize {
380    #[inline(always)]
381    fn digit_count(self) -> usize {
382        DigitCount::digit_count(self as i64)
383    }
384}
385
386#[cfg(target_pointer_width = "32")]
387impl DigitCount for isize {
388    #[inline(always)]
389    fn digit_count(self) -> usize {
390        DigitCount::digit_count(self as i32)
391    }
392}