Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a2b932c

Browse files
committedAug 18, 2015
core: Shuffle around float parsing
Stop using stability to hide the implementation details of ParseFloatError and instead move the error type into the `dec2flt` module. Also move the implementation blocks of `FromStr for f{32,64}` into `dec2flt` directly.
1 parent 5990249 commit a2b932c

File tree

9 files changed

+133
-138
lines changed

9 files changed

+133
-138
lines changed
 

‎src/libcore/num/dec2flt/mod.rs

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,9 @@
9696
issue = "0")]
9797

9898
use prelude::v1::*;
99-
use num::ParseFloatError as PFE;
100-
use num::FloatErrorKind;
99+
use fmt;
100+
use str::FromStr;
101+
101102
use self::parse::{parse_decimal, Decimal, Sign};
102103
use self::parse::ParseResult::{self, Valid, ShortcutToInf, ShortcutToZero};
103104
use self::num::digits_to_big;
@@ -110,14 +111,87 @@ mod num;
110111
pub mod rawfp;
111112
pub mod parse;
112113

113-
/// Entry point for decimal-to-f32 conversion.
114-
pub fn to_f32(s: &str) -> Result<f32, PFE> {
115-
dec2flt(s)
114+
macro_rules! from_str_float_impl {
115+
($t:ty, $func:ident) => {
116+
#[stable(feature = "rust1", since = "1.0.0")]
117+
impl FromStr for $t {
118+
type Err = ParseFloatError;
119+
120+
/// Converts a string in base 10 to a float.
121+
/// Accepts an optional decimal exponent.
122+
///
123+
/// This function accepts strings such as
124+
///
125+
/// * '3.14'
126+
/// * '-3.14'
127+
/// * '2.5E10', or equivalently, '2.5e10'
128+
/// * '2.5E-10'
129+
/// * '.' (understood as 0)
130+
/// * '5.'
131+
/// * '.5', or, equivalently, '0.5'
132+
/// * 'inf', '-inf', 'NaN'
133+
///
134+
/// Leading and trailing whitespace represent an error.
135+
///
136+
/// # Arguments
137+
///
138+
/// * src - A string
139+
///
140+
/// # Return value
141+
///
142+
/// `Err(ParseFloatError)` if the string did not represent a valid
143+
/// number. Otherwise, `Ok(n)` where `n` is the floating-point
144+
/// number represented by `src`.
145+
#[inline]
146+
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
147+
dec2flt(src)
148+
}
149+
}
150+
}
151+
}
152+
from_str_float_impl!(f32, to_f32);
153+
from_str_float_impl!(f64, to_f64);
154+
155+
/// An error which can be returned when parsing a float.
156+
#[derive(Debug, Clone, PartialEq)]
157+
#[stable(feature = "rust1", since = "1.0.0")]
158+
pub struct ParseFloatError {
159+
kind: FloatErrorKind
160+
}
161+
162+
#[derive(Debug, Clone, PartialEq)]
163+
enum FloatErrorKind {
164+
Empty,
165+
Invalid,
166+
}
167+
168+
impl ParseFloatError {
169+
#[unstable(feature = "int_error_internals",
170+
reason = "available through Error trait and this method should \
171+
not be exposed publicly",
172+
issue = "0")]
173+
#[doc(hidden)]
174+
pub fn __description(&self) -> &str {
175+
match self.kind {
176+
FloatErrorKind::Empty => "cannot parse float from empty string",
177+
FloatErrorKind::Invalid => "invalid float literal",
178+
}
179+
}
180+
}
181+
182+
#[stable(feature = "rust1", since = "1.0.0")]
183+
impl fmt::Display for ParseFloatError {
184+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185+
self.__description().fmt(f)
186+
}
187+
}
188+
189+
pub fn pfe_empty() -> ParseFloatError {
190+
ParseFloatError { kind: FloatErrorKind::Empty }
116191
}
117192

118-
/// Entry point for decimal-to-f64 conversion.
119-
pub fn to_f64(s: &str) -> Result<f64, PFE> {
120-
dec2flt(s)
193+
pub fn pfe_invalid() -> ParseFloatError {
194+
ParseFloatError { kind: FloatErrorKind::Invalid }
121195
}
122196

123197
/// Split decimal string into sign and the rest, without inspecting or validating the rest.
@@ -131,9 +205,9 @@ fn extract_sign(s: &str) -> (Sign, &str) {
131205
}
132206

133207
/// Convert a decimal string into a floating point number.
134-
fn dec2flt<T: RawFloat>(s: &str) -> Result<T, PFE> {
208+
fn dec2flt<T: RawFloat>(s: &str) -> Result<T, ParseFloatError> {
135209
if s.is_empty() {
136-
return Err(PFE { __kind: FloatErrorKind::Empty });
210+
return Err(pfe_empty())
137211
}
138212
let (sign, s) = extract_sign(s);
139213
let flt = match parse_decimal(s) {
@@ -143,7 +217,7 @@ fn dec2flt<T: RawFloat>(s: &str) -> Result<T, PFE> {
143217
ParseResult::Invalid => match s {
144218
"inf" => T::infinity(),
145219
"NaN" => T::nan(),
146-
_ => { return Err(PFE { __kind: FloatErrorKind::Invalid }); }
220+
_ => { return Err(pfe_invalid()); }
147221
}
148222
};
149223

@@ -155,7 +229,7 @@ fn dec2flt<T: RawFloat>(s: &str) -> Result<T, PFE> {
155229

156230
/// The main workhorse for the decimal-to-float conversion: Orchestrate all the preprocessing
157231
/// and figure out which algorithm should do the actual conversion.
158-
fn convert<T: RawFloat>(mut decimal: Decimal) -> Result<T, PFE> {
232+
fn convert<T: RawFloat>(mut decimal: Decimal) -> Result<T, ParseFloatError> {
159233
simplify(&mut decimal);
160234
if let Some(x) = trivial_cases(&decimal) {
161235
return Ok(x);
@@ -172,7 +246,7 @@ fn convert<T: RawFloat>(mut decimal: Decimal) -> Result<T, PFE> {
172246
// If we exceed this, perhaps while calculating `f * 10^e` in Algorithm R or Algorithm M,
173247
// we'll crash. So we error out before getting too close, with a generous safety margin.
174248
if max_digits > 375 {
175-
return Err(PFE { __kind: FloatErrorKind::Invalid });
249+
return Err(pfe_invalid());
176250
}
177251
let f = digits_to_big(decimal.integral, decimal.fractional);
178252

‎src/libcore/num/float_macros.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ macro_rules! from_str_radix_float_impl {
2323
($T:ty) => {
2424
fn from_str_radix(src: &str, radix: u32)
2525
-> Result<$T, ParseFloatError> {
26-
use num::FloatErrorKind::*;
27-
use num::ParseFloatError as PFE;
26+
use num::dec2flt::{pfe_empty, pfe_invalid};
2827

2928
// Special values
3029
match src {
@@ -35,8 +34,8 @@ macro_rules! from_str_radix_float_impl {
3534
}
3635

3736
let (is_positive, src) = match src.slice_shift_char() {
38-
None => return Err(PFE { __kind: Empty }),
39-
Some(('-', "")) => return Err(PFE { __kind: Empty }),
37+
None => return Err(pfe_empty()),
38+
Some(('-', "")) => return Err(pfe_empty()),
4039
Some(('-', src)) => (false, src),
4140
Some((_, _)) => (true, src),
4241
};
@@ -88,7 +87,7 @@ macro_rules! from_str_radix_float_impl {
8887
break; // start of fractional part
8988
},
9089
_ => {
91-
return Err(PFE { __kind: Invalid });
90+
return Err(pfe_invalid())
9291
},
9392
},
9493
}
@@ -122,7 +121,7 @@ macro_rules! from_str_radix_float_impl {
122121
break; // start of exponent
123122
},
124123
_ => {
125-
return Err(PFE { __kind: Invalid });
124+
return Err(pfe_invalid())
126125
},
127126
},
128127
}
@@ -135,7 +134,7 @@ macro_rules! from_str_radix_float_impl {
135134
let base = match c {
136135
'E' | 'e' if radix == 10 => 10.0,
137136
'P' | 'p' if radix == 16 => 2.0,
138-
_ => return Err(PFE { __kind: Invalid }),
137+
_ => return Err(pfe_invalid()),
139138
};
140139

141140
// Parse the exponent as decimal integer
@@ -144,13 +143,13 @@ macro_rules! from_str_radix_float_impl {
144143
Some(('-', src)) => (false, src.parse::<usize>()),
145144
Some(('+', src)) => (true, src.parse::<usize>()),
146145
Some((_, _)) => (true, src.parse::<usize>()),
147-
None => return Err(PFE { __kind: Invalid }),
146+
None => return Err(pfe_invalid()),
148147
};
149148

150149
match (is_positive, exp) {
151150
(true, Ok(exp)) => base.powi(exp as i32),
152151
(false, Ok(exp)) => 1.0 / base.powi(exp as i32),
153-
(_, Err(_)) => return Err(PFE { __kind: Invalid }),
152+
(_, Err(_)) => return Err(pfe_invalid()),
154153
}
155154
},
156155
None => 1.0, // no exponent

‎src/libcore/num/mod.rs

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,47 +1365,6 @@ pub trait Float: Sized {
13651365
fn to_radians(self) -> Self;
13661366
}
13671367

1368-
macro_rules! from_str_float_impl {
1369-
($t:ty, $func:ident) => {
1370-
#[stable(feature = "rust1", since = "1.0.0")]
1371-
impl FromStr for $t {
1372-
type Err = ParseFloatError;
1373-
1374-
/// Converts a string in base 10 to a float.
1375-
/// Accepts an optional decimal exponent.
1376-
///
1377-
/// This function accepts strings such as
1378-
///
1379-
/// * '3.14'
1380-
/// * '-3.14'
1381-
/// * '2.5E10', or equivalently, '2.5e10'
1382-
/// * '2.5E-10'
1383-
/// * '.' (understood as 0)
1384-
/// * '5.'
1385-
/// * '.5', or, equivalently, '0.5'
1386-
/// * 'inf', '-inf', 'NaN'
1387-
///
1388-
/// Leading and trailing whitespace represent an error.
1389-
///
1390-
/// # Arguments
1391-
///
1392-
/// * src - A string
1393-
///
1394-
/// # Return value
1395-
///
1396-
/// `Err(ParseFloatError)` if the string did not represent a valid
1397-
/// number. Otherwise, `Ok(n)` where `n` is the floating-point
1398-
/// number represented by `src`.
1399-
#[inline]
1400-
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
1401-
dec2flt::$func(src)
1402-
}
1403-
}
1404-
}
1405-
}
1406-
from_str_float_impl!(f32, to_f32);
1407-
from_str_float_impl!(f64, to_f64);
1408-
14091368
macro_rules! from_str_radix_int_impl {
14101369
($($t:ty)*) => {$(
14111370
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1548,40 +1507,4 @@ impl fmt::Display for ParseIntError {
15481507
}
15491508
}
15501509

1551-
/// An error which can be returned when parsing a float.
1552-
#[derive(Debug, Clone, PartialEq)]
1553-
#[stable(feature = "rust1", since = "1.0.0")]
1554-
pub struct ParseFloatError {
1555-
#[doc(hidden)]
1556-
#[unstable(feature = "float_error_internals",
1557-
reason = "should not be exposed publicly",
1558-
issue = "0")]
1559-
pub __kind: FloatErrorKind
1560-
}
1561-
1562-
#[derive(Debug, Clone, PartialEq)]
1563-
#[unstable(feature = "float_error_internals",
1564-
reason = "should not be exposed publicly",
1565-
issue = "0")]
1566-
#[doc(hidden)]
1567-
pub enum FloatErrorKind {
1568-
Empty,
1569-
Invalid,
1570-
}
1571-
1572-
impl ParseFloatError {
1573-
#[doc(hidden)]
1574-
pub fn __description(&self) -> &str {
1575-
match self.__kind {
1576-
FloatErrorKind::Empty => "cannot parse float from empty string",
1577-
FloatErrorKind::Invalid => "invalid float literal",
1578-
}
1579-
}
1580-
}
1581-
1582-
#[stable(feature = "rust1", since = "1.0.0")]
1583-
impl fmt::Display for ParseFloatError {
1584-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1585-
self.__description().fmt(f)
1586-
}
1587-
}
1510+
pub use num::dec2flt::ParseFloatError;

‎src/libcoretest/atomic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use core::atomic::*;
12-
use core::atomic::Ordering::SeqCst;
11+
use core::sync::atomic::*;
12+
use core::sync::atomic::Ordering::SeqCst;
1313

1414
#[test]
1515
fn bool_() {

‎src/libcoretest/num/dec2flt/mod.rs

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
use std::{i64, f32, f64};
1414
use test;
15-
use core::num::dec2flt::{to_f32, to_f64};
1615

1716
mod parse;
1817
mod rawfp;
@@ -27,11 +26,11 @@ macro_rules! test_literal {
2726
let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)];
2827
for input in inputs {
2928
if input != "inf" {
30-
assert_eq!(to_f64(input), Ok(x64));
31-
assert_eq!(to_f32(input), Ok(x32));
29+
assert_eq!(input.parse(), Ok(x64));
30+
assert_eq!(input.parse(), Ok(x32));
3231
let neg_input = &format!("-{}", input);
33-
assert_eq!(to_f64(neg_input), Ok(-x64));
34-
assert_eq!(to_f32(neg_input), Ok(-x32));
32+
assert_eq!(neg_input.parse(), Ok(-x64));
33+
assert_eq!(neg_input.parse(), Ok(-x32));
3534
}
3635
}
3736
})
@@ -99,83 +98,83 @@ fn fast_path_correct() {
9998

10099
#[test]
101100
fn lonely_dot() {
102-
assert_eq!(to_f64("."), Ok(0.0));
101+
assert_eq!(".".parse(), Ok(0.0));
103102
}
104103

105104
#[test]
106105
fn nan() {
107-
assert!(to_f64("NaN").unwrap().is_nan());
108-
assert!(to_f32("NaN").unwrap().is_nan());
106+
assert!("NaN".parse::<f32>().unwrap().is_nan());
107+
assert!("NaN".parse::<f64>().unwrap().is_nan());
109108
}
110109

111110
#[test]
112111
fn inf() {
113-
assert_eq!(to_f64("inf"), Ok(f64::INFINITY));
114-
assert_eq!(to_f64("-inf"), Ok(f64::NEG_INFINITY));
115-
assert_eq!(to_f32("inf"), Ok(f32::INFINITY));
116-
assert_eq!(to_f32("-inf"), Ok(f32::NEG_INFINITY));
112+
assert_eq!("inf".parse(), Ok(f64::INFINITY));
113+
assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY));
114+
assert_eq!("inf".parse(), Ok(f32::INFINITY));
115+
assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY));
117116
}
118117

119118
#[test]
120119
fn massive_exponent() {
121120
let max = i64::MAX;
122-
assert_eq!(to_f64(&format!("1e{}000", max)), Ok(f64::INFINITY));
123-
assert_eq!(to_f64(&format!("1e-{}000", max)), Ok(0.0));
124-
assert_eq!(to_f64(&format!("1e{}000", max)), Ok(f64::INFINITY));
121+
assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
122+
assert_eq!(format!("1e-{}000", max).parse(), Ok(0.0));
123+
assert_eq!(format!("1e{}000", max).parse(), Ok(f64::INFINITY));
125124
}
126125

127126
#[bench]
128127
fn bench_0(b: &mut test::Bencher) {
129-
b.iter(|| to_f64("0.0"));
128+
b.iter(|| "0.0".parse::<f64>());
130129
}
131130

132131
#[bench]
133132
fn bench_42(b: &mut test::Bencher) {
134-
b.iter(|| to_f64("42"));
133+
b.iter(|| "42".parse::<f64>());
135134
}
136135

137136
#[bench]
138137
fn bench_huge_int(b: &mut test::Bencher) {
139138
// 2^128 - 1
140-
b.iter(|| to_f64("170141183460469231731687303715884105727"));
139+
b.iter(|| "170141183460469231731687303715884105727".parse::<f64>());
141140
}
142141

143142
#[bench]
144143
fn bench_short_decimal(b: &mut test::Bencher) {
145-
b.iter(|| to_f64("1234.5678"));
144+
b.iter(|| "1234.5678".parse::<f64>());
146145
}
147146

148147
#[bench]
149148
fn bench_pi_long(b: &mut test::Bencher) {
150-
b.iter(|| to_f64("3.14159265358979323846264338327950288"));
149+
b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>());
151150
}
152151

153152
#[bench]
154153
fn bench_pi_short(b: &mut test::Bencher) {
155-
b.iter(|| to_f64("3.141592653589793"))
154+
b.iter(|| "3.141592653589793".parse::<f64>())
156155
}
157156

158157
#[bench]
159158
fn bench_1e150(b: &mut test::Bencher) {
160-
b.iter(|| to_f64("1e150"));
159+
b.iter(|| "1e150".parse::<f64>());
161160
}
162161

163162
#[bench]
164163
fn bench_long_decimal_and_exp(b: &mut test::Bencher) {
165-
b.iter(|| to_f64("727501488517303786137132964064381141071e-123"));
164+
b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>());
166165
}
167166

168167
#[bench]
169168
fn bench_min_subnormal(b: &mut test::Bencher) {
170-
b.iter(|| to_f64("5e-324"));
169+
b.iter(|| "5e-324".parse::<f64>());
171170
}
172171

173172
#[bench]
174173
fn bench_min_normal(b: &mut test::Bencher) {
175-
b.iter(|| to_f64("2.2250738585072014e-308"));
174+
b.iter(|| "2.2250738585072014e-308".parse::<f64>());
176175
}
177176

178177
#[bench]
179178
fn bench_max(b: &mut test::Bencher) {
180-
b.iter(|| to_f64("1.7976931348623157e308"));
179+
b.iter(|| "1.7976931348623157e308".parse::<f64>());
181180
}

‎src/libcoretest/num/uint_macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ mod tests {
1414
use core::$T_i::*;
1515
use num;
1616
use core::ops::{BitOr, BitAnd, BitXor, Shl, Shr, Not};
17-
use std::str;
17+
use std::str::FromStr;
1818

1919
#[test]
2020
fn test_overflows() {
@@ -152,5 +152,5 @@ mod tests {
152152
assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
153153
assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
154154
}
155-
155+
}
156156
)}

‎src/test/compile-fail/issue-1920-1.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ mod foo {
1717
fn assert_clone<T>() where T : Clone { }
1818

1919
fn main() {
20-
assert_clone::<foo::core::atomic::AtomicBool>();
20+
assert_clone::<foo::core::sync::atomic::AtomicBool>();
2121
//~^ ERROR the trait `foo::core::clone::Clone` is not implemented for the type `foo::core::
22-
}
22+
}

‎src/test/compile-fail/issue-1920-2.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ extern crate core as bar;
1515
fn assert_clone<T>() where T : Clone { }
1616

1717
fn main() {
18-
assert_clone::<bar::atomic::AtomicBool>();
19-
//~^ ERROR the trait `bar::clone::Clone` is not implemented for the type `bar::atomic::
20-
}
18+
assert_clone::<bar::sync::atomic::AtomicBool>();
19+
//~^ ERROR the trait `bar::clone::Clone` is not implemented for the type `bar::sync::atomic::
20+
}

‎src/test/compile-fail/issue-1920-3.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ extern crate core;
1919
fn assert_clone<T>() where T : Clone { }
2020

2121
fn main() {
22-
assert_clone::<foo::core::atomic::AtomicBool>();
23-
//~^ ERROR the trait `core::clone::Clone` is not implemented for the type `core::atomic::
24-
}
22+
assert_clone::<foo::core::sync::atomic::AtomicBool>();
23+
//~^ ERROR the trait `core::clone::Clone` is not implemented for the type `core::sync::atomic::
24+
}

0 commit comments

Comments
 (0)
Please sign in to comment.