1#![doc(html_root_url = "https://docs.rs/dtoa/1.0.11")]
43#![no_std]
44#![allow(
45 clippy::cast_lossless,
46 clippy::cast_possible_truncation,
47 clippy::cast_possible_wrap,
48 clippy::cast_precision_loss,
49 clippy::cast_sign_loss,
50 clippy::doc_markdown,
51 clippy::expl_impl_clone_on_copy,
52 clippy::if_not_else,
53 clippy::missing_errors_doc,
54 clippy::must_use_candidate,
55 clippy::needless_doctest_main,
56 clippy::range_plus_one,
57 clippy::semicolon_if_nothing_returned, clippy::shadow_unrelated,
59 clippy::suspicious_else_formatting,
60 clippy::unreadable_literal,
61 clippy::unseparated_literal_suffix
62)]
63
64#[macro_use]
65mod diyfp;
66#[macro_use]
67mod dtoa;
68
69use core::mem::MaybeUninit;
70use core::slice;
71use core::str;
72#[cfg(feature = "no-panic")]
73use no_panic::no_panic;
74
75const NAN: &str = "NaN";
76const INFINITY: &str = "inf";
77const NEG_INFINITY: &str = "-inf";
78
79pub struct Buffer {
90 bytes: [MaybeUninit<u8>; 25],
91}
92
93impl Default for Buffer {
94 #[inline]
95 fn default() -> Buffer {
96 Buffer::new()
97 }
98}
99
100impl Copy for Buffer {}
101
102#[allow(clippy::non_canonical_clone_impl)]
103impl Clone for Buffer {
104 #[inline]
105 fn clone(&self) -> Self {
106 Buffer::new()
107 }
108}
109
110impl Buffer {
111 #[inline]
114 #[cfg_attr(feature = "no-panic", no_panic)]
115 pub fn new() -> Buffer {
116 let bytes = [MaybeUninit::<u8>::uninit(); 25];
117 Buffer { bytes }
118 }
119
120 #[cfg_attr(feature = "no-panic", no_panic)]
132 pub fn format<F: Float>(&mut self, value: F) -> &str {
133 if value.is_nonfinite() {
134 value.format_nonfinite()
135 } else {
136 self.format_finite(value)
137 }
138 }
139
140 #[cfg_attr(feature = "no-panic", no_panic)]
156 pub fn format_finite<F: Float>(&mut self, value: F) -> &str {
157 value.write(self)
158 }
159}
160
161pub trait Float: private::Sealed {}
165
166impl Float for f32 {}
167impl Float for f64 {}
168
169mod private {
171 pub trait Sealed: Copy {
172 fn is_nonfinite(self) -> bool;
173 fn format_nonfinite(self) -> &'static str;
174 fn write(self, buf: &mut crate::Buffer) -> &str;
175 }
176}
177
178impl private::Sealed for f32 {
179 #[inline]
180 #[cfg_attr(feature = "no-panic", no_panic)]
181 fn is_nonfinite(self) -> bool {
182 const EXP_MASK: u32 = 0x7f800000;
183 let bits = self.to_bits();
184 bits & EXP_MASK == EXP_MASK
185 }
186
187 #[cold]
188 #[cfg_attr(feature = "no-panic", no_panic)]
189 fn format_nonfinite(self) -> &'static str {
190 const MANTISSA_MASK: u32 = 0x007fffff;
191 const SIGN_MASK: u32 = 0x80000000;
192 let bits = self.to_bits();
193 if bits & MANTISSA_MASK != 0 {
194 NAN
195 } else if bits & SIGN_MASK != 0 {
196 NEG_INFINITY
197 } else {
198 INFINITY
199 }
200 }
201
202 #[inline]
203 fn write(self, buf: &mut Buffer) -> &str {
204 dtoa! {
205 floating_type: f32,
206 significand_type: u32,
207 exponent_type: i32,
208
209 diy_significand_size: 32,
210 significand_size: 23,
211 exponent_bias: 0x7F,
212 mask_type: u32,
213 exponent_mask: 0x7F800000,
214 significand_mask: 0x007FFFFF,
215 hidden_bit: 0x00800000,
216 cached_powers_f: CACHED_POWERS_F_32,
217 cached_powers_e: CACHED_POWERS_E_32,
218 min_power: (-36),
219 };
220 unsafe { dtoa(buf, self) }
221 }
222}
223
224impl private::Sealed for f64 {
225 #[inline]
226 #[cfg_attr(feature = "no-panic", no_panic)]
227 fn is_nonfinite(self) -> bool {
228 const EXP_MASK: u64 = 0x7ff0000000000000;
229 let bits = self.to_bits();
230 bits & EXP_MASK == EXP_MASK
231 }
232
233 #[cold]
234 #[cfg_attr(feature = "no-panic", no_panic)]
235 fn format_nonfinite(self) -> &'static str {
236 const MANTISSA_MASK: u64 = 0x000fffffffffffff;
237 const SIGN_MASK: u64 = 0x8000000000000000;
238 let bits = self.to_bits();
239 if bits & MANTISSA_MASK != 0 {
240 NAN
241 } else if bits & SIGN_MASK != 0 {
242 NEG_INFINITY
243 } else {
244 INFINITY
245 }
246 }
247
248 #[inline]
249 fn write(self, buf: &mut Buffer) -> &str {
250 dtoa! {
251 floating_type: f64,
252 significand_type: u64,
253 exponent_type: isize,
254
255 diy_significand_size: 64,
256 significand_size: 52,
257 exponent_bias: 0x3FF,
258 mask_type: u64,
259 exponent_mask: 0x7FF0000000000000,
260 significand_mask: 0x000FFFFFFFFFFFFF,
261 hidden_bit: 0x0010000000000000,
262 cached_powers_f: CACHED_POWERS_F_64,
263 cached_powers_e: CACHED_POWERS_E_64,
264 min_power: (-348),
265 };
266 unsafe { dtoa(buf, self) }
267 }
268}
269
270const MAX_DECIMAL_PLACES: isize = 324;
273
274static DEC_DIGITS_LUT: [u8; 200] = *b"\
275 0001020304050607080910111213141516171819\
276 2021222324252627282930313233343536373839\
277 4041424344454647484950515253545556575859\
278 6061626364656667686970717273747576777879\
279 8081828384858687888990919293949596979899";
280
281#[rustfmt::skip]
283static CACHED_POWERS_F_32: [u32; 12] = [
284 0xaa242499, 0xfd87b5f3, 0xbce50865, 0x8cbccc09,
285 0xd1b71759, 0x9c400000, 0xe8d4a510, 0xad78ebc6,
286 0x813f3979, 0xc097ce7c, 0x8f7e32ce, 0xd5d238a5,
287];
288
289#[rustfmt::skip]
290static CACHED_POWERS_E_32: [i16; 12] = [
291 -151, -125, -98, -71, -45, -18, 8, 35, 62, 88, 115, 141,
292];
293
294#[rustfmt::skip]
296static CACHED_POWERS_F_64: [u64; 87] = [
297 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76,
298 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
299 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
300 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
301 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c,
302 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
303 0xea9c227723ee8bcb, 0xaecc49914078536d,
304 0x823c12795db6ce57, 0xc21094364dfb5637,
305 0x9096ea6f3848984f, 0xd77485cb25823ac7,
306 0xa086cfcd97bf97f4, 0xef340a98172aace5,
307 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b,
308 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
309 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6,
310 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
311 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
312 0x964e858c91ba2655, 0xdff9772470297ebd,
313 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94,
314 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
315 0xcdb02555653131b6, 0x993fe2c6d07b7fac,
316 0xe45c10c42a2b3b06, 0xaa242499697392d3,
317 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
318 0x8cbccc096f5088cc, 0xd1b71758e219652c,
319 0x9c40000000000000, 0xe8d4a51000000000,
320 0xad78ebc5ac620000, 0x813f3978f8940984,
321 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70,
322 0xd5d238a4abe98068, 0x9f4f2726179a2245,
323 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
324 0x83c7088e1aab65db, 0xc45d1df942711d9a,
325 0x924d692ca61be758, 0xda01ee641a708dea,
326 0xa26da3999aef774a, 0xf209787bb47d6b85,
327 0xb454e4a179dd1877, 0x865b86925b9bc5c2,
328 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
329 0xde469fbd99a05fe3, 0xa59bc234db398c25,
330 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
331 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5,
332 0x98165af37b2153df, 0xe2a0b5dc971f303a,
333 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c,
334 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
335 0xd01fef10a657842c, 0x9b10a4e5e9913129,
336 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
337 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d,
338 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
339 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9,
340 0xaf87023b9bf0ee6b,
341];
342
343#[rustfmt::skip]
344static CACHED_POWERS_E_64: [i16; 87] = [
345 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
346 -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
347 -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
348 -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
349 -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
350 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
351 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
352 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
353 907, 933, 960, 986, 1013, 1039, 1066,
354];