const_ryu/pretty/
mod.rs

1mod exponent;
2mod mantissa;
3
4use self::exponent::{write_exponent2, write_exponent3};
5use self::mantissa::{write_mantissa, write_mantissa_long};
6use crate::common;
7use crate::d2s::{self, d2d, DOUBLE_EXPONENT_BITS, DOUBLE_MANTISSA_BITS};
8use crate::f2s::{f2d, FLOAT_EXPONENT_BITS, FLOAT_MANTISSA_BITS};
9use core::ptr;
10#[cfg(feature = "no-panic")]
11use no_panic::no_panic;
12
13macro_rules! const_for_in_range_full {
14    (for $i:ident in $range_start:tt..$range_end:tt $body:block) => {{
15        let mut $i = $range_start;
16
17        while $i < $range_end {
18            $body
19            $i += 1;
20        }
21    }};
22}
23
24/// Print f64 to the given buffer and return number of bytes written.
25///
26/// At most 24 bytes will be written.
27///
28/// ## Special cases
29///
30/// This function **does not** check for NaN or infinity. If the input
31/// number is not a finite float, the printed representation will be some
32/// correctly formatted but unspecified numerical value.
33///
34/// Please check [`is_finite`] yourself before calling this function, or
35/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
36///
37/// [`is_finite`]: f64::is_finite
38/// [`is_nan`]: f64::is_nan
39/// [`is_infinite`]: f64::is_infinite
40///
41/// ## Safety
42///
43/// The `result` pointer argument must point to sufficiently many writable bytes
44/// to hold Ryū's representation of `f`.
45///
46/// ## Example
47///
48/// ```
49/// use std::{mem::MaybeUninit, slice, str};
50///
51/// let f = 1.234f64;
52///
53/// unsafe {
54///     let mut buffer = [MaybeUninit::<u8>::uninit(); 24];
55///     let len = const_ryu::raw::format64(f, buffer.as_mut_ptr() as *mut u8);
56///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
57///     let print = str::from_utf8_unchecked(slice);
58///     assert_eq!(print, "1.234");
59/// }
60/// ```
61#[must_use]
62#[cfg_attr(feature = "no-panic", no_panic)]
63pub const unsafe fn format64(f: f64, result: *mut u8) -> usize {
64    let bits = f.to_bits();
65    let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
66    let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
67    let ieee_exponent =
68        (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
69
70    let mut index = 0isize;
71    if sign {
72        *result = b'-';
73        index += 1;
74    }
75
76    if ieee_exponent == 0 && ieee_mantissa == 0 {
77        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
78        return sign as usize + 3;
79    }
80
81    let v = d2d(ieee_mantissa, ieee_exponent);
82
83    let length = d2s::decimal_length17(v.mantissa) as isize;
84    let k = v.exponent as isize;
85    let kk = length + k; // 10^(kk-1) <= v < 10^kk
86    if true {
    if !(k >= -324) {
        ::core::panicking::panic("assertion failed: k >= -324")
    };
};debug_assert!(k >= -324);
87
88    if 0 <= k && kk <= 16 {
89        // 1234e7 -> 12340000000.0
90        write_mantissa_long(v.mantissa, result.offset(index + length));
91
92        {
    let mut i = length;
    while i < kk { { *result.offset(index + i) = b'0'; } i += 1; }
}const_for_in_range_full! {
93        for i in length..kk {
94            *result.offset(index + i) = b'0';
95        }
96        }
97
98        *result.offset(index + kk) = b'.';
99        *result.offset(index + kk + 1) = b'0';
100        index as usize + kk as usize + 2
101    } else if 0 < kk && kk <= 16 {
102        // 1234e-2 -> 12.34
103        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
104        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
105        *result.offset(index + kk) = b'.';
106        index as usize + length as usize + 1
107    } else if -5 < kk && kk <= 0 {
108        // 1234e-6 -> 0.001234
109        *result.offset(index) = b'0';
110        *result.offset(index + 1) = b'.';
111        let offset = 2 - kk;
112
113        {
    let mut i = 2;
    while i < offset { { *result.offset(index + i) = b'0'; } i += 1; }
}const_for_in_range_full! {
114        for i in 2..offset {
115            *result.offset(index + i) = b'0';
116        }
117        }
118
119        write_mantissa_long(v.mantissa, result.offset(index + length + offset));
120        index as usize + length as usize + offset as usize
121    } else if length == 1 {
122        // 1e30
123        *result.offset(index) = b'0' + v.mantissa as u8;
124        *result.offset(index + 1) = b'e';
125        index as usize + 2 + write_exponent3(kk - 1, result.offset(index + 2))
126    } else {
127        // 1234e30 -> 1.234e33
128        write_mantissa_long(v.mantissa, result.offset(index + length + 1));
129        *result.offset(index) = *result.offset(index + 1);
130        *result.offset(index + 1) = b'.';
131        *result.offset(index + length + 1) = b'e';
132        index as usize
133            + length as usize
134            + 2
135            + write_exponent3(kk - 1, result.offset(index + length + 2))
136    }
137}
138
139/// Print f32 to the given buffer and return number of bytes written.
140///
141/// At most 16 bytes will be written.
142///
143/// ## Special cases
144///
145/// This function **does not** check for NaN or infinity. If the input
146/// number is not a finite float, the printed representation will be some
147/// correctly formatted but unspecified numerical value.
148///
149/// Please check [`is_finite`] yourself before calling this function, or
150/// check [`is_nan`] and [`is_infinite`] and handle those cases yourself.
151///
152/// [`is_finite`]: f32::is_finite
153/// [`is_nan`]: f32::is_nan
154/// [`is_infinite`]: f32::is_infinite
155///
156/// ## Safety
157///
158/// The `result` pointer argument must point to sufficiently many writable bytes
159/// to hold Ryū's representation of `f`.
160///
161/// ## Example
162///
163/// ```
164/// use std::{mem::MaybeUninit, slice, str};
165///
166/// let f = 1.234f32;
167///
168/// unsafe {
169///     let mut buffer = [MaybeUninit::<u8>::uninit(); 16];
170///     let len = const_ryu::raw::format32(f, buffer.as_mut_ptr() as *mut u8);
171///     let slice = slice::from_raw_parts(buffer.as_ptr() as *const u8, len);
172///     let print = str::from_utf8_unchecked(slice);
173///     assert_eq!(print, "1.234");
174/// }
175/// ```
176#[must_use]
177#[cfg_attr(feature = "no-panic", no_panic)]
178pub const unsafe fn format32(f: f32, result: *mut u8) -> usize {
179    let bits = f.to_bits();
180    let sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
181    let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
182    let ieee_exponent = (bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1);
183
184    let mut index = 0isize;
185    if sign {
186        *result = b'-';
187        index += 1;
188    }
189
190    if ieee_exponent == 0 && ieee_mantissa == 0 {
191        ptr::copy_nonoverlapping(b"0.0".as_ptr(), result.offset(index), 3);
192        return sign as usize + 3;
193    }
194
195    let v = f2d(ieee_mantissa, ieee_exponent);
196
197    let length = common::decimal_length9(v.mantissa) as isize;
198    let k = v.exponent as isize;
199    let kk = length + k; // 10^(kk-1) <= v < 10^kk
200    if true {
    if !(k >= -45) { ::core::panicking::panic("assertion failed: k >= -45") };
};debug_assert!(k >= -45);
201
202    if 0 <= k && kk <= 13 {
203        // 1234e7 -> 12340000000.0
204        write_mantissa(v.mantissa, result.offset(index + length));
205
206        {
    let mut i = length;
    while i < kk { { *result.offset(index + i) = b'0'; } i += 1; }
}const_for_in_range_full! {
207        for i in length..kk {
208            *result.offset(index + i) = b'0';
209        }
210        }
211
212        *result.offset(index + kk) = b'.';
213        *result.offset(index + kk + 1) = b'0';
214        index as usize + kk as usize + 2
215    } else if 0 < kk && kk <= 13 {
216        // 1234e-2 -> 12.34
217        write_mantissa(v.mantissa, result.offset(index + length + 1));
218        ptr::copy(result.offset(index + 1), result.offset(index), kk as usize);
219        *result.offset(index + kk) = b'.';
220        index as usize + length as usize + 1
221    } else if -6 < kk && kk <= 0 {
222        // 1234e-6 -> 0.001234
223        *result.offset(index) = b'0';
224        *result.offset(index + 1) = b'.';
225        let offset = 2 - kk;
226
227        {
    let mut i = 2;
    while i < offset { { *result.offset(index + i) = b'0'; } i += 1; }
}const_for_in_range_full! {
228        for i in 2..offset {
229            *result.offset(index + i) = b'0';
230        }
231        }
232
233        write_mantissa(v.mantissa, result.offset(index + length + offset));
234        index as usize + length as usize + offset as usize
235    } else if length == 1 {
236        // 1e30
237        *result.offset(index) = b'0' + v.mantissa as u8;
238        *result.offset(index + 1) = b'e';
239        index as usize + 2 + write_exponent2(kk - 1, result.offset(index + 2))
240    } else {
241        // 1234e30 -> 1.234e33
242        write_mantissa(v.mantissa, result.offset(index + length + 1));
243        *result.offset(index) = *result.offset(index + 1);
244        *result.offset(index + 1) = b'.';
245        *result.offset(index + length + 1) = b'e';
246        index as usize
247            + length as usize
248            + 2
249            + write_exponent2(kk - 1, result.offset(index + length + 2))
250    }
251}