1use core::{mem::MaybeUninit, slice, str};
2
3#[cfg(feature = "no-panic")]
4use no_panic::no_panic;
5
6use crate::raw;
7
8const NAN: &str = "NaN";
9const INFINITY: &str = "inf";
10const NEG_INFINITY: &str = "-inf";
11
12pub struct Buffer {
22 bytes: [MaybeUninit<u8>; 24],
23}
24
25impl Buffer {
26 #[inline]
29 #[cfg_attr(feature = "no-panic", no_panic)]
30 pub fn new() -> Self {
31 let bytes = [MaybeUninit::<u8>::uninit(); 24];
32 Buffer {
33 bytes,
34 }
35 }
36
37 #[cfg_attr(feature = "no-panic", inline)]
49 #[cfg_attr(feature = "no-panic", no_panic)]
50 pub fn format<F: Float>(&mut self, f: F) -> &str {
51 if f.is_nonfinite() {
52 f.format_nonfinite()
53 } else {
54 self.format_finite(f)
55 }
56 }
57
58 #[inline]
74 #[cfg_attr(feature = "no-panic", no_panic)]
75 pub fn format_finite<F: Float>(&mut self, f: F) -> &str {
76 unsafe {
77 let n = f.write_to_ryu_buffer(self.bytes.as_mut_ptr() as *mut u8);
78 debug_assert!(n <= self.bytes.len());
79 let slice = slice::from_raw_parts(self.bytes.as_ptr() as *const u8, n);
80 str::from_utf8_unchecked(slice)
81 }
82 }
83}
84
85impl Copy for Buffer {}
86
87impl Clone for Buffer {
88 #[inline]
89 #[allow(clippy::non_canonical_clone_impl)] fn clone(&self) -> Self {
91 Buffer::new()
92 }
93}
94
95impl Default for Buffer {
96 #[inline]
97 #[cfg_attr(feature = "no-panic", no_panic)]
98 fn default() -> Self {
99 Buffer::new()
100 }
101}
102
103pub trait Float: Sealed {}
109impl Float for f32 {}
110impl Float for f64 {}
111
112pub trait Sealed: Copy {
113 fn is_nonfinite(self) -> bool;
114 fn format_nonfinite(self) -> &'static str;
115 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize;
116}
117
118impl Sealed for f32 {
119 #[inline]
120 fn is_nonfinite(self) -> bool {
121 const EXP_MASK: u32 = 0x7f800000;
122 let bits = self.to_bits();
123 bits & EXP_MASK == EXP_MASK
124 }
125
126 #[cold]
127 #[cfg_attr(feature = "no-panic", inline)]
128 fn format_nonfinite(self) -> &'static str {
129 const MANTISSA_MASK: u32 = 0x007fffff;
130 const SIGN_MASK: u32 = 0x80000000;
131 let bits = self.to_bits();
132 if bits & MANTISSA_MASK != 0 {
133 NAN
134 } else if bits & SIGN_MASK != 0 {
135 NEG_INFINITY
136 } else {
137 INFINITY
138 }
139 }
140
141 #[inline]
142 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
143 unsafe { raw::format32(self, result) }
144 }
145}
146
147impl Sealed for f64 {
148 #[inline]
149 fn is_nonfinite(self) -> bool {
150 const EXP_MASK: u64 = 0x7ff0000000000000;
151 let bits = self.to_bits();
152 bits & EXP_MASK == EXP_MASK
153 }
154
155 #[cold]
156 #[cfg_attr(feature = "no-panic", inline)]
157 fn format_nonfinite(self) -> &'static str {
158 const MANTISSA_MASK: u64 = 0x000fffffffffffff;
159 const SIGN_MASK: u64 = 0x8000000000000000;
160 let bits = self.to_bits();
161 if bits & MANTISSA_MASK != 0 {
162 NAN
163 } else if bits & SIGN_MASK != 0 {
164 NEG_INFINITY
165 } else {
166 INFINITY
167 }
168 }
169
170 #[inline]
171 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
172 unsafe { raw::format64(self, result) }
173 }
174}