core/num/float_parse.rs
1//! User-facing API for float parsing.
2
3use crate::error::Error;
4use crate::fmt;
5use crate::num::imp::dec2flt;
6use crate::str::FromStr;
7
8macro_rules! from_str_float_impl {
9 ($t:ty) => {
10 #[stable(feature = "rust1", since = "1.0.0")]
11 impl FromStr for $t {
12 type Err = ParseFloatError;
13
14 /// Converts a string in base 10 to a float.
15 /// Accepts an optional decimal exponent.
16 ///
17 /// This function accepts strings such as
18 ///
19 /// * '3.14'
20 /// * '-3.14'
21 /// * '2.5E10', or equivalently, '2.5e10'
22 /// * '2.5E-10'
23 /// * '5.'
24 /// * '.5', or, equivalently, '0.5'
25 /// * '7'
26 /// * '007'
27 /// * 'inf', '-inf', '+infinity', 'NaN'
28 ///
29 /// Note that alphabetical characters are not case-sensitive.
30 ///
31 /// Leading and trailing whitespace represent an error.
32 ///
33 /// # Grammar
34 ///
35 /// All strings that adhere to the following [EBNF] grammar when
36 /// lowercased will result in an [`Ok`] being returned:
37 ///
38 /// ```txt
39 /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
40 /// Number ::= ( Digit+ |
41 /// Digit+ '.' Digit* |
42 /// Digit* '.' Digit+ ) Exp?
43 /// Exp ::= 'e' Sign? Digit+
44 /// Sign ::= [+-]
45 /// Digit ::= [0-9]
46 /// ```
47 ///
48 /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
49 ///
50 /// # Arguments
51 ///
52 /// * src - A string
53 ///
54 /// # Return value
55 ///
56 /// `Err(ParseFloatError)` if the string did not represent a valid
57 /// number. Otherwise, `Ok(n)` where `n` is the closest
58 /// representable floating-point number to the number represented
59 /// by `src` (following the same rules for rounding as for the
60 /// results of primitive operations).
61 // We add the `#[inline(never)]` attribute, since its content will
62 // be filled with that of `dec2flt`, which has #[inline(always)].
63 // Since `dec2flt` is generic, a normal inline attribute on this function
64 // with `dec2flt` having no attributes results in heavily repeated
65 // generation of `dec2flt`, despite the fact only a maximum of 2
66 // possible instances can ever exist. Adding #[inline(never)] avoids this.
67 #[inline(never)]
68 fn from_str(src: &str) -> Result<Self, ParseFloatError> {
69 dec2flt::dec2flt(src)
70 }
71 }
72 };
73}
74
75#[cfg(target_has_reliable_f16)]
76from_str_float_impl!(f16);
77from_str_float_impl!(f32);
78from_str_float_impl!(f64);
79
80// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
81// to avoid ICEs.
82
83#[cfg(not(target_has_reliable_f16))]
84#[expect(ineffective_unstable_trait_impl, reason = "stable trait on unstable type")]
85#[unstable(feature = "f16", issue = "116909")]
86impl FromStr for f16 {
87 type Err = ParseFloatError;
88
89 #[inline]
90 fn from_str(_src: &str) -> Result<Self, ParseFloatError> {
91 unimplemented!("requires target_has_reliable_f16")
92 }
93}
94
95/// An error which can be returned when parsing a float.
96///
97/// This error is used as the error type for the [`FromStr`] implementation
98/// for [`f32`] and [`f64`].
99///
100/// # Example
101///
102/// ```
103/// use std::str::FromStr;
104///
105/// if let Err(e) = f64::from_str("a.12") {
106/// println!("Failed conversion to f64: {e}");
107/// }
108/// ```
109#[derive(Debug, Clone, PartialEq, Eq)]
110#[stable(feature = "rust1", since = "1.0.0")]
111pub struct ParseFloatError {
112 pub(super) kind: FloatErrorKind,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
116pub(super) enum FloatErrorKind {
117 Empty,
118 Invalid,
119}
120
121#[stable(feature = "rust1", since = "1.0.0")]
122impl Error for ParseFloatError {}
123
124#[stable(feature = "rust1", since = "1.0.0")]
125impl fmt::Display for ParseFloatError {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self.kind {
128 FloatErrorKind::Empty => "cannot parse float from empty string",
129 FloatErrorKind::Invalid => "invalid float literal",
130 }
131 .fmt(f)
132 }
133}