From 0cdde6e5e015ee6f6d9381ab624a312af7c9b069 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 27 Jan 2015 22:52:32 -0800 Subject: [PATCH] std: Stabilize FromStr and parse This commits adds an associated type to the `FromStr` trait representing an error payload for parses which do not succeed. The previous return value, `Option` did not allow for this form of payload. After the associated type was added, the following attributes were applied: * `FromStr` is now stable * `FromStr::Err` is now stable * `FromStr::from_str` is now stable * `StrExt::parse` is now stable * `FromStr for bool` is now stable * `FromStr for $float` is now stable * `FromStr for $integral` is now stable * Errors returned from stable `FromStr` implementations are stable * Errors implement `Display` and `Error` (both impl blocks being `#[stable]`) Closes #15138 --- src/compiletest/common.rs | 21 ++- src/compiletest/compiletest.rs | 5 +- src/compiletest/header.rs | 6 +- src/doc/reference.md | 2 +- src/doc/trpl/guessing-game.md | 24 +-- src/libcollections/str.rs | 10 +- src/libcollections/string.rs | 8 +- src/libcore/num/mod.rs | 174 +++++++++++++----- src/libcore/option.rs | 4 +- src/libcore/str/mod.rs | 53 ++++-- src/libcoretest/num/int_macros.rs | 38 ++-- src/libcoretest/num/mod.rs | 52 +++--- src/libcoretest/str.rs | 6 +- src/liblog/directive.rs | 2 +- src/librustc/lint/builtin.rs | 2 +- src/librustc/metadata/decoder.rs | 2 +- src/librustc/metadata/tydecode.rs | 8 +- .../middle/infer/region_inference/graphviz.rs | 2 +- src/librustc/middle/recursion_limit.rs | 3 +- src/librustc/session/config.rs | 4 +- src/librustc_driver/pretty.rs | 14 +- src/libserialize/json.rs | 9 +- src/libstd/num/uint_macros.rs | 18 +- src/libstd/old_io/net/ip.rs | 108 ++++++----- src/libstd/path/posix.rs | 13 +- src/libstd/path/windows.rs | 13 +- src/libstd/rt/util.rs | 4 +- src/libsyntax/parse/lexer/mod.rs | 4 +- src/libsyntax/parse/mod.rs | 8 +- src/libsyntax/parse/parser.rs | 4 +- src/libsyntax/show_span.rs | 9 +- src/libtest/lib.rs | 3 +- src/test/auxiliary/static-methods-crate.rs | 2 +- src/test/bench/shootout-chameneos-redux.rs | 2 +- src/test/bench/shootout-fannkuch-redux.rs | 2 +- src/test/bench/shootout-nbody.rs | 2 +- src/test/bench/shootout-threadring.rs | 4 +- src/test/run-pass/match-with-ret-arm.rs | 2 +- .../run-pass/wait-forked-but-failed-child.rs | 2 +- 39 files changed, 389 insertions(+), 260 deletions(-) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index b1deb8a36ad..df2981a6c83 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -25,17 +25,18 @@ pub enum Mode { } impl FromStr for Mode { - fn from_str(s: &str) -> Option { + type Err = (); + fn from_str(s: &str) -> Result { match s { - "compile-fail" => Some(CompileFail), - "run-fail" => Some(RunFail), - "run-pass" => Some(RunPass), - "run-pass-valgrind" => Some(RunPassValgrind), - "pretty" => Some(Pretty), - "debuginfo-lldb" => Some(DebugInfoLldb), - "debuginfo-gdb" => Some(DebugInfoGdb), - "codegen" => Some(Codegen), - _ => None, + "compile-fail" => Ok(CompileFail), + "run-fail" => Ok(RunFail), + "run-pass" => Ok(RunPass), + "run-pass-valgrind" => Ok(RunPassValgrind), + "pretty" => Ok(Pretty), + "debuginfo-lldb" => Ok(DebugInfoLldb), + "debuginfo-gdb" => Ok(DebugInfoGdb), + "codegen" => Ok(Codegen), + _ => Err(()), } } } diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 357ccec7cf3..ea733c84a97 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -35,7 +35,6 @@ extern crate log; use std::os; use std::old_io; use std::old_io::fs; -use std::str::FromStr; use std::thunk::Thunk; use getopts::{optopt, optflag, reqopt}; use common::Config; @@ -140,9 +139,7 @@ pub fn parse_config(args: Vec ) -> Config { build_base: opt_path(matches, "build-base"), aux_base: opt_path(matches, "aux-base"), stage_id: matches.opt_str("stage-id").unwrap(), - mode: FromStr::from_str(matches.opt_str("mode") - .unwrap() - .as_slice()).expect("invalid mode"), + mode: matches.opt_str("mode").unwrap().parse().ok().expect("invalid mode"), run_ignored: matches.opt_present("ignored"), filter: filter, logfile: matches.opt_str("logfile").map(|s| Path::new(s)), diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index f83c27b75d6..66059d2d13d 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -352,8 +352,8 @@ pub fn gdb_version_to_int(version_string: &str) -> int { panic!("{}", error_string); } - let major: int = components[0].parse().expect(error_string); - let minor: int = components[1].parse().expect(error_string); + let major: int = components[0].parse().ok().expect(error_string); + let minor: int = components[1].parse().ok().expect(error_string); return major * 1000 + minor; } @@ -363,6 +363,6 @@ pub fn lldb_version_to_int(version_string: &str) -> int { "Encountered LLDB version string with unexpected format: {}", version_string); let error_string = error_string.as_slice(); - let major: int = version_string.parse().expect(error_string); + let major: int = version_string.parse().ok().expect(error_string); return major; } diff --git a/src/doc/reference.md b/src/doc/reference.md index 59ac173f97a..686820eb813 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2994,7 +2994,7 @@ Some examples of call expressions: # fn add(x: i32, y: i32) -> i32 { 0 } let x: i32 = add(1i32, 2i32); -let pi: Option = "3.14".parse(); +let pi: Option = "3.14".parse().ok(); ``` ### Lambda expressions diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index f01b62223ca..162e533d8bb 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -400,7 +400,7 @@ a function for that: let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); -let input_num: Option = input.parse(); +let input_num: Option = input.parse().ok(); ``` The `parse` function takes in a `&str` value and converts it into something. @@ -422,11 +422,13 @@ In this case, we say `x` is a `u32` explicitly, so Rust is able to properly tell `random()` what to generate. In a similar fashion, both of these work: ```{rust,ignore} -let input_num = "5".parse::(); // input_num: Option -let input_num: Option = "5".parse(); // input_num: Option +let input_num = "5".parse::().ok(); // input_num: Option +let input_num: Option = "5".parse().ok(); // input_num: Option ``` -Anyway, with us now converting our input to a number, our code looks like this: +Here we're converting the `Result` returned by `parse` to an `Option` by using +the `ok` method as well. Anyway, with us now converting our input to a number, +our code looks like this: ```{rust,ignore} use std::old_io; @@ -445,7 +447,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.parse(); + let input_num: Option = input.parse().ok(); println!("You guessed: {}", input_num); @@ -495,7 +497,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.parse(); + let input_num: Option = input.parse().ok(); let num = match input_num { Some(num) => num, @@ -562,7 +564,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.trim().parse(); + let input_num: Option = input.trim().parse().ok(); let num = match input_num { Some(num) => num, @@ -638,7 +640,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.trim().parse(); + let input_num: Option = input.trim().parse().ok(); let num = match input_num { Some(num) => num, @@ -714,7 +716,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.trim().parse(); + let input_num: Option = input.trim().parse().ok(); let num = match input_num { Some(num) => num, @@ -770,7 +772,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.trim().parse(); + let input_num: Option = input.trim().parse().ok(); let num = match input_num { Some(num) => num, @@ -847,7 +849,7 @@ fn main() { let input = old_io::stdin().read_line() .ok() .expect("Failed to read line"); - let input_num: Option = input.trim().parse(); + let input_num: Option = input.trim().parse().ok(); let num = match input_num { Some(num) => num, diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 35591a5e9ef..2a2a44aa38f 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -68,6 +68,7 @@ use core::ops::FullRange; #[cfg(not(stage0))] use core::ops::RangeFull; use core::option::Option::{self, Some, None}; +use core::result::Result; use core::slice::AsSlice; use core::str as core_str; use unicode::str::{UnicodeStr, Utf16Encoder}; @@ -1231,13 +1232,12 @@ pub trait StrExt: Index { /// # Example /// /// ``` - /// assert_eq!("4".parse::(), Some(4)); - /// assert_eq!("j".parse::(), None); + /// assert_eq!("4".parse::(), Ok(4)); + /// assert!("j".parse::().is_err()); /// ``` #[inline] - #[unstable(feature = "collections", - reason = "this method was just created")] - fn parse(&self) -> Option { + #[stable(feature = "rust1", since = "1.0.0")] + fn parse(&self) -> Result { core_str::StrExt::parse(&self[]) } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 035529c7365..fa399ca3414 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -940,10 +940,12 @@ pub fn as_string<'a>(x: &'a str) -> DerefString<'a> { DerefString { x: as_vec(x.as_bytes()) } } +#[unstable(feature = "collections", reason = "associated error type may change")] impl FromStr for String { + type Err = (); #[inline] - fn from_str(s: &str) -> Option { - Some(String::from_str(s)) + fn from_str(s: &str) -> Result { + Ok(String::from_str(s)) } } @@ -1016,7 +1018,7 @@ mod tests { #[test] fn test_from_str() { - let owned: Option<::std::string::String> = "string".parse(); + let owned: Option<::std::string::String> = "string".parse().ok(); assert_eq!(owned.as_ref().map(|s| s.as_slice()), Some("string")); } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index dd9cc553c7c..138085abf41 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -17,16 +17,17 @@ use char::CharExt; use clone::Clone; -use cmp::{PartialEq, Eq}; -use cmp::{PartialOrd, Ord}; +use cmp::{PartialEq, Eq, PartialOrd, Ord}; +use error::Error; +use fmt; use intrinsics; use iter::IteratorExt; use marker::Copy; use mem::size_of; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; -use option::Option; -use option::Option::{Some, None}; +use option::Option::{self, Some, None}; +use result::Result::{self, Ok, Err}; use str::{FromStr, StrExt}; /// A built-in signed or unsigned integer. @@ -1428,22 +1429,25 @@ pub trait Float } /// A generic trait for converting a string with a radix (base) to a value -#[unstable(feature = "core", reason = "might need to return Result")] +#[unstable(feature = "core", reason = "needs reevaluation")] pub trait FromStrRadix { - fn from_str_radix(str: &str, radix: uint) -> Option; + type Err; + fn from_str_radix(str: &str, radix: uint) -> Result; } /// A utility function that just calls FromStrRadix::from_str_radix. -#[unstable(feature = "core", reason = "might need to return Result")] -pub fn from_str_radix(str: &str, radix: uint) -> Option { +#[unstable(feature = "core", reason = "needs reevaluation")] +pub fn from_str_radix(str: &str, radix: uint) + -> Result { FromStrRadix::from_str_radix(str, radix) } macro_rules! from_str_radix_float_impl { ($T:ty) => { - #[unstable(feature = "core", - reason = "might need to return Result")] + #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for $T { + type Err = ParseFloatError; + /// Convert a string in base 10 to a float. /// Accepts an optional decimal exponent. /// @@ -1470,14 +1474,15 @@ macro_rules! from_str_radix_float_impl { /// `None` if the string did not represent a valid number. Otherwise, /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str(src: &str) -> Option<$T> { + fn from_str(src: &str) -> Result<$T, ParseFloatError> { from_str_radix(src, 10) } } - #[unstable(feature = "core", - reason = "might need to return Result")] + #[stable(feature = "rust1", since = "1.0.0")] impl FromStrRadix for $T { + type Err = ParseFloatError; + /// Convert a string in a given base to a float. /// /// Due to possible conflicts, this function does **not** accept @@ -1493,24 +1498,28 @@ macro_rules! from_str_radix_float_impl { /// /// # Return value /// - /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `src`. - fn from_str_radix(src: &str, radix: uint) -> Option<$T> { - assert!(radix >= 2 && radix <= 36, + /// `None` if the string did not represent a valid number. + /// Otherwise, `Some(n)` where `n` is the floating-point number + /// represented by `src`. + fn from_str_radix(src: &str, radix: uint) + -> Result<$T, ParseFloatError> { + use self::FloatErrorKind::*; + use self::ParseFloatError as PFE; + assert!(radix >= 2 && radix <= 36, "from_str_radix_float: must lie in the range `[2, 36]` - found {}", radix); // Special values match src { - "inf" => return Some(Float::infinity()), - "-inf" => return Some(Float::neg_infinity()), - "NaN" => return Some(Float::nan()), + "inf" => return Ok(Float::infinity()), + "-inf" => return Ok(Float::neg_infinity()), + "NaN" => return Ok(Float::nan()), _ => {}, } let (is_positive, src) = match src.slice_shift_char() { - None => return None, - Some(('-', "")) => return None, + None => return Err(PFE { kind: Empty }), + Some(('-', "")) => return Err(PFE { kind: Empty }), Some(('-', src)) => (false, src), Some((_, _)) => (true, src), }; @@ -1541,15 +1550,15 @@ macro_rules! from_str_radix_float_impl { // if we've not seen any non-zero digits. if prev_sig != 0.0 { if is_positive && sig <= prev_sig - { return Some(Float::infinity()); } + { return Ok(Float::infinity()); } if !is_positive && sig >= prev_sig - { return Some(Float::neg_infinity()); } + { return Ok(Float::neg_infinity()); } // Detect overflow by reversing the shift-and-add process if is_positive && (prev_sig != (sig - digit as $T) / radix as $T) - { return Some(Float::infinity()); } + { return Ok(Float::infinity()); } if !is_positive && (prev_sig != (sig + digit as $T) / radix as $T) - { return Some(Float::neg_infinity()); } + { return Ok(Float::neg_infinity()); } } prev_sig = sig; }, @@ -1562,7 +1571,7 @@ macro_rules! from_str_radix_float_impl { break; // start of fractional part }, _ => { - return None; + return Err(PFE { kind: Invalid }); }, }, } @@ -1585,9 +1594,9 @@ macro_rules! from_str_radix_float_impl { }; // Detect overflow by comparing to last value if is_positive && sig < prev_sig - { return Some(Float::infinity()); } + { return Ok(Float::infinity()); } if !is_positive && sig > prev_sig - { return Some(Float::neg_infinity()); } + { return Ok(Float::neg_infinity()); } prev_sig = sig; }, None => match c { @@ -1596,7 +1605,7 @@ macro_rules! from_str_radix_float_impl { break; // start of exponent }, _ => { - return None; // invalid number + return Err(PFE { kind: Invalid }); }, }, } @@ -1609,7 +1618,7 @@ macro_rules! from_str_radix_float_impl { let base = match c { 'E' | 'e' if radix == 10 => 10.0, 'P' | 'p' if radix == 16 => 2.0, - _ => return None, + _ => return Err(PFE { kind: Invalid }), }; // Parse the exponent as decimal integer @@ -1618,19 +1627,19 @@ macro_rules! from_str_radix_float_impl { Some(('-', src)) => (false, src.parse::()), Some(('+', src)) => (true, src.parse::()), Some((_, _)) => (true, src.parse::()), - None => return None, + None => return Err(PFE { kind: Invalid }), }; match (is_positive, exp) { - (true, Some(exp)) => base.powi(exp as i32), - (false, Some(exp)) => 1.0 / base.powi(exp as i32), - (_, None) => return None, + (true, Ok(exp)) => base.powi(exp as i32), + (false, Ok(exp)) => 1.0 / base.powi(exp as i32), + (_, Err(_)) => return Err(PFE { kind: Invalid }), } }, None => 1.0, // no exponent }; - Some(sig * exp) + Ok(sig * exp) } } } @@ -1640,19 +1649,22 @@ from_str_radix_float_impl! { f64 } macro_rules! from_str_radix_int_impl { ($T:ty) => { - #[unstable(feature = "core", - reason = "might need to return Result")] + #[stable(feature = "rust1", since = "1.0.0")] impl FromStr for $T { + type Err = ParseIntError; #[inline] - fn from_str(src: &str) -> Option<$T> { + fn from_str(src: &str) -> Result<$T, ParseIntError> { from_str_radix(src, 10) } } - #[unstable(feature = "core", - reason = "might need to return Result")] + #[stable(feature = "rust1", since = "1.0.0")] impl FromStrRadix for $T { - fn from_str_radix(src: &str, radix: uint) -> Option<$T> { + type Err = ParseIntError; + fn from_str_radix(src: &str, radix: uint) + -> Result<$T, ParseIntError> { + use self::IntErrorKind::*; + use self::ParseIntError as PIE; assert!(radix >= 2 && radix <= 36, "from_str_radix_int: must lie in the range `[2, 36]` - found {}", radix); @@ -1666,18 +1678,18 @@ macro_rules! from_str_radix_int_impl { for c in src.chars() { let x = match c.to_digit(radix) { Some(x) => x, - None => return None, + None => return Err(PIE { kind: InvalidDigit }), }; result = match result.checked_mul(radix as $T) { Some(result) => result, - None => return None, + None => return Err(PIE { kind: Underflow }), }; result = match result.checked_sub(x as $T) { Some(result) => result, - None => return None, + None => return Err(PIE { kind: Underflow }), }; } - Some(result) + Ok(result) }, Some((_, _)) => { // The number is signed @@ -1685,20 +1697,20 @@ macro_rules! from_str_radix_int_impl { for c in src.chars() { let x = match c.to_digit(radix) { Some(x) => x, - None => return None, + None => return Err(PIE { kind: InvalidDigit }), }; result = match result.checked_mul(radix as $T) { Some(result) => result, - None => return None, + None => return Err(PIE { kind: Overflow }), }; result = match result.checked_add(x as $T) { Some(result) => result, - None => return None, + None => return Err(PIE { kind: Overflow }), }; } - Some(result) + Ok(result) }, - None => None, + None => Err(ParseIntError { kind: Empty }), } } } @@ -1714,3 +1726,63 @@ from_str_radix_int_impl! { u8 } from_str_radix_int_impl! { u16 } from_str_radix_int_impl! { u32 } from_str_radix_int_impl! { u64 } + +/// An error which can be returned when parsing an integer. +#[derive(Show, Clone, PartialEq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseIntError { kind: IntErrorKind } + +#[derive(Show, Clone, PartialEq)] +enum IntErrorKind { + Empty, + InvalidDigit, + Overflow, + Underflow, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError { + fn description(&self) -> &str { + match self.kind { + IntErrorKind::Empty => "cannot parse integer from empty string", + IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::Overflow => "number too large to fit in target type", + IntErrorKind::Underflow => "number too small to fit in target type", + } + } +} + +/// An error which can be returned when parsing a float. +#[derive(Show, Clone, PartialEq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseFloatError { kind: FloatErrorKind } + +#[derive(Show, Clone, PartialEq)] +enum FloatErrorKind { + Empty, + Invalid, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError { + fn description(&self) -> &str { + match self.kind { + FloatErrorKind::Empty => "cannot parse float from empty string", + FloatErrorKind::Invalid => "invalid float literal", + } + } +} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 5cb8e5e5565..2f261b0628f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -728,8 +728,8 @@ impl Option { /// ``` /// let good_year_from_input = "1909"; /// let bad_year_from_input = "190blarg"; - /// let good_year = good_year_from_input.parse().unwrap_or_default(); - /// let bad_year = bad_year_from_input.parse().unwrap_or_default(); + /// let good_year = good_year_from_input.parse().ok().unwrap_or_default(); + /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default(); /// /// assert_eq!(1909, good_year); /// assert_eq!(0, bad_year); diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 8495a03747e..d08a2d3d77e 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -108,37 +108,62 @@ macro_rules! delegate_iter { /// A trait to abstract the idea of creating a new instance of a type from a /// string. -// FIXME(#17307): there should be an `E` associated type for a `Result` return -#[unstable(feature = "core", - reason = "will return a Result once associated types are working")] +#[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr { + /// The associated error which can be returned from parsing. + #[stable(feature = "rust1", since = "1.0.0")] + type Err; + /// Parses a string `s` to return an optional value of this type. If the /// string is ill-formatted, the None is returned. - fn from_str(s: &str) -> Option; + #[stable(feature = "rust1", since = "1.0.0")] + fn from_str(s: &str) -> Result; } +#[stable(feature = "rust1", since = "1.0.0")] impl FromStr for bool { + type Err = ParseBoolError; + /// Parse a `bool` from a string. /// - /// Yields an `Option`, because `s` may or may not actually be parseable. + /// Yields an `Option`, because `s` may or may not actually be + /// parseable. /// /// # Examples /// /// ```rust - /// assert_eq!("true".parse(), Some(true)); - /// assert_eq!("false".parse(), Some(false)); - /// assert_eq!("not even a boolean".parse::(), None); + /// assert_eq!("true".parse(), Ok(true)); + /// assert_eq!("false".parse(), Ok(false)); + /// assert!("not even a boolean".parse::().is_err()); /// ``` #[inline] - fn from_str(s: &str) -> Option { + fn from_str(s: &str) -> Result { match s { - "true" => Some(true), - "false" => Some(false), - _ => None, + "true" => Ok(true), + "false" => Ok(false), + _ => Err(ParseBoolError { _priv: () }), } } } +/// An error returned when parsing a `bool` from a string fails. +#[derive(Show, Clone, PartialEq)] +#[allow(missing_copy_implementations)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseBoolError { _priv: () } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseBoolError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "provided string was not `true` or `false`".fmt(f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseBoolError { + fn description(&self) -> &str { "failed to parse bool" } +} + /* Section: Creating a string */ @@ -1355,7 +1380,7 @@ pub trait StrExt { fn as_ptr(&self) -> *const u8; fn len(&self) -> uint; fn is_empty(&self) -> bool; - fn parse(&self) -> Option; + fn parse(&self) -> Result; } #[inline(never)] @@ -1670,7 +1695,7 @@ impl StrExt for str { fn is_empty(&self) -> bool { self.len() == 0 } #[inline] - fn parse(&self) -> Option { FromStr::from_str(self) } + fn parse(&self) -> Result { FromStr::from_str(self) } } /// Pluck a code point out of a UTF-8-like byte slice and return the diff --git a/src/libcoretest/num/int_macros.rs b/src/libcoretest/num/int_macros.rs index b98432e26b2..d956cd4816b 100644 --- a/src/libcoretest/num/int_macros.rs +++ b/src/libcoretest/num/int_macros.rs @@ -159,7 +159,7 @@ mod tests { #[test] fn test_from_str() { fn from_str(t: &str) -> Option { - ::std::str::FromStr::from_str(t) + ::std::str::FromStr::from_str(t).ok() } assert_eq!(from_str::<$T>("0"), Some(0 as $T)); assert_eq!(from_str::<$T>("3"), Some(3 as $T)); @@ -180,26 +180,26 @@ mod tests { #[test] fn test_from_str_radix() { - assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Some(65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("Z", 36), Some(35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 10), Ok(123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Ok(9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Ok(83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Ok(291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Ok(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Ok(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Ok(35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("Z", 36), Ok(35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 10), Some(-123 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Some(-9 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 8), Some(-83 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-123", 16), Some(-291 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Some(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Some(-65535 as i32)); - assert_eq!(FromStrRadix::from_str_radix("-z", 36), Some(-35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Some(-35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 10), Ok(-123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Ok(-9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 8), Ok(-83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 16), Ok(-291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Ok(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Ok(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-z", 36), Ok(-35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Ok(-35 as $T)); - assert_eq!(FromStrRadix::from_str_radix("Z", 35), None::<$T>); - assert_eq!(FromStrRadix::from_str_radix("-9", 2), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("Z", 35).ok(), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("-9", 2).ok(), None::<$T>); } } diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index e0623bade5c..f93c07eac5f 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -62,64 +62,64 @@ mod test { #[test] fn from_str_issue7588() { - let u : Option = from_str_radix("1000", 10); + let u : Option = from_str_radix("1000", 10).ok(); assert_eq!(u, None); - let s : Option = from_str_radix("80000", 10); + let s : Option = from_str_radix("80000", 10).ok(); assert_eq!(s, None); - let f : Option = from_str_radix("10000000000000000000000000000000000000000", 10); + let f : Option = from_str_radix("10000000000000000000000000000000000000000", 10).ok(); assert_eq!(f, Some(Float::infinity())); - let fe : Option = from_str_radix("1e40", 10); + let fe : Option = from_str_radix("1e40", 10).ok(); assert_eq!(fe, Some(Float::infinity())); } #[test] fn test_from_str_radix_float() { - let x1 : Option = from_str_radix("-123.456", 10); + let x1 : Option = from_str_radix("-123.456", 10).ok(); assert_eq!(x1, Some(-123.456)); - let x2 : Option = from_str_radix("123.456", 10); + let x2 : Option = from_str_radix("123.456", 10).ok(); assert_eq!(x2, Some(123.456)); - let x3 : Option = from_str_radix("-0.0", 10); + let x3 : Option = from_str_radix("-0.0", 10).ok(); assert_eq!(x3, Some(-0.0)); - let x4 : Option = from_str_radix("0.0", 10); + let x4 : Option = from_str_radix("0.0", 10).ok(); assert_eq!(x4, Some(0.0)); - let x4 : Option = from_str_radix("1.0", 10); + let x4 : Option = from_str_radix("1.0", 10).ok(); assert_eq!(x4, Some(1.0)); - let x5 : Option = from_str_radix("-1.0", 10); + let x5 : Option = from_str_radix("-1.0", 10).ok(); assert_eq!(x5, Some(-1.0)); } #[test] fn test_int_from_str_overflow() { let mut i8_val: i8 = 127_i8; - assert_eq!("127".parse::(), Some(i8_val)); - assert_eq!("128".parse::(), None); + assert_eq!("127".parse::().ok(), Some(i8_val)); + assert_eq!("128".parse::().ok(), None); i8_val += 1 as i8; - assert_eq!("-128".parse::(), Some(i8_val)); - assert_eq!("-129".parse::(), None); + assert_eq!("-128".parse::().ok(), Some(i8_val)); + assert_eq!("-129".parse::().ok(), None); let mut i16_val: i16 = 32_767_i16; - assert_eq!("32767".parse::(), Some(i16_val)); - assert_eq!("32768".parse::(), None); + assert_eq!("32767".parse::().ok(), Some(i16_val)); + assert_eq!("32768".parse::().ok(), None); i16_val += 1 as i16; - assert_eq!("-32768".parse::(), Some(i16_val)); - assert_eq!("-32769".parse::(), None); + assert_eq!("-32768".parse::().ok(), Some(i16_val)); + assert_eq!("-32769".parse::().ok(), None); let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!("2147483647".parse::(), Some(i32_val)); - assert_eq!("2147483648".parse::(), None); + assert_eq!("2147483647".parse::().ok(), Some(i32_val)); + assert_eq!("2147483648".parse::().ok(), None); i32_val += 1 as i32; - assert_eq!("-2147483648".parse::(), Some(i32_val)); - assert_eq!("-2147483649".parse::(), None); + assert_eq!("-2147483648".parse::().ok(), Some(i32_val)); + assert_eq!("-2147483649".parse::().ok(), None); let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!("9223372036854775807".parse::(), Some(i64_val)); - assert_eq!("9223372036854775808".parse::(), None); + assert_eq!("9223372036854775807".parse::().ok(), Some(i64_val)); + assert_eq!("9223372036854775808".parse::().ok(), None); i64_val += 1 as i64; - assert_eq!("-9223372036854775808".parse::(), Some(i64_val)); - assert_eq!("-9223372036854775809".parse::(), None); + assert_eq!("-9223372036854775808".parse::().ok(), Some(i64_val)); + assert_eq!("-9223372036854775809".parse::().ok(), None); } } diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index 938755113b5..f2a1b0ac584 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -10,9 +10,9 @@ #[test] fn test_bool_from_str() { - assert_eq!("true".parse(), Some(true)); - assert_eq!("false".parse(), Some(false)); - assert_eq!("not even a boolean".parse::(), None); + assert_eq!("true".parse().ok(), Some(true)); + assert_eq!("false".parse().ok(), Some(false)); + assert_eq!("not even a boolean".parse::().ok(), None); } fn check_contains_all_substrings(s: &str) { diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs index edd93358bfa..46b9b2ed865 100644 --- a/src/liblog/directive.rs +++ b/src/liblog/directive.rs @@ -22,7 +22,7 @@ pub static LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", /// Parse an individual log level that is either a number or a symbolic log level fn parse_log_level(level: &str) -> Option { - level.parse::().or_else(|| { + level.parse::().ok().or_else(|| { let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); pos.map(|p| p as u32 + 1) }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index f13814527cd..664914f2e4c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -254,7 +254,7 @@ impl LintPass for TypeLimits { let lit_val: f64 = match lit.node { ast::LitFloat(ref v, _) | ast::LitFloatUnsuffixed(ref v) => { - match v.parse() { + match v.parse().ok() { Some(f) => f, None => return } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 933fd873aeb..bb4b52378ea 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -223,7 +223,7 @@ fn each_reexport(d: rbml::Doc, f: F) -> bool where fn variant_disr_val(d: rbml::Doc) -> Option { reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { reader::with_doc_data(val_doc, |data| { - str::from_utf8(data).ok().and_then(|s| s.parse()) + str::from_utf8(data).ok().and_then(|s| s.parse().ok()) }) }) } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 943479ff35e..6d19107096a 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -717,12 +717,16 @@ pub fn parse_def_id(buf: &[u8]) -> ast::DefId { let crate_part = &buf[0u..colon_idx]; let def_part = &buf[colon_idx + 1u..len]; - let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| s.parse::()) { + let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { + s.parse::().ok() + }) { Some(cn) => cn as ast::CrateNum, None => panic!("internal error: parse_def_id: crate number expected, found {:?}", crate_part) }; - let def_num = match str::from_utf8(def_part).ok().and_then(|s| s.parse::()) { + let def_num = match str::from_utf8(def_part).ok().and_then(|s| { + s.parse::().ok() + }) { Some(dn) => dn as ast::NodeId, None => panic!("internal error: parse_def_id: id expected, found {:?}", def_part) diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs index 215c4945ea9..92d8419484a 100644 --- a/src/librustc/middle/infer/region_inference/graphviz.rs +++ b/src/librustc/middle/infer/region_inference/graphviz.rs @@ -59,7 +59,7 @@ pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a, } let requested_node : Option = - os::getenv("RUST_REGION_GRAPH_NODE").and_then(|s| s.parse()); + os::getenv("RUST_REGION_GRAPH_NODE").and_then(|s| s.parse().ok()); if requested_node.is_some() && requested_node != Some(subject_node) { return; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index 81cbdf13c51..da83833fba3 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -18,7 +18,6 @@ use session::Session; use syntax::ast; use syntax::attr::AttrMetaMethods; -use std::str::FromStr; pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) { for attr in krate.attrs.iter() { @@ -27,7 +26,7 @@ pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) { } if let Some(s) = attr.value_str() { - if let Some(n) = FromStr::from_str(s.get()) { + if let Some(n) = s.parse().ok() { sess.recursion_limit.set(n); return; } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2fc68e6244a..125fbaa40e0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -424,7 +424,7 @@ macro_rules! options { } fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool { - match v.and_then(|s| s.parse()) { + match v.and_then(|s| s.parse().ok()) { Some(i) => { *slot = i; true }, None => false } @@ -432,7 +432,7 @@ macro_rules! options { fn parse_opt_uint(slot: &mut Option, v: Option<&str>) -> bool { match v { - Some(s) => { *slot = s.parse(); slot.is_some() } + Some(s) => { *slot = s.parse().ok(); slot.is_some() } None => { *slot = None; true } } } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 4ee13f5a542..bd7ad51de37 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -99,7 +99,7 @@ pub fn parse_pretty(sess: &Session, } } }; - let opt_second = opt_second.and_then(|s| s.parse::()); + let opt_second = opt_second.and_then(|s| s.parse::().ok()); (first, opt_second) } @@ -345,13 +345,11 @@ pub enum UserIdentifiedItem { } impl FromStr for UserIdentifiedItem { - fn from_str(s: &str) -> Option { - s.parse().map(ItemViaNode).or_else(|| { - let v : Vec<_> = s.split_str("::") - .map(|x|x.to_string()) - .collect(); - Some(ItemViaPath(v)) - }) + type Err = (); + fn from_str(s: &str) -> Result { + Ok(s.parse().map(ItemViaNode).unwrap_or_else(|_| { + ItemViaPath(s.split_str("::").map(|s| s.to_string()).collect()) + })) } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 2e7a6fd4923..b50f12deb44 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2127,7 +2127,7 @@ macro_rules! read_primitive { Json::F64(f) => Err(ExpectedError("Integer".to_string(), format!("{}", f))), // re: #12967.. a type w/ numeric keys (ie HashMap etc) // is going to have a string here, as per JSON spec. - Json::String(s) => match s.parse() { + Json::String(s) => match s.parse().ok() { Some(f) => Ok(f), None => Err(ExpectedError("Number".to_string(), s)), }, @@ -2165,7 +2165,7 @@ impl ::Decoder for Decoder { Json::String(s) => { // re: #12967.. a type w/ numeric keys (ie HashMap etc) // is going to have a string here, as per JSON spec. - match s.parse() { + match s.parse().ok() { Some(f) => Ok(f), None => Err(ExpectedError("Number".to_string(), s)), } @@ -2597,8 +2597,9 @@ impl<'a, T: Encodable> fmt::Display for AsPrettyJson<'a, T> { } impl FromStr for Json { - fn from_str(s: &str) -> Option { - from_str(s).ok() + type Err = BuilderError; + fn from_str(s: &str) -> Result { + from_str(s) } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index 82c55d7b5b8..4cd6391318f 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -20,7 +20,7 @@ mod tests { use num::FromStrRadix; fn from_str(t: &str) -> Option { - ::str::FromStr::from_str(t) + ::str::FromStr::from_str(t).ok() } #[test] @@ -38,15 +38,15 @@ mod tests { #[test] pub fn test_parse_bytes() { - assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123u as $T)); - assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9u as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83u as $T)); - assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291u as u16)); - assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535u as u16)); - assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 10), Ok(123u as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Ok(9u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Ok(83u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Ok(291u as u16)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Ok(65535u as u16)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Ok(35u as $T)); - assert_eq!(FromStrRadix::from_str_radix("Z", 10), None::<$T>); - assert_eq!(FromStrRadix::from_str_radix("_", 2), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("Z", 10).ok(), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("_", 2).ok(), None::<$T>); } #[test] diff --git a/src/libstd/old_io/net/ip.rs b/src/libstd/old_io/net/ip.rs index f0b73bd37f2..3e2e69f75a6 100644 --- a/src/libstd/old_io/net/ip.rs +++ b/src/libstd/old_io/net/ip.rs @@ -25,7 +25,7 @@ use iter::{Iterator, IteratorExt}; use ops::{FnOnce, FnMut}; use option::Option; use option::Option::{None, Some}; -use result::Result::{Ok, Err}; +use result::Result::{self, Ok, Err}; use slice::SliceExt; use str::{FromStr, StrExt}; use vec::Vec; @@ -350,17 +350,28 @@ impl<'a> Parser<'a> { } impl FromStr for IpAddr { - fn from_str(s: &str) -> Option { - Parser::new(s).read_till_eof(|p| p.read_ip_addr()) + type Err = ParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) { + Some(s) => Ok(s), + None => Err(ParseError), + } } } impl FromStr for SocketAddr { - fn from_str(s: &str) -> Option { - Parser::new(s).read_till_eof(|p| p.read_socket_addr()) + type Err = ParseError; + fn from_str(s: &str) -> Result { + match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) { + Some(s) => Ok(s), + None => Err(ParseError), + } } } +#[derive(Show, Clone, PartialEq, Copy)] +pub struct ParseError; + /// A trait for objects which can be converted or resolved to one or more `SocketAddr` values. /// /// Implementing types minimally have to implement either `to_socket_addr` or `to_socket_addr_all` @@ -493,7 +504,7 @@ fn parse_and_resolve_socket_addr(s: &str) -> IoResult> { let mut parts_iter = s.rsplitn(2, ':'); let port_str = try_opt!(parts_iter.next(), "invalid socket address"); let host = try_opt!(parts_iter.next(), "invalid socket address"); - let port: u16 = try_opt!(FromStr::from_str(port_str), "invalid port value"); + let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); resolve_socket_addr(host, port) } @@ -502,7 +513,7 @@ impl<'a> ToSocketAddr for (&'a str, u16) { let (host, port) = *self; // try to parse the host as a regular IpAddr first - match FromStr::from_str(host) { + match host.parse().ok() { Some(addr) => return Ok(vec![SocketAddr { ip: addr, port: port @@ -518,7 +529,7 @@ impl<'a> ToSocketAddr for (&'a str, u16) { impl<'a> ToSocketAddr for &'a str { fn to_socket_addr(&self) -> IoResult { // try to parse as a regular SocketAddr first - match FromStr::from_str(*self) { + match self.parse().ok() { Some(addr) => return Ok(addr), None => {} } @@ -535,7 +546,7 @@ impl<'a> ToSocketAddr for &'a str { fn to_socket_addr_all(&self) -> IoResult> { // try to parse as a regular SocketAddr first - match FromStr::from_str(*self) { + match self.parse().ok() { Some(addr) => return Ok(vec![addr]), None => {} } @@ -553,95 +564,94 @@ mod test { #[test] fn test_from_str_ipv4() { - assert_eq!(Some(Ipv4Addr(127, 0, 0, 1)), FromStr::from_str("127.0.0.1")); - assert_eq!(Some(Ipv4Addr(255, 255, 255, 255)), FromStr::from_str("255.255.255.255")); - assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0")); + assert_eq!(Ok(Ipv4Addr(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr(0, 0, 0, 0)), "0.0.0.0".parse()); // out of range - let none: Option = FromStr::from_str("256.0.0.1"); + let none: Option = "256.0.0.1".parse().ok(); assert_eq!(None, none); // too short - let none: Option = FromStr::from_str("255.0.0"); + let none: Option = "255.0.0".parse().ok(); assert_eq!(None, none); // too long - let none: Option = FromStr::from_str("255.0.0.1.2"); + let none: Option = "255.0.0.1.2".parse().ok(); assert_eq!(None, none); // no number between dots - let none: Option = FromStr::from_str("255.0..1"); + let none: Option = "255.0..1".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_ipv6() { - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("0:0:0:0:0:0:0:0")); - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("0:0:0:0:0:0:0:1")); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), FromStr::from_str("::1")); - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), FromStr::from_str("::")); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - assert_eq!(Some(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - FromStr::from_str("2a02:6b8::11:11")); + assert_eq!(Ok(Ipv6Addr(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), + "2a02:6b8::11:11".parse()); // too long group - let none: Option = FromStr::from_str("::00000"); + let none: Option = "::00000".parse().ok(); assert_eq!(None, none); // too short - let none: Option = FromStr::from_str("1:2:3:4:5:6:7"); + let none: Option = "1:2:3:4:5:6:7".parse().ok(); assert_eq!(None, none); // too long - let none: Option = FromStr::from_str("1:2:3:4:5:6:7:8:9"); + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); assert_eq!(None, none); // triple colon - let none: Option = FromStr::from_str("1:2:::6:7:8"); + let none: Option = "1:2:::6:7:8".parse().ok(); assert_eq!(None, none); // two double colons - let none: Option = FromStr::from_str("1:2::6::8"); + let none: Option = "1:2::6::8".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), - FromStr::from_str("::192.0.2.33")); - assert_eq!(Some(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - FromStr::from_str("::FFFF:192.0.2.33")); - assert_eq!(Some(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - FromStr::from_str("64:ff9b::192.0.2.33")); - assert_eq!(Some(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33")); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0, 49152, 545)), + "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), + "::FFFF:192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse()); // colon after v4 - let none: Option = FromStr::from_str("::127.0.0.1:"); + let none: Option = "::127.0.0.1:".parse().ok(); assert_eq!(None, none); // not enough groups - let none: Option = FromStr::from_str("1.2.3.4.5:127.0.0.1"); + let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); assert_eq!(None, none); // too many groups - let none: Option = - FromStr::from_str("1.2.3.4.5:6:7:127.0.0.1"); + let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); assert_eq!(None, none); } #[test] fn test_from_str_socket_addr() { - assert_eq!(Some(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), - FromStr::from_str("77.88.21.11:80")); - assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), - FromStr::from_str("[2a02:6b8:0:1::1]:53")); - assert_eq!(Some(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), - FromStr::from_str("[::127.0.0.1]:22")); + assert_eq!(Ok(SocketAddr { ip: Ipv4Addr(77, 88, 21, 11), port: 80 }), + "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), port: 53 }), + "[2a02:6b8:0:1::1]:53".parse()); + assert_eq!(Ok(SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0x7F00, 1), port: 22 }), + "[::127.0.0.1]:22".parse()); // without port - let none: Option = FromStr::from_str("127.0.0.1"); + let none: Option = "127.0.0.1".parse().ok(); assert_eq!(None, none); // without port - let none: Option = FromStr::from_str("127.0.0.1:"); + let none: Option = "127.0.0.1:".parse().ok(); assert_eq!(None, none); // wrong brackets around v4 - let none: Option = FromStr::from_str("[127.0.0.1]:22"); + let none: Option = "[127.0.0.1]:22".parse().ok(); assert_eq!(None, none); // port out of range - let none: Option = FromStr::from_str("127.0.0.1:123456"); + let none: Option = "127.0.0.1:123456".parse().ok(); assert_eq!(None, none); } diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 588f724134e..72c41f2399e 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -19,6 +19,7 @@ use iter::{AdditiveIterator, Extend}; use iter::{Iterator, IteratorExt, Map}; use marker::Sized; use option::Option::{self, Some, None}; +use result::Result::{self, Ok, Err}; use slice::{AsSlice, Split, SliceExt, SliceConcatExt}; use str::{self, FromStr, StrExt}; use vec::Vec; @@ -86,11 +87,19 @@ impl Ord for Path { } impl FromStr for Path { - fn from_str(s: &str) -> Option { - Path::new_opt(s) + type Err = ParsePathError; + fn from_str(s: &str) -> Result { + match Path::new_opt(s) { + Some(p) => Ok(p), + None => Err(ParsePathError), + } } } +/// Valuelue indicating that a path could not be parsed from a string. +#[derive(Show, Clone, PartialEq, Copy)] +pub struct ParsePathError; + impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 88db27013ac..f3289492390 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -27,6 +27,7 @@ use mem; use option::Option::{self, Some, None}; #[cfg(stage0)] use ops::FullRange; +use result::Result::{self, Ok, Err}; use slice::{SliceExt, SliceConcatExt}; use str::{SplitTerminator, FromStr, StrExt}; use string::{String, ToString}; @@ -115,11 +116,19 @@ impl Ord for Path { } impl FromStr for Path { - fn from_str(s: &str) -> Option { - Path::new_opt(s) + type Err = ParsePathError; + fn from_str(s: &str) -> Result { + match Path::new_opt(s) { + Some(p) => Ok(p), + None => Err(ParsePathError), + } } } +/// Value indicating that a path could not be parsed from a string. +#[derive(Show, Clone, PartialEq, Copy)] +pub struct ParsePathError; + impl hash::Hash for Path { #[cfg(not(test))] #[inline] diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index 4023a0a4c10..f5727a38b69 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -51,7 +51,7 @@ pub fn min_stack() -> uint { 0 => {} n => return n - 1, } - let amt = os::getenv("RUST_MIN_STACK").and_then(|s| s.parse()); + let amt = os::getenv("RUST_MIN_STACK").and_then(|s| s.parse().ok()); let amt = amt.unwrap_or(2 * 1024 * 1024); // 0 is our sentinel value, so ensure that we'll never see 0 after // initialization has run @@ -64,7 +64,7 @@ pub fn min_stack() -> uint { pub fn default_sched_threads() -> uint { match os::getenv("RUST_THREADS") { Some(nstr) => { - let opt_n: Option = nstr.parse(); + let opt_n: Option = nstr.parse().ok(); match opt_n { Some(n) if n > 0 => n, _ => panic!("`RUST_THREADS` is `{}`, should be a positive integer", nstr) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 493a97c24cf..2cf6058a433 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -613,7 +613,7 @@ impl<'a> StringReader<'a> { // find the integer representing the name self.scan_digits(base); let encoded_name : u32 = self.with_str_from(start_bpos, |s| { - num::from_str_radix(s, 10).unwrap_or_else(|| { + num::from_str_radix(s, 10).ok().unwrap_or_else(|| { panic!("expected digits representing a name, got {:?}, {}, range [{:?},{:?}]", s, whence, start_bpos, self.last_pos); }) @@ -631,7 +631,7 @@ impl<'a> StringReader<'a> { let start_bpos = self.last_pos; self.scan_digits(base); let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| { - num::from_str_radix(s, 10).unwrap_or_else(|| { + num::from_str_radix(s, 10).ok().unwrap_or_else(|| { panic!("expected digits representing a ctxt, got {:?}, {}", s, whence); }) }); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 1c146968fd5..e7be876edbb 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -401,7 +401,7 @@ pub fn char_lit(lit: &str) -> (char, isize) { let msg2 = &msg[]; fn esc(len: usize, lit: &str) -> Option<(char, isize)> { - num::from_str_radix(&lit[2..len], 16) + num::from_str_radix(&lit[2..len], 16).ok() .and_then(char::from_u32) .map(|x| (x, len as isize)) } @@ -410,7 +410,7 @@ pub fn char_lit(lit: &str) -> (char, isize) { if lit.as_bytes()[2] == b'{' { let idx = lit.find('}').expect(msg2); let subslice = &lit[3..idx]; - num::from_str_radix(subslice, 16) + num::from_str_radix(subslice, 16).ok() .and_then(char::from_u32) .map(|x| (x, subslice.chars().count() as isize + 4)) } else { @@ -583,7 +583,7 @@ pub fn byte_lit(lit: &str) -> (u8, usize) { b'\'' => b'\'', b'0' => b'\0', _ => { - match ::std::num::from_str_radix::(&lit[2..4], 16) { + match ::std::num::from_str_radix::(&lit[2..4], 16).ok() { Some(c) => if c > 0xFF { panic!(err(2)) @@ -732,7 +732,7 @@ pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - let res: u64 = match ::std::num::from_str_radix(s, base) { + let res: u64 = match ::std::num::from_str_radix(s, base).ok() { Some(r) => r, None => { sd.span_err(sp, "int literal is too large"); 0 } }; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c4224db8e18..d99095eeba3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2459,7 +2459,7 @@ impl<'a> Parser<'a> { hi = self.span.hi; self.bump(); - let index = n.as_str().parse::(); + let index = n.as_str().parse::().ok(); match index { Some(n) => { let id = spanned(dot, hi, n); @@ -2479,7 +2479,7 @@ impl<'a> Parser<'a> { self.span_err(last_span, &format!("unexpected token: `{}`", n.as_str())[]); if fstr.chars().all(|x| "0123456789.".contains_char(x)) { - let float = match fstr.parse::() { + let float = match fstr.parse::().ok() { Some(f) => f, None => continue, }; diff --git a/src/libsyntax/show_span.rs b/src/libsyntax/show_span.rs index 57520257fe1..6492cd4b095 100644 --- a/src/libsyntax/show_span.rs +++ b/src/libsyntax/show_span.rs @@ -27,14 +27,15 @@ enum Mode { } impl FromStr for Mode { - fn from_str(s: &str) -> Option { + type Err = (); + fn from_str(s: &str) -> Result { let mode = match s { "expr" => Mode::Expression, "pat" => Mode::Pattern, "ty" => Mode::Type, - _ => return None + _ => return Err(()) }; - Some(mode) + Ok(mode) } } @@ -73,7 +74,7 @@ impl<'a, 'v> Visitor<'v> for ShowSpanVisitor<'a> { pub fn run(span_diagnostic: &diagnostic::SpanHandler, mode: &str, krate: &ast::Crate) { - let mode = match mode.parse() { + let mode = match mode.parse().ok() { Some(mode) => mode, None => return }; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 8fea6bb539f..e49efebfef4 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -74,7 +74,6 @@ use std::old_io; use std::iter::repeat; use std::num::{Float, Int}; use std::os; -use std::str::FromStr; use std::sync::mpsc::{channel, Sender}; use std::thread::{self, Thread}; use std::thunk::{Thunk, Invoke}; @@ -818,7 +817,7 @@ fn get_concurrency() -> uint { use std::rt; match os::getenv("RUST_TEST_TASKS") { Some(s) => { - let opt_n: Option = FromStr::from_str(s.as_slice()); + let opt_n: Option = s.parse().ok(); match opt_n { Some(n) if n > 0 => n, _ => panic!("RUST_TEST_TASKS is `{}`, should be a positive integer.", s) diff --git a/src/test/auxiliary/static-methods-crate.rs b/src/test/auxiliary/static-methods-crate.rs index 1b18571cf8c..6cb16f04ce1 100644 --- a/src/test/auxiliary/static-methods-crate.rs +++ b/src/test/auxiliary/static-methods-crate.rs @@ -19,7 +19,7 @@ pub trait read { impl read for int { fn readMaybe(s: String) -> Option { - s.parse() + s.parse().ok() } } diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 7fad2c9b4be..15a63e153b9 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -232,7 +232,7 @@ fn main() { } else { std::os::args().as_slice() .get(1) - .and_then(|arg| arg.parse()) + .and_then(|arg| arg.parse().ok()) .unwrap_or(600u) }; diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index e12a9e7cb16..03666c84d57 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -182,7 +182,7 @@ fn fannkuch(n: i32) -> (i32, i32) { fn main() { let n = std::os::args().as_slice() .get(1) - .and_then(|arg| arg.parse()) + .and_then(|arg| arg.parse().ok()) .unwrap_or(2i32); let (checksum, maxflips) = fannkuch(n); diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 7325b8a4738..b2161000322 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -174,7 +174,7 @@ fn main() { 5000000 } else { std::os::args().get(1) - .and_then(|arg| arg.parse()) + .and_then(|arg| arg.parse().ok()) .unwrap_or(1000) }; let mut bodies = BODIES; diff --git a/src/test/bench/shootout-threadring.rs b/src/test/bench/shootout-threadring.rs index 47f17997e84..ebe8a0751c3 100644 --- a/src/test/bench/shootout-threadring.rs +++ b/src/test/bench/shootout-threadring.rs @@ -68,10 +68,10 @@ fn main() { let token = if std::os::getenv("RUST_BENCH").is_some() { 2000000 } else { - args.get(1).and_then(|arg| arg.parse()).unwrap_or(1000) + args.get(1).and_then(|arg| arg.parse().ok()).unwrap_or(1000) }; let n_tasks = args.get(2) - .and_then(|arg| arg.parse()) + .and_then(|arg| arg.parse().ok()) .unwrap_or(503); start(n_tasks, token); diff --git a/src/test/run-pass/match-with-ret-arm.rs b/src/test/run-pass/match-with-ret-arm.rs index a1537e63e57..05c6aac90e3 100644 --- a/src/test/run-pass/match-with-ret-arm.rs +++ b/src/test/run-pass/match-with-ret-arm.rs @@ -14,7 +14,7 @@ pub fn main() { // sometimes we have had trouble finding // the right type for f, as we unified // bot and u32 here - let f = match "1234".parse::() { + let f = match "1234".parse::().ok() { None => return (), Some(num) => num as u32 }; diff --git a/src/test/run-pass/wait-forked-but-failed-child.rs b/src/test/run-pass/wait-forked-but-failed-child.rs index ef48bdff11d..12de40129fd 100644 --- a/src/test/run-pass/wait-forked-but-failed-child.rs +++ b/src/test/run-pass/wait-forked-but-failed-child.rs @@ -41,7 +41,7 @@ fn find_zombies() { if 0 < line_no && 0 < line.len() && my_pid == line.split(' ').filter(|w| 0 < w.len()).nth(1) .expect("1st column should be PPID") - .parse() + .parse().ok() .expect("PPID string into integer") && line.contains("defunct") { panic!("Zombie child {}", line);