lexical_write_integer/
api.rs

1//! Implements the algorithm in terms of the lexical API.
2
3#![doc(hidden)]
4
5use lexical_util::format::{NumberFormat, STANDARD};
6use lexical_util::num::SignedInteger;
7use lexical_util::{to_lexical, to_lexical_with_options};
8
9use crate::options::Options;
10use crate::write::WriteInteger;
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#[cfg_attr(not(feature = "compact"), inline(always))]
21fn unsigned<T, const FORMAT: u128>(value: T, buffer: &mut [u8]) -> usize
22where
23    T: WriteInteger,
24{
25    let format = NumberFormat::<FORMAT> {};
26    if cfg!(feature = "format") && format.required_mantissa_sign() {
27        buffer[0] = b'+';
28        let buffer = &mut buffer[1..];
29        value.write_mantissa::<FORMAT>(buffer) + 1
30    } else {
31        value.write_mantissa::<FORMAT>(buffer)
32    }
33}
34
35// SIGNED
36
37/// Callback for signed integer formatter.
38///
39/// # Safety
40///
41/// Safe as long as the buffer can hold `FORMATTED_SIZE` elements
42/// (or `FORMATTED_SIZE_DECIMAL` for decimal).
43#[cfg_attr(not(feature = "compact"), inline(always))]
44fn signed<Signed, Unsigned, const FORMAT: u128>(value: Signed, buffer: &mut [u8]) -> usize
45where
46    Signed: SignedInteger,
47    Unsigned: WriteInteger,
48{
49    let format = NumberFormat::<FORMAT> {};
50    if value < Signed::ZERO {
51        // Need to cast the value to the same size as unsigned type, since if
52        // the value is **exactly** `Narrow::MIN`, and it it is then cast
53        // as the wrapping negative as the unsigned value, a wider type
54        // will have a very different value.
55        let unsigned = Unsigned::as_cast(value.wrapping_neg());
56        buffer[0] = b'-';
57        let buffer = &mut buffer[1..];
58        unsigned.write_mantissa_signed::<FORMAT>(buffer) + 1
59    } else if cfg!(feature = "format") && format.required_mantissa_sign() {
60        let unsigned = Unsigned::as_cast(value);
61        buffer[0] = b'+';
62        let buffer = &mut buffer[1..];
63        unsigned.write_mantissa_signed::<FORMAT>(buffer) + 1
64    } else {
65        let unsigned = Unsigned::as_cast(value);
66        unsigned.write_mantissa_signed::<FORMAT>(buffer)
67    }
68}
69
70// API
71
72// Implement `ToLexical` for numeric type.
73macro_rules! unsigned_to_lexical {
74    ($($t:tt)*) => ($(
75        impl ToLexical for $t {
76            #[cfg_attr(not(feature = "compact"), inline)]
77            fn to_lexical(self, bytes: &mut [u8])
78                -> &mut [u8]
79            {
80                let len = unsigned::<$t, { STANDARD }>(self, bytes);
81                &mut bytes[..len]
82            }
83        }
84
85        impl ToLexicalWithOptions for $t {
86            type Options = Options;
87
88            #[cfg_attr(not(feature = "compact"), inline)]
89            fn to_lexical_with_options<'a, const FORMAT: u128>(
90                self,
91                bytes: &'a mut [u8],
92                options: &Self::Options,
93            ) -> &'a mut [u8]
94            {
95                _ = options;
96                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
97                let len = unsigned::<$t, FORMAT>(self, bytes);
98                &mut bytes[..len]
99            }
100        }
101    )*)
102}
103
104to_lexical! {}
105to_lexical_with_options! {}
106unsigned_to_lexical! { u8 u16 u32 u64 u128 usize }
107
108// Implement `ToLexical` for numeric type.
109macro_rules! signed_to_lexical {
110    ($($signed:tt $unsigned:tt ; )*) => ($(
111        impl ToLexical for $signed {
112            #[cfg_attr(not(feature = "compact"), inline)]
113            fn to_lexical(self, bytes: &mut [u8])
114                -> &mut [u8]
115            {
116                let len = signed::<$signed, $unsigned, { STANDARD }>(self, bytes);
117                &mut bytes[..len]
118            }
119        }
120
121        impl ToLexicalWithOptions for $signed {
122            type Options = Options;
123            #[cfg_attr(not(feature = "compact"), inline)]
124            fn to_lexical_with_options<'a, const FORMAT: u128>(
125                self,
126                bytes: &'a mut [u8],
127                options: &Self::Options,
128            ) -> &'a mut [u8]
129            {
130                _ = options;
131                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
132                let len = signed::<$signed, $unsigned, FORMAT>(self, bytes);
133                &mut bytes[..len]
134            }
135        }
136    )*)
137}
138
139signed_to_lexical! {
140    i8 u8 ;
141    i16 u16 ;
142    i32 u32 ;
143    i64 u64 ;
144    i128 u128 ;
145}
146
147#[cfg(target_pointer_width = "16")]
148signed_to_lexical! { isize u16 ; }
149
150#[cfg(target_pointer_width = "32")]
151signed_to_lexical! { isize u32 ; }
152
153#[cfg(target_pointer_width = "64")]
154signed_to_lexical! { isize u64 ; }