lexical_write_integer/
api.rs

1//! Implements the algorithm in terms of the lexical API.
2
3#![doc(hidden)]
4
5use crate::options::Options;
6use crate::write::WriteInteger;
7use lexical_util::assert::{assert_buffer, debug_assert_buffer};
8use lexical_util::format::{NumberFormat, STANDARD};
9use lexical_util::num::SignedInteger;
10use lexical_util::{to_lexical, to_lexical_with_options};
11
12// UNSIGNED
13
14/// Callback for unsigned integer formatter.
15///
16/// # Safety
17///
18/// Safe as long as the buffer can hold `FORMATTED_SIZE` elements
19/// (or `FORMATTED_SIZE_DECIMAL` for decimal).
20#[inline]
21unsafe fn unsigned<Narrow, Wide, const FORMAT: u128>(value: Narrow, buffer: &mut [u8]) -> usize
22where
23    Narrow: WriteInteger,
24    Wide: WriteInteger,
25{
26    let format = NumberFormat::<FORMAT> {};
27    if cfg!(feature = "format") && format.required_mantissa_sign() {
28        // SAFETY: safe as long as there is at least `FORMATTED_SIZE` elements.
29        unsafe {
30            index_unchecked_mut!(buffer[0]) = b'+';
31            let buffer = &mut index_unchecked_mut!(buffer[1..]);
32            value.write_mantissa::<Wide, FORMAT>(buffer) + 1
33        }
34    } else {
35        // SAFETY: safe as long as there is at least `FORMATTED_SIZE` elements.
36        unsafe { value.write_mantissa::<Wide, FORMAT>(buffer) }
37    }
38}
39
40// SIGNED
41
42/// Callback for signed integer formatter.
43///
44/// # Safety
45///
46/// Safe as long as the buffer can hold `FORMATTED_SIZE` elements
47/// (or `FORMATTED_SIZE_DECIMAL` for decimal).
48#[inline]
49unsafe fn signed<Narrow, Wide, Unsigned, const FORMAT: u128>(
50    value: Narrow,
51    buffer: &mut [u8],
52) -> usize
53where
54    Narrow: SignedInteger,
55    Wide: SignedInteger,
56    Unsigned: WriteInteger,
57{
58    let format = NumberFormat::<FORMAT> {};
59    if value < Narrow::ZERO {
60        // Need to cast the value to the same size as unsigned type, since if
61        // the value is **exactly** `Narrow::MIN`, and it it is then cast
62        // as the wrapping negative as the unsigned value, a wider type
63        // will have a very different value.
64        let value = Wide::as_cast(value);
65        let unsigned = Unsigned::as_cast(value.wrapping_neg());
66        // SAFETY: safe as long as there is at least `FORMATTED_SIZE` elements.
67        unsafe {
68            index_unchecked_mut!(buffer[0]) = b'-';
69            let buffer = &mut index_unchecked_mut!(buffer[1..]);
70            unsigned.write_mantissa::<Unsigned, FORMAT>(buffer) + 1
71        }
72    } else if cfg!(feature = "format") && format.required_mantissa_sign() {
73        let unsigned = Unsigned::as_cast(value);
74        // SAFETY: safe as long as there is at least `FORMATTED_SIZE` elements.
75        unsafe {
76            index_unchecked_mut!(buffer[0]) = b'+';
77            let buffer = &mut index_unchecked_mut!(buffer[1..]);
78            unsigned.write_mantissa::<Unsigned, FORMAT>(buffer) + 1
79        }
80    } else {
81        let unsigned = Unsigned::as_cast(value);
82        // SAFETY: safe as long as there is at least `FORMATTED_SIZE` elements.
83        unsafe { unsigned.write_mantissa::<Unsigned, FORMAT>(buffer) }
84    }
85}
86
87// API
88
89// Implement ToLexical for numeric type.
90macro_rules! unsigned_to_lexical {
91    ($($narrow:tt $wide:tt $(, #[$meta:meta])? ; )*) => ($(
92        impl ToLexical for $narrow {
93            $(#[$meta:meta])?
94            unsafe fn to_lexical_unchecked<'a>(self, bytes: &'a mut [u8])
95                -> &'a mut [u8]
96            {
97                debug_assert_buffer::<$narrow>(10, bytes.len());
98                // SAFETY: safe if `bytes.len() > Self::FORMATTED_SIZE_DECIMAL`.
99                unsafe {
100                    let len = unsigned::<$narrow, $wide, { STANDARD }>(self, bytes);
101                    &mut index_unchecked_mut!(bytes[..len])
102                }
103            }
104
105            $(#[$meta:meta])?
106            fn to_lexical<'a>(self, bytes: &'a mut [u8])
107                -> &'a mut [u8]
108            {
109                assert_buffer::<$narrow>(10, bytes.len());
110                // SAFETY: safe since `bytes.len() > Self::FORMATTED_SIZE_DECIMAL`.
111                unsafe { self.to_lexical_unchecked(bytes) }
112            }
113        }
114
115        impl ToLexicalWithOptions for $narrow {
116            type Options = Options;
117
118            $(#[$meta:meta])?
119            unsafe fn to_lexical_with_options_unchecked<'a, const FORMAT: u128>(
120                self,
121                bytes: &'a mut [u8],
122                _: &Self::Options,
123            ) -> &'a mut [u8]
124            {
125                debug_assert_buffer::<$narrow>(NumberFormat::<{ FORMAT }>::RADIX, bytes.len());
126                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
127                // SAFETY: safe if `bytes.len() > Self::FORMATTED_SIZE`.
128                unsafe {
129                    let len = unsigned::<$narrow, $wide, FORMAT>(self, bytes);
130                    &mut index_unchecked_mut!(bytes[..len])
131                }
132            }
133
134            $(#[$meta:meta])?
135            fn to_lexical_with_options<'a, const FORMAT: u128>(
136                self,
137                bytes: &'a mut [u8],
138                options: &Self::Options,
139            ) -> &'a mut [u8]
140            {
141                assert_buffer::<$narrow>(NumberFormat::<{ FORMAT }>::RADIX, bytes.len());
142                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
143                // SAFETY: safe since `bytes.len() > Self::FORMATTED_SIZE`.
144                unsafe { self.to_lexical_with_options_unchecked::<FORMAT>(bytes, options) }
145            }
146        }
147    )*)
148}
149
150to_lexical! {}
151to_lexical_with_options! {}
152unsigned_to_lexical! {
153    u8 u32 ;
154    u16 u32 ;
155    u32 u32 ;
156    u64 u64 ;
157    u128 u128 ;
158}
159
160#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
161unsigned_to_lexical! { usize u32 ; }
162
163#[cfg(target_pointer_width = "64")]
164unsigned_to_lexical! { usize u64 ; }
165
166// Implement ToLexical for numeric type.
167macro_rules! signed_to_lexical {
168    ($($narrow:tt $wide:tt $unsigned:tt $(, #[$meta:meta])? ; )*) => ($(
169        impl ToLexical for $narrow {
170            $(#[$meta:meta])?
171            unsafe fn to_lexical_unchecked<'a>(self, bytes: &'a mut [u8])
172                -> &'a mut [u8]
173            {
174                debug_assert_buffer::<$narrow>(10, bytes.len());
175                // SAFETY: safe if `bytes.len() > Self::FORMATTED_SIZE_DECIMAL`.
176                unsafe {
177                    let len = signed::<$narrow, $wide, $unsigned, { STANDARD }>(self, bytes);
178                    &mut index_unchecked_mut!(bytes[..len])
179                }
180            }
181
182            $(#[$meta:meta])?
183            fn to_lexical<'a>(self, bytes: &'a mut [u8])
184                -> &'a mut [u8]
185            {
186                assert_buffer::<$narrow>(10, bytes.len());
187                // SAFETY: safe since `bytes.len() > Self::FORMATTED_SIZE_DECIMAL`.
188                unsafe { self.to_lexical_unchecked(bytes) }
189            }
190        }
191
192        impl ToLexicalWithOptions for $narrow {
193            type Options = Options;
194
195            $(#[$meta:meta])?
196            unsafe fn to_lexical_with_options_unchecked<'a, const FORMAT: u128>(
197                self,
198                bytes: &'a mut [u8],
199                _: &Self::Options,
200            ) -> &'a mut [u8]
201            {
202                debug_assert_buffer::<$narrow>(NumberFormat::<{ FORMAT }>::RADIX, bytes.len());
203                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
204                // SAFETY: safe if `bytes.len() > Self::FORMATTED_SIZE`.
205                unsafe {
206                    let len = signed::<$narrow, $wide, $unsigned, FORMAT>(self, bytes);
207                    &mut index_unchecked_mut!(bytes[..len])
208                }
209            }
210
211            $(#[$meta:meta])?
212            fn to_lexical_with_options<'a, const FORMAT: u128>(
213                self,
214                bytes: &'a mut [u8],
215                options: &Self::Options,
216            ) -> &'a mut [u8]
217            {
218                assert_buffer::<$narrow>(NumberFormat::<{ FORMAT }>::RADIX, bytes.len());
219                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
220                // SAFETY: safe since `bytes.len() > Self::FORMATTED_SIZE`.
221                unsafe { self.to_lexical_with_options_unchecked::<FORMAT>(bytes, options) }
222            }
223        }
224    )*)
225}
226
227signed_to_lexical! {
228    i8 i32 u32 ;
229    i16 i32 u32 ;
230    i32 i32 u32 ;
231    i64 i64 u64 ;
232    i128 i128 u128 ;
233}
234
235#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
236signed_to_lexical! { isize i32 u32 ; }
237
238#[cfg(target_pointer_width = "64")]
239signed_to_lexical! { isize i64 u64 ; }