lexical_write_float/
write.rs
1#![doc(hidden)]
4
5#[cfg(feature = "f16")]
6use lexical_util::bf16::bf16;
7#[cfg(feature = "f16")]
8use lexical_util::f16::f16;
9use lexical_util::format::NumberFormat;
10use lexical_util::options::WriteOptions;
11use lexical_util::{algorithm::copy_to_dst, constants::FormattedSize};
12use lexical_write_integer::write::WriteInteger;
13
14#[cfg(not(feature = "compact"))]
16use crate::algorithm::write_float as write_float_decimal;
17#[cfg(feature = "power-of-two")]
18use crate::binary;
19#[cfg(feature = "compact")]
20use crate::compact::write_float as write_float_decimal;
21use crate::float::RawFloat;
22#[cfg(feature = "power-of-two")]
23use crate::hex;
24use crate::options::Options;
25#[cfg(feature = "radix")]
26use crate::radix;
27
28#[inline(always)]
30fn write_special(bytes: &mut [u8], special: Option<&[u8]>, error: &'static str) -> usize {
31 if let Some(special_str) = special {
33 debug_assert!(special_str.len() <= 50, "special_str.len() must be <= 50");
34 copy_to_dst(bytes, special_str)
35 } else {
36 panic!("{}", error);
38 }
39}
40
41fn write_nan(bytes: &mut [u8], options: &Options, count: usize) -> usize {
43 count
44 + write_special(
45 bytes,
46 options.nan_string(),
47 "NaN explicitly disabled but asked to write NaN as string.",
48 )
49}
50
51fn write_inf(bytes: &mut [u8], options: &Options, count: usize) -> usize {
53 count
54 + write_special(
55 bytes,
56 options.inf_string(),
57 "Inf explicitly disabled but asked to write Inf as string.",
58 )
59}
60
61#[inline(always)]
63fn check_buffer<T, const FORMAT: u128>(len: usize, options: &Options) -> bool
64where
65 T: FormattedSize,
66{
67 let size = Options::buffer_size::<T, FORMAT>(options);
68 len >= size
69}
70
71pub trait WriteFloat: RawFloat + FormattedSize {
73 #[cfg_attr(not(feature = "compact"), inline(always))]
89 fn write_float<const FORMAT: u128>(self, bytes: &mut [u8], options: &Options) -> usize
90 where
91 Self::Unsigned: FormattedSize + WriteInteger,
92 {
93 assert!(check_buffer::<Self, { FORMAT }>(bytes.len(), options));
95 let format = NumberFormat::<FORMAT> {};
96 assert!(format.is_valid());
97 assert!(Self::BITS <= 64);
99
100 #[cfg(feature = "power-of-two")]
101 {
102 if format.radix() != format.exponent_base() {
104 assert!(matches!(
105 (format.radix(), format.exponent_base()),
106 (4, 2) | (8, 2) | (16, 2) | (32, 2) | (16, 4)
107 ));
108 }
109 }
110
111 let (float, count, bytes) = if self.needs_negative_sign() {
112 bytes[0] = b'-';
113 (-self, 1, &mut bytes[1..])
114 } else if cfg!(feature = "format") && format.required_mantissa_sign() {
115 bytes[0] = b'+';
116 (self, 1, &mut bytes[1..])
117 } else {
118 (self, 0, bytes)
119 };
120
121 if !self.is_special() {
123 #[cfg(all(feature = "power-of-two", not(feature = "radix")))]
124 {
125 let radix = format.radix();
126 let exponent_base = format.exponent_base();
127 count
128 + if radix == 10 {
129 write_float_decimal::<_, FORMAT>(float, bytes, options)
130 } else if radix != exponent_base {
131 hex::write_float::<_, FORMAT>(float, bytes, options)
132 } else {
133 binary::write_float::<_, FORMAT>(float, bytes, options)
134 }
135 }
136
137 #[cfg(feature = "radix")]
138 {
139 let radix = format.radix();
140 let exponent_base = format.exponent_base();
141 count
142 + if radix == 10 {
143 write_float_decimal::<_, FORMAT>(float, bytes, options)
144 } else if radix != exponent_base {
145 hex::write_float::<_, FORMAT>(float, bytes, options)
146 } else if matches!(radix, 2 | 4 | 8 | 16 | 32) {
147 binary::write_float::<_, FORMAT>(float, bytes, options)
148 } else {
149 radix::write_float::<_, FORMAT>(float, bytes, options)
150 }
151 }
152
153 #[cfg(not(feature = "power-of-two"))]
154 {
155 count + write_float_decimal::<_, FORMAT>(float, bytes, options)
156 }
157 } else if self.is_nan() {
158 write_nan(bytes, options, count)
159 } else {
160 write_inf(bytes, options, count)
161 }
162 }
163}
164
165macro_rules! write_float_impl {
166 ($($t:ty)*) => ($(
167 impl WriteFloat for $t {}
168 )*)
169}
170
171write_float_impl! { f32 f64 }
172
173#[cfg(feature = "f16")]
174macro_rules! write_float_as_f32 {
175 ($($t:ty)*) => ($(
176 impl WriteFloat for $t {
177 #[inline(always)]
178 fn write_float<const FORMAT: u128>(self, bytes: &mut [u8], options: &Options) -> usize
179 {
180 self.as_f32().write_float::<FORMAT>(bytes, options)
181 }
182 }
183 )*)
184}
185
186#[cfg(feature = "f16")]
187write_float_as_f32! { bf16 f16 }