Skip to content

Commit 8ecf216

Browse files
committed
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`.
1 parent 2509946 commit 8ecf216

3 files changed

Lines changed: 141 additions & 134 deletions

File tree

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//! User-facing API for float parsing.
2+
3+
use crate::error::Error;
4+
use crate::fmt;
5+
use crate::num::imp::dec2flt;
6+
use crate::str::FromStr;
7+
8+
macro_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+
from_str_float_impl!(f16);
77+
from_str_float_impl!(f32);
78+
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+
impl FromStr for f16 {
85+
type Err = ParseFloatError;
86+
87+
#[inline]
88+
fn from_str(_src: &str) -> Result<Self, ParseFloatError> {
89+
unimplemented!("requires target_has_reliable_f16")
90+
}
91+
}
92+
93+
/// An error which can be returned when parsing a float.
94+
///
95+
/// This error is used as the error type for the [`FromStr`] implementation
96+
/// for [`f32`] and [`f64`].
97+
///
98+
/// # Example
99+
///
100+
/// ```
101+
/// use std::str::FromStr;
102+
///
103+
/// if let Err(e) = f64::from_str("a.12") {
104+
/// println!("Failed conversion to f64: {e}");
105+
/// }
106+
/// ```
107+
#[derive(Debug, Clone, PartialEq, Eq)]
108+
#[stable(feature = "rust1", since = "1.0.0")]
109+
pub struct ParseFloatError {
110+
pub(super) kind: FloatErrorKind,
111+
}
112+
113+
#[derive(Debug, Clone, PartialEq, Eq)]
114+
pub(super) enum FloatErrorKind {
115+
Empty,
116+
Invalid,
117+
}
118+
119+
#[stable(feature = "rust1", since = "1.0.0")]
120+
impl Error for ParseFloatError {}
121+
122+
#[stable(feature = "rust1", since = "1.0.0")]
123+
impl fmt::Display for ParseFloatError {
124+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125+
match self.kind {
126+
FloatErrorKind::Empty => "cannot parse float from empty string",
127+
FloatErrorKind::Invalid => "invalid float literal",
128+
}
129+
.fmt(f)
130+
}
131+
}

library/core/src/num/imp/dec2flt/mod.rs

Lines changed: 8 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,14 @@
8787
issue = "none"
8888
)]
8989

90-
use self::common::BiasedFp;
91-
use self::float::RawFloat;
92-
use self::lemire::compute_float;
93-
use self::parse::{parse_inf_nan, parse_number};
94-
use self::slow::parse_long_mantissa;
95-
use crate::error::Error;
96-
use crate::fmt;
97-
use crate::str::FromStr;
90+
use common::BiasedFp;
91+
use float::RawFloat;
92+
use lemire::compute_float;
93+
use parse::{parse_inf_nan, parse_number};
94+
use slow::parse_long_mantissa;
95+
96+
use crate::num::ParseFloatError;
97+
use crate::num::float_parse::FloatErrorKind;
9898

9999
mod common;
100100
pub mod decimal;
@@ -107,131 +107,6 @@ pub mod float;
107107
pub mod lemire;
108108
pub mod parse;
109109

110-
macro_rules! from_str_float_impl {
111-
($t:ty) => {
112-
#[stable(feature = "rust1", since = "1.0.0")]
113-
impl FromStr for $t {
114-
type Err = ParseFloatError;
115-
116-
/// Converts a string in base 10 to a float.
117-
/// Accepts an optional decimal exponent.
118-
///
119-
/// This function accepts strings such as
120-
///
121-
/// * '3.14'
122-
/// * '-3.14'
123-
/// * '2.5E10', or equivalently, '2.5e10'
124-
/// * '2.5E-10'
125-
/// * '5.'
126-
/// * '.5', or, equivalently, '0.5'
127-
/// * '7'
128-
/// * '007'
129-
/// * 'inf', '-inf', '+infinity', 'NaN'
130-
///
131-
/// Note that alphabetical characters are not case-sensitive.
132-
///
133-
/// Leading and trailing whitespace represent an error.
134-
///
135-
/// # Grammar
136-
///
137-
/// All strings that adhere to the following [EBNF] grammar when
138-
/// lowercased will result in an [`Ok`] being returned:
139-
///
140-
/// ```txt
141-
/// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number )
142-
/// Number ::= ( Digit+ |
143-
/// Digit+ '.' Digit* |
144-
/// Digit* '.' Digit+ ) Exp?
145-
/// Exp ::= 'e' Sign? Digit+
146-
/// Sign ::= [+-]
147-
/// Digit ::= [0-9]
148-
/// ```
149-
///
150-
/// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
151-
///
152-
/// # Arguments
153-
///
154-
/// * src - A string
155-
///
156-
/// # Return value
157-
///
158-
/// `Err(ParseFloatError)` if the string did not represent a valid
159-
/// number. Otherwise, `Ok(n)` where `n` is the closest
160-
/// representable floating-point number to the number represented
161-
/// by `src` (following the same rules for rounding as for the
162-
/// results of primitive operations).
163-
// We add the `#[inline(never)]` attribute, since its content will
164-
// be filled with that of `dec2flt`, which has #[inline(always)].
165-
// Since `dec2flt` is generic, a normal inline attribute on this function
166-
// with `dec2flt` having no attributes results in heavily repeated
167-
// generation of `dec2flt`, despite the fact only a maximum of 2
168-
// possible instances can ever exist. Adding #[inline(never)] avoids this.
169-
#[inline(never)]
170-
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
171-
dec2flt(src)
172-
}
173-
}
174-
};
175-
}
176-
177-
#[cfg(target_has_reliable_f16)]
178-
from_str_float_impl!(f16);
179-
from_str_float_impl!(f32);
180-
from_str_float_impl!(f64);
181-
182-
// FIXME(f16): A fallback is used when the backend+target does not support f16 well, in order
183-
// to avoid ICEs.
184-
185-
#[cfg(not(target_has_reliable_f16))]
186-
impl FromStr for f16 {
187-
type Err = ParseFloatError;
188-
189-
#[inline]
190-
fn from_str(_src: &str) -> Result<Self, ParseFloatError> {
191-
unimplemented!("requires target_has_reliable_f16")
192-
}
193-
}
194-
195-
/// An error which can be returned when parsing a float.
196-
///
197-
/// This error is used as the error type for the [`FromStr`] implementation
198-
/// for [`f32`] and [`f64`].
199-
///
200-
/// # Example
201-
///
202-
/// ```
203-
/// use std::str::FromStr;
204-
///
205-
/// if let Err(e) = f64::from_str("a.12") {
206-
/// println!("Failed conversion to f64: {e}");
207-
/// }
208-
/// ```
209-
#[derive(Debug, Clone, PartialEq, Eq)]
210-
#[stable(feature = "rust1", since = "1.0.0")]
211-
pub struct ParseFloatError {
212-
kind: FloatErrorKind,
213-
}
214-
215-
#[derive(Debug, Clone, PartialEq, Eq)]
216-
enum FloatErrorKind {
217-
Empty,
218-
Invalid,
219-
}
220-
221-
#[stable(feature = "rust1", since = "1.0.0")]
222-
impl Error for ParseFloatError {}
223-
224-
#[stable(feature = "rust1", since = "1.0.0")]
225-
impl fmt::Display for ParseFloatError {
226-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227-
match self.kind {
228-
FloatErrorKind::Empty => "cannot parse float from empty string",
229-
FloatErrorKind::Invalid => "invalid float literal",
230-
}
231-
.fmt(f)
232-
}
233-
}
234-
235110
#[inline]
236111
pub(super) fn pfe_empty() -> ParseFloatError {
237112
ParseFloatError { kind: FloatErrorKind::Empty }

library/core/src/num/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod int_macros; // import int_impl!
4242
mod uint_macros; // import uint_impl!
4343

4444
mod error;
45+
mod float_parse;
4546
mod nonzero;
4647
mod saturating;
4748
mod wrapping;
@@ -58,7 +59,7 @@ pub use error::ParseIntError;
5859
pub use error::TryFromIntError;
5960
#[stable(feature = "rust1", since = "1.0.0")]
6061
#[cfg(not(no_fp_fmt_parse))]
61-
pub use imp::dec2flt::ParseFloatError;
62+
pub use float_parse::ParseFloatError;
6263
#[stable(feature = "generic_nonzero", since = "1.79.0")]
6364
pub use nonzero::NonZero;
6465
#[unstable(

0 commit comments

Comments
 (0)