mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
num: Move user-public float parsing items directly under core::num
Follow up to the previous commit refactoring `core::num` by moving the user-facing error types and trait implementations back out of `imp` and into a new module under `core::num`.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
//! User-facing API for float parsing.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::fmt;
|
||||
use crate::num::imp::dec2flt;
|
||||
use crate::str::FromStr;
|
||||
|
||||
macro_rules! from_str_float_impl {
|
||||
($t:ty) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromStr for $t {
|
||||
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).
|
||||
// We add the `#[inline(never)]` attribute, since its content will
|
||||
// be filled with that of `dec2flt`, which has #[inline(always)].
|
||||
// Since `dec2flt` is generic, a normal inline attribute on this function
|
||||
// with `dec2flt` having no attributes results in heavily repeated
|
||||
// generation of `dec2flt`, despite the fact only a maximum of 2
|
||||
// possible instances can ever exist. Adding #[inline(never)] avoids this.
|
||||
#[inline(never)]
|
||||
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
|
||||
dec2flt::dec2flt(src)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
from_str_float_impl!(f16);
|
||||
from_str_float_impl!(f32);
|
||||
from_str_float_impl!(f64);
|
||||
|
||||
// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
|
||||
// to avoid ICEs.
|
||||
|
||||
#[cfg(not(target_has_reliable_f16))]
|
||||
#[expect(ineffective_unstable_trait_impl, reason = "stable trait on unstable type")]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
impl FromStr for f16 {
|
||||
type Err = ParseFloatError;
|
||||
|
||||
#[inline]
|
||||
fn from_str(_src: &str) -> Result<Self, ParseFloatError> {
|
||||
unimplemented!("requires target_has_reliable_f16")
|
||||
}
|
||||
}
|
||||
|
||||
/// An error which can be returned when parsing a float.
|
||||
///
|
||||
/// This error is used as the error type for the [`FromStr`] implementation
|
||||
/// for [`f32`] and [`f64`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// if let Err(e) = f64::from_str("a.12") {
|
||||
/// println!("Failed conversion to f64: {e}");
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct ParseFloatError {
|
||||
pub(super) kind: FloatErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(super) enum FloatErrorKind {
|
||||
Empty,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for ParseFloatError {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for ParseFloatError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
FloatErrorKind::Empty => "cannot parse float from empty string",
|
||||
FloatErrorKind::Invalid => "invalid float literal",
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
@@ -87,14 +87,14 @@
|
||||
issue = "none"
|
||||
)]
|
||||
|
||||
use self::common::BiasedFp;
|
||||
use self::float::RawFloat;
|
||||
use self::lemire::compute_float;
|
||||
use self::parse::{parse_inf_nan, parse_number};
|
||||
use self::slow::parse_long_mantissa;
|
||||
use crate::error::Error;
|
||||
use crate::fmt;
|
||||
use crate::str::FromStr;
|
||||
use common::BiasedFp;
|
||||
use float::RawFloat;
|
||||
use lemire::compute_float;
|
||||
use parse::{parse_inf_nan, parse_number};
|
||||
use slow::parse_long_mantissa;
|
||||
|
||||
use crate::num::ParseFloatError;
|
||||
use crate::num::float_parse::FloatErrorKind;
|
||||
|
||||
mod common;
|
||||
pub mod decimal;
|
||||
@@ -107,131 +107,6 @@
|
||||
pub mod lemire;
|
||||
pub mod parse;
|
||||
|
||||
macro_rules! from_str_float_impl {
|
||||
($t:ty) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl FromStr for $t {
|
||||
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).
|
||||
// We add the `#[inline(never)]` attribute, since its content will
|
||||
// be filled with that of `dec2flt`, which has #[inline(always)].
|
||||
// Since `dec2flt` is generic, a normal inline attribute on this function
|
||||
// with `dec2flt` having no attributes results in heavily repeated
|
||||
// generation of `dec2flt`, despite the fact only a maximum of 2
|
||||
// possible instances can ever exist. Adding #[inline(never)] avoids this.
|
||||
#[inline(never)]
|
||||
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
|
||||
dec2flt(src)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
from_str_float_impl!(f16);
|
||||
from_str_float_impl!(f32);
|
||||
from_str_float_impl!(f64);
|
||||
|
||||
// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
|
||||
// to avoid ICEs.
|
||||
|
||||
#[cfg(not(target_has_reliable_f16))]
|
||||
impl FromStr for f16 {
|
||||
type Err = ParseFloatError;
|
||||
|
||||
#[inline]
|
||||
fn from_str(_src: &str) -> Result<Self, ParseFloatError> {
|
||||
unimplemented!("requires target_has_reliable_f16")
|
||||
}
|
||||
}
|
||||
|
||||
/// An error which can be returned when parsing a float.
|
||||
///
|
||||
/// This error is used as the error type for the [`FromStr`] implementation
|
||||
/// for [`f32`] and [`f64`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// if let Err(e) = f64::from_str("a.12") {
|
||||
/// println!("Failed conversion to f64: {e}");
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct ParseFloatError {
|
||||
kind: FloatErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
enum FloatErrorKind {
|
||||
Empty,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Error for ParseFloatError {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for ParseFloatError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.kind {
|
||||
FloatErrorKind::Empty => "cannot parse float from empty string",
|
||||
FloatErrorKind::Invalid => "invalid float literal",
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn pfe_empty() -> ParseFloatError {
|
||||
ParseFloatError { kind: FloatErrorKind::Empty }
|
||||
|
||||
@@ -42,6 +42,8 @@ macro_rules! sign_dependent_expr {
|
||||
mod uint_macros; // import uint_impl!
|
||||
|
||||
mod error;
|
||||
#[cfg(not(no_fp_fmt_parse))]
|
||||
mod float_parse;
|
||||
mod nonzero;
|
||||
mod saturating;
|
||||
mod wrapping;
|
||||
@@ -58,7 +60,7 @@ macro_rules! sign_dependent_expr {
|
||||
pub use error::TryFromIntError;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg(not(no_fp_fmt_parse))]
|
||||
pub use imp::dec2flt::ParseFloatError;
|
||||
pub use float_parse::ParseFloatError;
|
||||
#[stable(feature = "generic_nonzero", since = "1.79.0")]
|
||||
pub use nonzero::NonZero;
|
||||
#[unstable(
|
||||
|
||||
@@ -21,7 +21,7 @@ pub unsafe fn add(a: u8, b: u8) -> u8 {
|
||||
// CHECK: i8 noundef{{( zeroext)?}} %a, i8 noundef{{( zeroext)?}} %b
|
||||
// CHECK: add i8 %b, %a
|
||||
// DEBUG: icmp ult i8 [[zero:[^,]+]], %a
|
||||
// DEBUG: call core::num::overflow_panic::add
|
||||
// DEBUG: call core::num::imp::overflow_panic::add
|
||||
// DEBUG: unreachable
|
||||
// NOCHECKS-NOT: unreachable
|
||||
// NOCHECKS: ret i8 %0
|
||||
|
||||
Reference in New Issue
Block a user