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