@@ -5,13 +5,17 @@ use raw;
5
5
#[ cfg( feature = "no-panic" ) ]
6
6
use no_panic:: no_panic;
7
7
8
+ const NAN : & ' static str = "NaN" ;
9
+ const INFINITY : & ' static str = "inf" ;
10
+ const NEG_INFINITY : & ' static str = "-inf" ;
11
+
8
12
/// Safe API for formatting floating point numbers to text.
9
13
///
10
14
/// ## Example
11
15
///
12
16
/// ```edition2018
13
17
/// let mut buffer = ryu::Buffer::new();
14
- /// let printed = buffer.format (1.234);
18
+ /// let printed = buffer.format_finite (1.234);
15
19
/// assert_eq!(printed, "1.234");
16
20
/// ```
17
21
#[ derive( Copy , Clone ) ]
@@ -30,6 +34,26 @@ impl Buffer {
30
34
}
31
35
}
32
36
37
+ /// Print a floating point number into this buffer and return a reference to
38
+ /// its string representation within the buffer.
39
+ ///
40
+ /// # Special cases
41
+ ///
42
+ /// This function formats NaN as the string "NaN", positive infinity as
43
+ /// "inf", and negative infinity as "-inf" to match std::fmt.
44
+ ///
45
+ /// If your input is known to be finite, you may get better performance by
46
+ /// calling the `format_finite` method instead of `format` to avoid the
47
+ /// checks for special cases.
48
+ #[ cfg_attr( feature = "no-panic" , no_panic) ]
49
+ pub fn format < F : Float > ( & mut self , f : F ) -> & str {
50
+ if f. is_nonfinite ( ) {
51
+ f. format_nonfinite ( )
52
+ } else {
53
+ self . format_finite ( f)
54
+ }
55
+ }
56
+
33
57
/// Print a floating point number into this buffer and return a reference to
34
58
/// its string representation within the buffer.
35
59
///
@@ -47,7 +71,7 @@ impl Buffer {
47
71
/// [`is_infinite`]: https://doc.rust-lang.org/std/primitive.f64.html#method.is_infinite
48
72
#[ inline]
49
73
#[ cfg_attr( feature = "no-panic" , no_panic) ]
50
- pub fn format < F : Float > ( & mut self , f : F ) -> & str {
74
+ pub fn format_finite < F : Float > ( & mut self , f : F ) -> & str {
51
75
unsafe {
52
76
let n = f. write_to_ryu_buffer ( & mut self . bytes [ 0 ] ) ;
53
77
debug_assert ! ( n <= self . bytes. len( ) ) ;
@@ -74,11 +98,35 @@ pub trait Float: Sealed {}
74
98
impl Float for f32 { }
75
99
impl Float for f64 { }
76
100
77
- pub trait Sealed {
101
+ pub trait Sealed : Copy {
102
+ fn is_nonfinite ( self ) -> bool ;
103
+ fn format_nonfinite ( self ) -> & ' static str ;
78
104
unsafe fn write_to_ryu_buffer ( self , result : * mut u8 ) -> usize ;
79
105
}
80
106
81
107
impl Sealed for f32 {
108
+ #[ inline]
109
+ #[ cfg_attr( feature = "no-panic" , no_panic) ]
110
+ fn is_nonfinite ( self ) -> bool {
111
+ const EXP_MASK : u32 = 0x7f800000 ;
112
+ let bits = unsafe { mem:: transmute :: < f32 , u32 > ( self ) } ;
113
+ bits & EXP_MASK == EXP_MASK
114
+ }
115
+
116
+ #[ cold]
117
+ fn format_nonfinite ( self ) -> & ' static str {
118
+ const MANTISSA_MASK : u32 = 0x007fffff ;
119
+ const SIGN_MASK : u32 = 0x80000000 ;
120
+ let bits = unsafe { mem:: transmute :: < f32 , u32 > ( self ) } ;
121
+ if bits & MANTISSA_MASK != 0 {
122
+ NAN
123
+ } else if bits & SIGN_MASK != 0 {
124
+ NEG_INFINITY
125
+ } else {
126
+ INFINITY
127
+ }
128
+ }
129
+
82
130
#[ inline]
83
131
#[ cfg_attr( feature = "no-panic" , no_panic) ]
84
132
unsafe fn write_to_ryu_buffer ( self , result : * mut u8 ) -> usize {
@@ -87,6 +135,28 @@ impl Sealed for f32 {
87
135
}
88
136
89
137
impl Sealed for f64 {
138
+ #[ inline]
139
+ #[ cfg_attr( feature = "no-panic" , no_panic) ]
140
+ fn is_nonfinite ( self ) -> bool {
141
+ const EXP_MASK : u64 = 0x7ff0000000000000 ;
142
+ let bits = unsafe { mem:: transmute :: < f64 , u64 > ( self ) } ;
143
+ bits & EXP_MASK == EXP_MASK
144
+ }
145
+
146
+ #[ cold]
147
+ fn format_nonfinite ( self ) -> & ' static str {
148
+ const MANTISSA_MASK : u64 = 0x000fffffffffffff ;
149
+ const SIGN_MASK : u64 = 0x8000000000000000 ;
150
+ let bits = unsafe { mem:: transmute :: < f64 , u64 > ( self ) } ;
151
+ if bits & MANTISSA_MASK != 0 {
152
+ NAN
153
+ } else if bits & SIGN_MASK != 0 {
154
+ NEG_INFINITY
155
+ } else {
156
+ INFINITY
157
+ }
158
+ }
159
+
90
160
#[ inline]
91
161
#[ cfg_attr( feature = "no-panic" , no_panic) ]
92
162
unsafe fn write_to_ryu_buffer ( self , result : * mut u8 ) -> usize {
0 commit comments