]> git.lizzy.rs Git - rust.git/blob - src/libcore/fmt/float.rs
Auto merge of #57714 - matthewjasper:wellformed-unreachable, r=pnkfelix
[rust.git] / src / libcore / fmt / float.rs
1 use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
2 use mem::MaybeUninit;
3 use num::flt2dec;
4
5 // Don't inline this so callers don't use the stack space this function
6 // requires unless they have to.
7 #[inline(never)]
8 fn float_to_decimal_common_exact<T>(fmt: &mut Formatter, num: &T,
9                                     sign: flt2dec::Sign, precision: usize) -> Result
10     where T: flt2dec::DecodableFloat
11 {
12     unsafe {
13         let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
14         let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
15         // FIXME(#53491): Technically, this is calling `get_mut` on an uninitialized
16         // `MaybeUninit` (here and elsewhere in this file).  Revisit this once
17         // we decided whether that is valid or not.
18         let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact,
19                                                     *num, sign, precision,
20                                                     false, buf.get_mut(), parts.get_mut());
21         fmt.pad_formatted_parts(&formatted)
22     }
23 }
24
25 // Don't inline this so callers that call both this and the above won't wind
26 // up using the combined stack space of both functions in some cases.
27 #[inline(never)]
28 fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter, num: &T,
29                                        sign: flt2dec::Sign, precision: usize) -> Result
30     where T: flt2dec::DecodableFloat
31 {
32     unsafe {
33         // enough for f32 and f64
34         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
35         let mut parts = MaybeUninit::<[flt2dec::Part; 4]>::uninitialized();
36         let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num,
37                                                  sign, precision, false, buf.get_mut(),
38                                                  parts.get_mut());
39         fmt.pad_formatted_parts(&formatted)
40     }
41 }
42
43 // Common code of floating point Debug and Display.
44 fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T,
45                               negative_zero: bool, min_precision: usize) -> Result
46     where T: flt2dec::DecodableFloat
47 {
48     let force_sign = fmt.sign_plus();
49     let sign = match (force_sign, negative_zero) {
50         (false, false) => flt2dec::Sign::Minus,
51         (false, true)  => flt2dec::Sign::MinusRaw,
52         (true,  false) => flt2dec::Sign::MinusPlus,
53         (true,  true)  => flt2dec::Sign::MinusPlusRaw,
54     };
55
56     if let Some(precision) = fmt.precision {
57         float_to_decimal_common_exact(fmt, num, sign, precision)
58     } else {
59         float_to_decimal_common_shortest(fmt, num, sign, min_precision)
60     }
61 }
62
63 // Don't inline this so callers don't use the stack space this function
64 // requires unless they have to.
65 #[inline(never)]
66 fn float_to_exponential_common_exact<T>(fmt: &mut Formatter, num: &T,
67                                         sign: flt2dec::Sign, precision: usize,
68                                         upper: bool) -> Result
69     where T: flt2dec::DecodableFloat
70 {
71     unsafe {
72         let mut buf = MaybeUninit::<[u8; 1024]>::uninitialized(); // enough for f32 and f64
73         let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
74         let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact,
75                                                   *num, sign, precision,
76                                                   upper, buf.get_mut(), parts.get_mut());
77         fmt.pad_formatted_parts(&formatted)
78     }
79 }
80
81 // Don't inline this so callers that call both this and the above won't wind
82 // up using the combined stack space of both functions in some cases.
83 #[inline(never)]
84 fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter,
85                                            num: &T, sign: flt2dec::Sign,
86                                            upper: bool) -> Result
87     where T: flt2dec::DecodableFloat
88 {
89     unsafe {
90         // enough for f32 and f64
91         let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninitialized();
92         let mut parts = MaybeUninit::<[flt2dec::Part; 6]>::uninitialized();
93         let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest,
94                                                      *num, sign, (0, 0), upper,
95                                                      buf.get_mut(), parts.get_mut());
96         fmt.pad_formatted_parts(&formatted)
97     }
98 }
99
100 // Common code of floating point LowerExp and UpperExp.
101 fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result
102     where T: flt2dec::DecodableFloat
103 {
104     let force_sign = fmt.sign_plus();
105     let sign = match force_sign {
106         false => flt2dec::Sign::Minus,
107         true  => flt2dec::Sign::MinusPlus,
108     };
109
110     if let Some(precision) = fmt.precision {
111         // 1 integral digit + `precision` fractional digits = `precision + 1` total digits
112         float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper)
113     } else {
114         float_to_exponential_common_shortest(fmt, num, sign, upper)
115     }
116 }
117
118 macro_rules! floating {
119     ($ty:ident) => (
120         #[stable(feature = "rust1", since = "1.0.0")]
121         impl Debug for $ty {
122             fn fmt(&self, fmt: &mut Formatter) -> Result {
123                 float_to_decimal_common(fmt, self, true, 1)
124             }
125         }
126
127         #[stable(feature = "rust1", since = "1.0.0")]
128         impl Display for $ty {
129             fn fmt(&self, fmt: &mut Formatter) -> Result {
130                 float_to_decimal_common(fmt, self, false, 0)
131             }
132         }
133
134         #[stable(feature = "rust1", since = "1.0.0")]
135         impl LowerExp for $ty {
136             fn fmt(&self, fmt: &mut Formatter) -> Result {
137                 float_to_exponential_common(fmt, self, false)
138             }
139         }
140
141         #[stable(feature = "rust1", since = "1.0.0")]
142         impl UpperExp for $ty {
143             fn fmt(&self, fmt: &mut Formatter) -> Result {
144                 float_to_exponential_common(fmt, self, true)
145             }
146         }
147     )
148 }
149
150 floating! { f32 }
151 floating! { f64 }