]> git.lizzy.rs Git - rust.git/blob - src/libcore/fmt/float.rs
Rollup merge of #69569 - matthiaskrgr:nonminimal_bool, r=mark-Simulacrum
[rust.git] / src / libcore / fmt / float.rs
1 use crate::fmt::{Debug, Display, Formatter, LowerExp, Result, UpperExp};
2 use crate::mem::MaybeUninit;
3 use crate::num::flt2dec;
4
5 // ignore-tidy-undocumented-unsafe
6
7 // Don't inline this so callers don't use the stack space this function
8 // requires unless they have to.
9 #[inline(never)]
10 fn float_to_decimal_common_exact<T>(
11     fmt: &mut Formatter<'_>,
12     num: &T,
13     sign: flt2dec::Sign,
14     precision: usize,
15 ) -> Result
16 where
17     T: flt2dec::DecodableFloat,
18 {
19     unsafe {
20         let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
21         let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
22         // FIXME(#53491): This is calling `get_mut` on an uninitialized
23         // `MaybeUninit` (here and elsewhere in this file). Revisit this once
24         // we decided whether that is valid or not.
25         // We can do this only because we are libstd and coupled to the compiler.
26         // (FWIW, using `freeze` would not be enough; `flt2dec::Part` is an enum!)
27         let formatted = flt2dec::to_exact_fixed_str(
28             flt2dec::strategy::grisu::format_exact,
29             *num,
30             sign,
31             precision,
32             buf.get_mut(),
33             parts.get_mut(),
34         );
35         fmt.pad_formatted_parts(&formatted)
36     }
37 }
38
39 // Don't inline this so callers that call both this and the above won't wind
40 // up using the combined stack space of both functions in some cases.
41 #[inline(never)]
42 fn float_to_decimal_common_shortest<T>(
43     fmt: &mut Formatter<'_>,
44     num: &T,
45     sign: flt2dec::Sign,
46     precision: usize,
47 ) -> Result
48 where
49     T: flt2dec::DecodableFloat,
50 {
51     unsafe {
52         // enough for f32 and f64
53         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
54         let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
55         // FIXME(#53491)
56         let formatted = flt2dec::to_shortest_str(
57             flt2dec::strategy::grisu::format_shortest,
58             *num,
59             sign,
60             precision,
61             buf.get_mut(),
62             parts.get_mut(),
63         );
64         fmt.pad_formatted_parts(&formatted)
65     }
66 }
67
68 // Common code of floating point Debug and Display.
69 fn float_to_decimal_common<T>(
70     fmt: &mut Formatter<'_>,
71     num: &T,
72     negative_zero: bool,
73     min_precision: usize,
74 ) -> Result
75 where
76     T: flt2dec::DecodableFloat,
77 {
78     let force_sign = fmt.sign_plus();
79     let sign = match (force_sign, negative_zero) {
80         (false, false) => flt2dec::Sign::Minus,
81         (false, true) => flt2dec::Sign::MinusRaw,
82         (true, false) => flt2dec::Sign::MinusPlus,
83         (true, true) => flt2dec::Sign::MinusPlusRaw,
84     };
85
86     if let Some(precision) = fmt.precision {
87         float_to_decimal_common_exact(fmt, num, sign, precision)
88     } else {
89         float_to_decimal_common_shortest(fmt, num, sign, min_precision)
90     }
91 }
92
93 // Don't inline this so callers don't use the stack space this function
94 // requires unless they have to.
95 #[inline(never)]
96 fn float_to_exponential_common_exact<T>(
97     fmt: &mut Formatter<'_>,
98     num: &T,
99     sign: flt2dec::Sign,
100     precision: usize,
101     upper: bool,
102 ) -> Result
103 where
104     T: flt2dec::DecodableFloat,
105 {
106     unsafe {
107         let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
108         let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
109         // FIXME(#53491)
110         let formatted = flt2dec::to_exact_exp_str(
111             flt2dec::strategy::grisu::format_exact,
112             *num,
113             sign,
114             precision,
115             upper,
116             buf.get_mut(),
117             parts.get_mut(),
118         );
119         fmt.pad_formatted_parts(&formatted)
120     }
121 }
122
123 // Don't inline this so callers that call both this and the above won't wind
124 // up using the combined stack space of both functions in some cases.
125 #[inline(never)]
126 fn float_to_exponential_common_shortest<T>(
127     fmt: &mut Formatter<'_>,
128     num: &T,
129     sign: flt2dec::Sign,
130     upper: bool,
131 ) -> Result
132 where
133     T: flt2dec::DecodableFloat,
134 {
135     unsafe {
136         // enough for f32 and f64
137         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
138         let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
139         // FIXME(#53491)
140         let formatted = flt2dec::to_shortest_exp_str(
141             flt2dec::strategy::grisu::format_shortest,
142             *num,
143             sign,
144             (0, 0),
145             upper,
146             buf.get_mut(),
147             parts.get_mut(),
148         );
149         fmt.pad_formatted_parts(&formatted)
150     }
151 }
152
153 // Common code of floating point LowerExp and UpperExp.
154 fn float_to_exponential_common<T>(fmt: &mut Formatter<'_>, num: &T, upper: bool) -> Result
155 where
156     T: flt2dec::DecodableFloat,
157 {
158     let force_sign = fmt.sign_plus();
159     let sign = match force_sign {
160         false => flt2dec::Sign::Minus,
161         true => flt2dec::Sign::MinusPlus,
162     };
163
164     if let Some(precision) = fmt.precision {
165         // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
166         float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
167     } else {
168         float_to_exponential_common_shortest(fmt, num, sign, upper)
169     }
170 }
171
172 macro_rules! floating {
173     ($ty:ident) => {
174         #[stable(feature = "rust1", since = "1.0.0")]
175         impl Debug for $ty {
176             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
177                 float_to_decimal_common(fmt, self, true, 1)
178             }
179         }
180
181         #[stable(feature = "rust1", since = "1.0.0")]
182         impl Display for $ty {
183             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
184                 float_to_decimal_common(fmt, self, false, 0)
185             }
186         }
187
188         #[stable(feature = "rust1", since = "1.0.0")]
189         impl LowerExp for $ty {
190             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
191                 float_to_exponential_common(fmt, self, false)
192             }
193         }
194
195         #[stable(feature = "rust1", since = "1.0.0")]
196         impl UpperExp for $ty {
197             fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
198                 float_to_exponential_common(fmt, self, true)
199             }
200         }
201     };
202 }
203
204 floating! { f32 }
205 floating! { f64 }