/rust/registry/src/index.crates.io-6f17d22bba15001f/ryu-1.0.19/src/buffer/mod.rs
Line | Count | Source (jump to first uncovered line) |
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)] |
29 | 0 | pub fn new() -> Self { |
30 | 0 | let bytes = [MaybeUninit::<u8>::uninit(); 24]; |
31 | 0 | Buffer { bytes } |
32 | 0 | } Unexecuted instantiation: <ryu::buffer::Buffer>::new Unexecuted instantiation: <ryu::buffer::Buffer>::new |
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)] |
47 | 0 | pub fn format<F: Float>(&mut self, f: F) -> &str { |
48 | 0 | if f.is_nonfinite() { |
49 | 0 | f.format_nonfinite() |
50 | | } else { |
51 | 0 | self.format_finite(f) |
52 | | } |
53 | 0 | } |
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)] |
72 | 0 | pub fn format_finite<F: Float>(&mut self, f: F) -> &str { |
73 | 0 | unsafe { |
74 | 0 | let n = f.write_to_ryu_buffer(self.bytes.as_mut_ptr() as *mut u8); |
75 | 0 | debug_assert!(n <= self.bytes.len()); |
76 | 0 | let slice = slice::from_raw_parts(self.bytes.as_ptr() as *const u8, n); |
77 | 0 | str::from_utf8_unchecked(slice) |
78 | 0 | } |
79 | 0 | } Unexecuted instantiation: <ryu::buffer::Buffer>::format_finite::<f64> Unexecuted instantiation: <ryu::buffer::Buffer>::format_finite::<_> |
80 | | } |
81 | | |
82 | | impl Copy for Buffer {} |
83 | | |
84 | | impl Clone for Buffer { |
85 | | #[inline] |
86 | | #[allow(clippy::non_canonical_clone_impl)] // false positive https://github.com/rust-lang/rust-clippy/issues/11072 |
87 | 0 | fn clone(&self) -> Self { |
88 | 0 | Buffer::new() |
89 | 0 | } |
90 | | } |
91 | | |
92 | | impl Default for Buffer { |
93 | | #[inline] |
94 | | #[cfg_attr(feature = "no-panic", no_panic)] |
95 | 0 | fn default() -> Self { |
96 | 0 | Buffer::new() |
97 | 0 | } |
98 | | } |
99 | | |
100 | | /// A floating point number, f32 or f64, that can be written into a |
101 | | /// [`ryu::Buffer`][Buffer]. |
102 | | /// |
103 | | /// This trait is sealed and cannot be implemented for types outside of the |
104 | | /// `ryu` crate. |
105 | | pub trait Float: Sealed {} |
106 | | impl Float for f32 {} |
107 | | impl Float for f64 {} |
108 | | |
109 | | pub trait Sealed: Copy { |
110 | | fn is_nonfinite(self) -> bool; |
111 | | fn format_nonfinite(self) -> &'static str; |
112 | | unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize; |
113 | | } |
114 | | |
115 | | impl Sealed for f32 { |
116 | | #[inline] |
117 | 0 | fn is_nonfinite(self) -> bool { |
118 | | const EXP_MASK: u32 = 0x7f800000; |
119 | 0 | let bits = self.to_bits(); |
120 | 0 | bits & EXP_MASK == EXP_MASK |
121 | 0 | } |
122 | | |
123 | | #[cold] |
124 | | #[cfg_attr(feature = "no-panic", inline)] |
125 | 0 | fn format_nonfinite(self) -> &'static str { |
126 | | const MANTISSA_MASK: u32 = 0x007fffff; |
127 | | const SIGN_MASK: u32 = 0x80000000; |
128 | 0 | let bits = self.to_bits(); |
129 | 0 | if bits & MANTISSA_MASK != 0 { |
130 | 0 | NAN |
131 | 0 | } else if bits & SIGN_MASK != 0 { |
132 | 0 | NEG_INFINITY |
133 | | } else { |
134 | 0 | INFINITY |
135 | | } |
136 | 0 | } |
137 | | |
138 | | #[inline] |
139 | 0 | unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { |
140 | 0 | raw::format32(self, result) |
141 | 0 | } |
142 | | } |
143 | | |
144 | | impl Sealed for f64 { |
145 | | #[inline] |
146 | 0 | fn is_nonfinite(self) -> bool { |
147 | | const EXP_MASK: u64 = 0x7ff0000000000000; |
148 | 0 | let bits = self.to_bits(); |
149 | 0 | bits & EXP_MASK == EXP_MASK |
150 | 0 | } |
151 | | |
152 | | #[cold] |
153 | | #[cfg_attr(feature = "no-panic", inline)] |
154 | 0 | fn format_nonfinite(self) -> &'static str { |
155 | | const MANTISSA_MASK: u64 = 0x000fffffffffffff; |
156 | | const SIGN_MASK: u64 = 0x8000000000000000; |
157 | 0 | let bits = self.to_bits(); |
158 | 0 | if bits & MANTISSA_MASK != 0 { |
159 | 0 | NAN |
160 | 0 | } else if bits & SIGN_MASK != 0 { |
161 | 0 | NEG_INFINITY |
162 | | } else { |
163 | 0 | INFINITY |
164 | | } |
165 | 0 | } |
166 | | |
167 | | #[inline] |
168 | 0 | unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize { |
169 | 0 | raw::format64(self, result) |
170 | 0 | } Unexecuted instantiation: <f64 as ryu::buffer::Sealed>::write_to_ryu_buffer Unexecuted instantiation: <f64 as ryu::buffer::Sealed>::write_to_ryu_buffer |
171 | | } |