Coverage Report

Created: 2026-03-14 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ryu-1.0.5/src/buffer/mod.rs
Line
Count
Source
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)]
33
0
    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
0
        let bytes = [MaybeUninit::<u8>::uninit(); 24];
38
        #[cfg(not(maybe_uninit))]
39
        let bytes = unsafe { mem::uninitialized() };
40
41
0
        Buffer { bytes: bytes }
42
0
    }
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)]
57
0
    pub fn format<F: Float>(&mut self, f: F) -> &str {
58
0
        if f.is_nonfinite() {
59
0
            f.format_nonfinite()
60
        } else {
61
0
            self.format_finite(f)
62
        }
63
0
    }
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)]
82
0
    pub fn format_finite<F: Float>(&mut self, f: F) -> &str {
83
        unsafe {
84
0
            let n = f.write_to_ryu_buffer(self.bytes.as_mut_ptr() as *mut u8);
85
0
            debug_assert!(n <= self.bytes.len());
86
0
            let slice = slice::from_raw_parts(self.bytes.as_ptr() as *const u8, n);
87
0
            str::from_utf8_unchecked(slice)
88
        }
89
0
    }
Unexecuted instantiation: <ryu::buffer::Buffer>::format_finite::<_>
Unexecuted instantiation: <ryu::buffer::Buffer>::format_finite::<f64>
90
}
91
92
impl Copy for Buffer {}
93
94
impl Clone for Buffer {
95
    #[inline]
96
0
    fn clone(&self) -> Self {
97
0
        Buffer::new()
98
0
    }
99
}
100
101
impl Default for Buffer {
102
    #[inline]
103
    #[cfg_attr(feature = "no-panic", no_panic)]
104
0
    fn default() -> Self {
105
0
        Buffer::new()
106
0
    }
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 {
119
    fn is_nonfinite(self) -> bool;
120
    fn format_nonfinite(self) -> &'static str;
121
    unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize;
122
}
123
124
impl Sealed for f32 {
125
    #[inline]
126
0
    fn is_nonfinite(self) -> bool {
127
        const EXP_MASK: u32 = 0x7f800000;
128
0
        let bits = unsafe { mem::transmute::<f32, u32>(self) };
129
0
        bits & EXP_MASK == EXP_MASK
130
0
    }
131
132
    #[cold]
133
    #[cfg_attr(feature = "no-panic", inline)]
134
0
    fn format_nonfinite(self) -> &'static str {
135
        const MANTISSA_MASK: u32 = 0x007fffff;
136
        const SIGN_MASK: u32 = 0x80000000;
137
0
        let bits = unsafe { mem::transmute::<f32, u32>(self) };
138
0
        if bits & MANTISSA_MASK != 0 {
139
0
            NAN
140
0
        } else if bits & SIGN_MASK != 0 {
141
0
            NEG_INFINITY
142
        } else {
143
0
            INFINITY
144
        }
145
0
    }
146
147
    #[inline]
148
0
    unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
149
0
        raw::format32(self, result)
150
0
    }
151
}
152
153
impl Sealed for f64 {
154
    #[inline]
155
0
    fn is_nonfinite(self) -> bool {
156
        const EXP_MASK: u64 = 0x7ff0000000000000;
157
0
        let bits = unsafe { mem::transmute::<f64, u64>(self) };
158
0
        bits & EXP_MASK == EXP_MASK
159
0
    }
160
161
    #[cold]
162
    #[cfg_attr(feature = "no-panic", inline)]
163
0
    fn format_nonfinite(self) -> &'static str {
164
        const MANTISSA_MASK: u64 = 0x000fffffffffffff;
165
        const SIGN_MASK: u64 = 0x8000000000000000;
166
0
        let bits = unsafe { mem::transmute::<f64, u64>(self) };
167
0
        if bits & MANTISSA_MASK != 0 {
168
0
            NAN
169
0
        } else if bits & SIGN_MASK != 0 {
170
0
            NEG_INFINITY
171
        } else {
172
0
            INFINITY
173
        }
174
0
    }
175
176
    #[inline]
177
0
    unsafe fn write_to_ryu_buffer(self, result: *mut u8) -> usize {
178
0
        raw::format64(self, result)
179
0
    }
180
}