1 use crate::raw; 2 use core::mem::MaybeUninit; 3 use core::{slice, str}; 4 #[cfg(feature = "no-panic")] 5 use no_panic::no_panic; 6 7 const NAN: &str = "NaN"; 8 const INFINITY: &str = "inf"; 9 const NEG_INFINITY: &str = "-inf"; 10 11 /// Safe API for formatting floating point numbers to text. 12 /// 13 /// ## Example 14 /// 15 /// ``` 16 /// let mut buffer = ryu::Buffer::new(); 17 /// let printed = buffer.format_finite(1.234); 18 /// assert_eq!(printed, "1.234"); 19 /// ``` 20 pub struct Buffer { 21 bytes: [MaybeUninit<u8>; 24], 22 } 23 24 impl Buffer { 25 /// This is a cheap operation; you don't need to worry about reusing buffers 26 /// for efficiency. 27 #[inline] 28 #[cfg_attr(feature = "no-panic", no_panic)] new() -> Self29 pub fn new() -> Self { 30 let bytes = [MaybeUninit::<u8>::uninit(); 24]; 31 Buffer { bytes } 32 } 33 34 /// Print a floating point number into this buffer and return a reference to 35 /// its string representation within the buffer. 36 /// 37 /// # Special cases 38 /// 39 /// This function formats NaN as the string "NaN", positive infinity as 40 /// "inf", and negative infinity as "-inf" to match std::fmt. 41 /// 42 /// If your input is known to be finite, you may get better performance by 43 /// calling the `format_finite` method instead of `format` to avoid the 44 /// checks for special cases. 45 #[cfg_attr(feature = "no-panic", inline)] 46 #[cfg_attr(feature = "no-panic", no_panic)] format<F: Float>(&mut self, f: F) -> &str47 pub fn format<F: Float>(&mut self, f: F) -> &str { 48 if f.is_nonfinite() { 49 f.format_nonfinite() 50 } else { 51 self.format_finite(f) 52 } 53 } 54 55 /// Print a floating point number into this buffer and return a reference to 56 /// its string representation within the buffer. 57 /// 58 /// # Special cases 59 /// 60 /// This function **does not** check for NaN or infinity. If the input 61 /// number is not a finite float, the printed representation will be some 62 /// correctly formatted but unspecified numerical value. 63 /// 64 /// Please check [`is_finite`] yourself before calling this function, or 65 /// check [`is_nan`] and [`is_infinite`] and handle those cases yourself. 66 /// 67 /// [`is_finite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_finite 68 /// [`is_nan`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_nan 69 /// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite 70 #[inline] 71 #[cfg_attr(feature = "no-panic", no_panic)] format_finite<F: Float>(&mut self, f: F) -> &str72 pub fn format_finite<F: Float>(&mut self, f: F) -> &str { 73 unsafe { 74 let n = f.write_to_ryu_buffer(self.bytes.as_mut_ptr() as *mut u8); 75 debug_assert!(n <= self.bytes.len()); 76 let slice = slice::from_raw_parts(self.bytes.as_ptr() as *const u8, n); 77 str::from_utf8_unchecked(slice) 78 } 79 } 80 } 81 82 impl Copy for Buffer {} 83 84 impl Clone for Buffer { 85 #[inline] clone(&self) -> Self86 fn clone(&self) -> Self { 87 Buffer::new() 88 } 89 } 90 91 impl Default for Buffer { 92 #[inline] 93 #[cfg_attr(feature = "no-panic", no_panic)] default() -> Self94 fn default() -> Self { 95 Buffer::new() 96 } 97 } 98 99 /// A floating point number, f32 or f64, that can be written into a 100 /// [`ryu::Buffer`][Buffer]. 101 /// 102 /// This trait is sealed and cannot be implemented for types outside of the 103 /// `ryu` crate. 104 pub trait Float: Sealed {} 105 impl Float for f32 {} 106 impl Float for f64 {} 107 108 pub trait Sealed: Copy { is_nonfinite(self) -> bool109 fn is_nonfinite(self) -> bool; format_nonfinite(self) -> &'static str110 fn format_nonfinite(self) -> &'static str; write_to_ryu_buffer(self, result: *mut u8) -> usize111 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize; 112 } 113 114 impl Sealed for f32 { 115 #[inline] is_nonfinite(self) -> bool116 fn is_nonfinite(self) -> bool { 117 const EXP_MASK: u32 = 0x7f800000; 118 let bits = self.to_bits(); 119 bits & EXP_MASK == EXP_MASK 120 } 121 122 #[cold] 123 #[cfg_attr(feature = "no-panic", inline)] format_nonfinite(self) -> &'static str124 fn format_nonfinite(self) -> &'static str { 125 const MANTISSA_MASK: u32 = 0x007fffff; 126 const SIGN_MASK: u32 = 0x80000000; 127 let bits = self.to_bits(); 128 if bits & MANTISSA_MASK != 0 { 129 NAN 130 } else if bits & SIGN_MASK != 0 { 131 NEG_INFINITY 132 } else { 133 INFINITY 134 } 135 } 136 137 #[inline] write_to_ryu_buffer(self, result: *mut u8) -> usize138 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { 139 raw::format32(self, result) 140 } 141 } 142 143 impl Sealed for f64 { 144 #[inline] is_nonfinite(self) -> bool145 fn is_nonfinite(self) -> bool { 146 const EXP_MASK: u64 = 0x7ff0000000000000; 147 let bits = self.to_bits(); 148 bits & EXP_MASK == EXP_MASK 149 } 150 151 #[cold] 152 #[cfg_attr(feature = "no-panic", inline)] format_nonfinite(self) -> &'static str153 fn format_nonfinite(self) -> &'static str { 154 const MANTISSA_MASK: u64 = 0x000fffffffffffff; 155 const SIGN_MASK: u64 = 0x8000000000000000; 156 let bits = self.to_bits(); 157 if bits & MANTISSA_MASK != 0 { 158 NAN 159 } else if bits & SIGN_MASK != 0 { 160 NEG_INFINITY 161 } else { 162 INFINITY 163 } 164 } 165 166 #[inline] write_to_ryu_buffer(self, result: *mut u8) -> usize167 unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { 168 raw::format64(self, result) 169 } 170 } 171