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)]
76#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for f16 {
    type Err = ParseFloatError;
    /// Converts a string in base 10 to a float.
    /// Accepts an optional decimal exponent.
    ///
    /// This function accepts strings such as
    ///
    /// * '3.14'
    /// * '-3.14'
    /// * '2.5E10', or equivalently, '2.5e10'
    /// * '2.5E-10'
    /// * '5.'
    /// * '.5', or, equivalently, '0.5'
    /// * '7'
    /// * '007'
    /// * 'inf', '-inf', '+infinity', 'NaN'
    ///
    /// Note that alphabetical characters are not case-sensitive.
    ///
    /// Leading and trailing whitespace represent an error.
    ///
    /// # Grammar
    ///
    /// All strings that adhere to the following [EBNF] grammar when
    /// lowercased will result in an [`Ok`] being returned:
    ///
    /// ```txt
    /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
    /// Number ::= ( Digit+ |
    ///              Digit+ '.' Digit* |
    ///              Digit* '.' Digit+ ) Exp?
    /// Exp    ::= 'e' Sign? Digit+
    /// Sign   ::= [+-]
    /// Digit  ::= [0-9]
    /// ```
    ///
    /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
    ///
    /// # Arguments
    ///
    /// * src - A string
    ///
    /// # Return value
    ///
    /// `Err(ParseFloatError)` if the string did not represent a valid
    /// number. Otherwise, `Ok(n)` where `n` is the closest
    /// representable floating-point number to the number represented
    /// by `src` (following the same rules for rounding as for the
    /// results of primitive operations).
    #[inline(never)]
    fn from_str(src: &str) -> Result<Self, ParseFloatError> {
        dec2flt::dec2flt(src)
    }
}from_str_float_impl!(f16);
77#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for f32 {
    type Err = ParseFloatError;
    /// Converts a string in base 10 to a float.
    /// Accepts an optional decimal exponent.
    ///
    /// This function accepts strings such as
    ///
    /// * '3.14'
    /// * '-3.14'
    /// * '2.5E10', or equivalently, '2.5e10'
    /// * '2.5E-10'
    /// * '5.'
    /// * '.5', or, equivalently, '0.5'
    /// * '7'
    /// * '007'
    /// * 'inf', '-inf', '+infinity', 'NaN'
    ///
    /// Note that alphabetical characters are not case-sensitive.
    ///
    /// Leading and trailing whitespace represent an error.
    ///
    /// # Grammar
    ///
    /// All strings that adhere to the following [EBNF] grammar when
    /// lowercased will result in an [`Ok`] being returned:
    ///
    /// ```txt
    /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
    /// Number ::= ( Digit+ |
    ///              Digit+ '.' Digit* |
    ///              Digit* '.' Digit+ ) Exp?
    /// Exp    ::= 'e' Sign? Digit+
    /// Sign   ::= [+-]
    /// Digit  ::= [0-9]
    /// ```
    ///
    /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
    ///
    /// # Arguments
    ///
    /// * src - A string
    ///
    /// # Return value
    ///
    /// `Err(ParseFloatError)` if the string did not represent a valid
    /// number. Otherwise, `Ok(n)` where `n` is the closest
    /// representable floating-point number to the number represented
    /// by `src` (following the same rules for rounding as for the
    /// results of primitive operations).
    #[inline(never)]
    fn from_str(src: &str) -> Result<Self, ParseFloatError> {
        dec2flt::dec2flt(src)
    }
}from_str_float_impl!(f32);
78#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for f64 {
    type Err = ParseFloatError;
    /// Converts a string in base 10 to a float.
    /// Accepts an optional decimal exponent.
    ///
    /// This function accepts strings such as
    ///
    /// * '3.14'
    /// * '-3.14'
    /// * '2.5E10', or equivalently, '2.5e10'
    /// * '2.5E-10'
    /// * '5.'
    /// * '.5', or, equivalently, '0.5'
    /// * '7'
    /// * '007'
    /// * 'inf', '-inf', '+infinity', 'NaN'
    ///
    /// Note that alphabetical characters are not case-sensitive.
    ///
    /// Leading and trailing whitespace represent an error.
    ///
    /// # Grammar
    ///
    /// All strings that adhere to the following [EBNF] grammar when
    /// lowercased will result in an [`Ok`] being returned:
    ///
    /// ```txt
    /// Float  ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
    /// Number ::= ( Digit+ |
    ///              Digit+ '.' Digit* |
    ///              Digit* '.' Digit+ ) Exp?
    /// Exp    ::= 'e' Sign? Digit+
    /// Sign   ::= [+-]
    /// Digit  ::= [0-9]
    /// ```
    ///
    /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
    ///
    /// # Arguments
    ///
    /// * src - A string
    ///
    /// # Return value
    ///
    /// `Err(ParseFloatError)` if the string did not represent a valid
    /// number. Otherwise, `Ok(n)` where `n` is the closest
    /// representable floating-point number to the number represented
    /// by `src` (following the same rules for rounding as for the
    /// results of primitive operations).
    #[inline(never)]
    fn from_str(src: &str) -> Result<Self, ParseFloatError> {
        dec2flt::dec2flt(src)
    }
}from_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(#[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::fmt::Debug for ParseFloatError {
    #[inline]
    fn fmt(&self, f: &mut crate::fmt::Formatter) -> crate::fmt::Result {
        crate::fmt::Formatter::debug_struct_field1_finish(f,
            "ParseFloatError", "kind", &&self.kind)
    }
}Debug, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::clone::Clone for ParseFloatError {
    #[inline]
    fn clone(&self) -> ParseFloatError {
        ParseFloatError { kind: crate::clone::Clone::clone(&self.kind) }
    }
}Clone, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::cmp::PartialEq for ParseFloatError {
    #[inline]
    fn eq(&self, other: &ParseFloatError) -> bool { self.kind == other.kind }
}PartialEq, #[automatically_derived]
#[stable(feature = "rust1", since = "1.0.0")]
impl crate::cmp::Eq for ParseFloatError {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: crate::cmp::AssertParamIsEq<FloatErrorKind>;
    }
}Eq)]
110#[stable(feature = "rust1", since = "1.0.0")]
111pub struct ParseFloatError {
112    pub(super) kind: FloatErrorKind,
113}
114
115#[derive(#[automatically_derived]
impl crate::fmt::Debug for FloatErrorKind {
    #[inline]
    fn fmt(&self, f: &mut crate::fmt::Formatter) -> crate::fmt::Result {
        crate::fmt::Formatter::write_str(f,
            match self {
                FloatErrorKind::Empty => "Empty",
                FloatErrorKind::Invalid => "Invalid",
            })
    }
}Debug, #[automatically_derived]
impl crate::clone::Clone for FloatErrorKind {
    #[inline]
    fn clone(&self) -> FloatErrorKind {
        match self {
            FloatErrorKind::Empty => FloatErrorKind::Empty,
            FloatErrorKind::Invalid => FloatErrorKind::Invalid,
        }
    }
}Clone, #[automatically_derived]
impl crate::cmp::PartialEq for FloatErrorKind {
    #[inline]
    fn eq(&self, other: &FloatErrorKind) -> bool {
        let __self_discr = crate::intrinsics::discriminant_value(self);
        let __arg1_discr = crate::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl crate::cmp::Eq for FloatErrorKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}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}