Coverage Report

Created: 2025-06-16 06:50

/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
}