lexical_write_float/
api.rs

1//! Implements the algorithm in terms of the lexical API.
2
3#![doc(hidden)]
4
5use crate::options::Options;
6use crate::write::WriteFloat;
7#[cfg(feature = "f16")]
8use lexical_util::bf16::bf16;
9use lexical_util::constants::FormattedSize;
10#[cfg(feature = "f16")]
11use lexical_util::f16::f16;
12use lexical_util::format::{is_valid_options_punctuation, NumberFormat, STANDARD};
13use lexical_util::options::WriteOptions;
14use lexical_util::{to_lexical, to_lexical_with_options};
15
16/// Check if a buffer is sufficiently large.
17#[inline]
18fn check_buffer<T, const FORMAT: u128>(len: usize, options: &Options) -> bool
19where
20    T: FormattedSize,
21{
22    let size = Options::buffer_size::<T, FORMAT>(options);
23    len >= size
24}
25
26// API
27
28const DEFAULT_OPTIONS: Options = Options::new();
29
30// Implement ToLexical for numeric type.
31macro_rules! float_to_lexical {
32    ($($t:tt $(, #[$meta:meta])? ; )*) => ($(
33        impl ToLexical for $t {
34            $(#[$meta:meta])?
35            unsafe fn to_lexical_unchecked<'a>(self, bytes: &'a mut [u8])
36                -> &'a mut [u8]
37            {
38                debug_assert!(check_buffer::<Self, { STANDARD }>(bytes.len(), &DEFAULT_OPTIONS));
39                // SAFETY: safe if `check_buffer::<STANDARD>(bytes.len(), &options)` passes.
40                unsafe {
41                    let len = self.write_float::<{ STANDARD }>(bytes, &DEFAULT_OPTIONS);
42                    &mut index_unchecked_mut!(bytes[..len])
43                }
44            }
45
46            $(#[$meta:meta])?
47            fn to_lexical<'a>(self, bytes: &'a mut [u8])
48                -> &'a mut [u8]
49            {
50                assert!(check_buffer::<Self, { STANDARD }>(bytes.len(), &DEFAULT_OPTIONS));
51                // SAFETY: safe since `check_buffer::<STANDARD>(bytes.len(), &options)` passes.
52                unsafe { self.to_lexical_unchecked(bytes) }
53            }
54        }
55
56        impl ToLexicalWithOptions for $t {
57            type Options = Options;
58
59            $(#[$meta:meta])?
60            unsafe fn to_lexical_with_options_unchecked<'a, const FORMAT: u128>(
61                self,
62                bytes: &'a mut [u8],
63                options: &Self::Options,
64            ) -> &'a mut [u8]
65            {
66                assert!(NumberFormat::<{ FORMAT }> {}.is_valid());
67                assert!(is_valid_options_punctuation(FORMAT, options.exponent(), options.decimal_point()));
68                debug_assert!(check_buffer::<Self, { FORMAT }>(bytes.len(), &options));
69                // SAFETY: safe if `check_buffer::<FORMAT>(bytes.len(), &options)` passes.
70                unsafe {
71                    let len = self.write_float::<{ FORMAT }>(bytes, &options);
72                    &mut index_unchecked_mut!(bytes[..len])
73                }
74            }
75
76            $(#[$meta:meta])?
77            fn to_lexical_with_options<'a, const FORMAT: u128>(
78                self,
79                bytes: &'a mut [u8],
80                options: &Self::Options,
81            ) -> &'a mut [u8]
82            {
83                assert!(check_buffer::<Self, { FORMAT }>(bytes.len(), &options));
84                // SAFETY: safe since `check_buffer::<FORMAT>(bytes.len(), &options)` passes.
85                unsafe { self.to_lexical_with_options_unchecked::<FORMAT>(bytes, options) }
86            }
87        }
88    )*)
89}
90
91to_lexical! {}
92to_lexical_with_options! {}
93float_to_lexical! {
94    f32 ;
95    f64 ;
96}
97#[cfg(feature = "f16")]
98float_to_lexical! {
99    f16 ;
100    bf16 ;
101}