Skip to main content

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}