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