Update FromStr and FromStrRadix to return Result

Fixes build errors with Rust 1.0.0-nightly.
This commit is contained in:
Matt Brubeck 2015-02-03 11:42:46 -08:00
parent b324415930
commit 42edb63090
3 changed files with 99 additions and 47 deletions

View File

@ -60,7 +60,10 @@ extern crate "rustc-serialize" as rustc_serialize;
use Integer; use Integer;
use core::num::ParseIntError;
use std::default::Default; use std::default::Default;
use std::error::{Error, FromError};
use std::iter::repeat; use std::iter::repeat;
use std::num::{Int, ToPrimitive, FromPrimitive, FromStrRadix}; use std::num::{Int, ToPrimitive, FromPrimitive, FromStrRadix};
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Rem, Shl, Shr, Sub};
@ -181,8 +184,10 @@ impl fmt::Display for BigUint {
} }
impl FromStr for BigUint { impl FromStr for BigUint {
type Err = ParseBigIntError;
#[inline] #[inline]
fn from_str(s: &str) -> Option<BigUint> { fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
FromStrRadix::from_str_radix(s, 10) FromStrRadix::from_str_radix(s, 10)
} }
} }
@ -815,13 +820,15 @@ fn to_str_radix_signed(me: &BigInt, radix: usize) -> String {
} }
impl FromStrRadix for BigUint { impl FromStrRadix for BigUint {
type Err = ParseBigIntError;
/// Creates and initializes a `BigUint`. /// Creates and initializes a `BigUint`.
#[inline] #[inline]
fn from_str_radix(s: &str, radix: usize) -> Option<BigUint> { fn from_str_radix(s: &str, radix: usize) -> Result<BigUint, ParseBigIntError> {
let (base, unit_len) = get_radix_base(radix); let (base, unit_len) = get_radix_base(radix);
let base_num = match base.to_biguint() { let base_num = match base.to_biguint() {
Some(base_num) => base_num, Some(base_num) => base_num,
None => { return None; } None => { return Err(ParseBigIntError::Other); }
}; };
let mut end = s.len(); let mut end = s.len();
@ -829,22 +836,18 @@ impl FromStrRadix for BigUint {
let mut power: BigUint = One::one(); let mut power: BigUint = One::one();
loop { loop {
let start = cmp::max(end, unit_len) - unit_len; let start = cmp::max(end, unit_len) - unit_len;
match FromStrRadix::from_str_radix(&s[start .. end], radix) { let d = try!(FromStrRadix::from_str_radix(&s[start .. end], radix));
let d: Option<BigUint> = FromPrimitive::from_uint(d);
match d {
Some(d) => { Some(d) => {
let d: Option<BigUint> = FromPrimitive::from_uint(d); // FIXME(#5992): assignment operator overloads
match d { // n += d * &power;
Some(d) => { n = n + d * &power;
// FIXME(#5992): assignment operator overloads
// n += d * &power;
n = n + d * &power;
}
None => { return None; }
}
} }
None => { return None; } None => { return Err(ParseBigIntError::Other); }
} }
if end <= unit_len { if end <= unit_len {
return Some(n); return Ok(n);
} }
end -= unit_len; end -= unit_len;
// FIXME(#5992): assignment operator overloads // FIXME(#5992): assignment operator overloads
@ -956,7 +959,7 @@ impl BigUint {
/// ``` /// ```
#[inline] #[inline]
pub fn parse_bytes(buf: &[u8], radix: usize) -> Option<BigUint> { pub fn parse_bytes(buf: &[u8], radix: usize) -> Option<BigUint> {
str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix)) str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix).ok())
} }
#[inline] #[inline]
@ -1110,8 +1113,10 @@ impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for BigInt {
} }
impl FromStr for BigInt { impl FromStr for BigInt {
type Err = ParseBigIntError;
#[inline] #[inline]
fn from_str(s: &str) -> Option<BigInt> { fn from_str(s: &str) -> Result<BigInt, ParseBigIntError> {
FromStrRadix::from_str_radix(s, 10) FromStrRadix::from_str_radix(s, 10)
} }
} }
@ -1521,10 +1526,12 @@ impl_to_bigint!(u32, FromPrimitive::from_u32);
impl_to_bigint!(u64, FromPrimitive::from_u64); impl_to_bigint!(u64, FromPrimitive::from_u64);
impl FromStrRadix for BigInt { impl FromStrRadix for BigInt {
type Err = ParseBigIntError;
/// Creates and initializes a BigInt. /// Creates and initializes a BigInt.
#[inline] #[inline]
fn from_str_radix(s: &str, radix: usize) -> Option<BigInt> { fn from_str_radix(s: &str, radix: usize) -> Result<BigInt, ParseBigIntError> {
if s.is_empty() { return None; } if s.is_empty() { return Err(ParseBigIntError::Other); }
let mut sign = Plus; let mut sign = Plus;
let mut start = 0; let mut start = 0;
if s.starts_with("-") { if s.starts_with("-") {
@ -1703,7 +1710,7 @@ impl BigInt {
/// ``` /// ```
#[inline] #[inline]
pub fn parse_bytes(buf: &[u8], radix: usize) -> Option<BigInt> { pub fn parse_bytes(buf: &[u8], radix: usize) -> Option<BigInt> {
str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix)) str::from_utf8(buf).ok().and_then(|s| FromStrRadix::from_str_radix(s, radix).ok())
} }
@ -1741,6 +1748,31 @@ impl BigInt {
} }
} }
#[derive(Debug, PartialEq)]
pub enum ParseBigIntError {
ParseInt(ParseIntError),
Other,
}
impl fmt::Display for ParseBigIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&ParseBigIntError::ParseInt(ref e) => e.fmt(f),
&ParseBigIntError::Other => "failed to parse provided string".fmt(f)
}
}
}
impl Error for ParseBigIntError {
fn description(&self) -> &str { "failed to parse bigint/biguint" }
}
impl FromError<ParseIntError> for ParseBigIntError {
fn from_error(err: ParseIntError) -> ParseBigIntError {
ParseBigIntError::ParseInt(err)
}
}
#[cfg(test)] #[cfg(test)]
mod biguint_tests { mod biguint_tests {
use Integer; use Integer;
@ -1929,7 +1961,7 @@ mod biguint_tests {
#[test] #[test]
fn test_shl() { fn test_shl() {
fn check(s: &str, shift: usize, ans: &str) { fn check(s: &str, shift: usize, ans: &str) {
let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16); let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16).ok();
let bu = to_str_radix(&(opt_biguint.unwrap() << shift), 16); let bu = to_str_radix(&(opt_biguint.unwrap() << shift), 16);
assert_eq!(bu.as_slice(), ans); assert_eq!(bu.as_slice(), ans);
} }
@ -2051,7 +2083,7 @@ mod biguint_tests {
fn test_shr() { fn test_shr() {
fn check(s: &str, shift: usize, ans: &str) { fn check(s: &str, shift: usize, ans: &str) {
let opt_biguint: Option<BigUint> = let opt_biguint: Option<BigUint> =
FromStrRadix::from_str_radix(s, 16); FromStrRadix::from_str_radix(s, 16).ok();
let bu = to_str_radix(&(opt_biguint.unwrap() >> shift), 16); let bu = to_str_radix(&(opt_biguint.unwrap() >> shift), 16);
assert_eq!(bu.as_slice(), ans); assert_eq!(bu.as_slice(), ans);
} }
@ -2571,12 +2603,12 @@ mod biguint_tests {
} }
} }
let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10); let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10).ok();
assert_eq!(zed, None); assert_eq!(zed, None);
let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2); let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2).ok();
assert_eq!(blank, None); assert_eq!(blank, None);
let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1", let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1",
10); 10).ok();
assert_eq!(minus_one, None); assert_eq!(minus_one, None);
} }
@ -2596,7 +2628,7 @@ mod biguint_tests {
fn check(n: usize, s: &str) { fn check(n: usize, s: &str) {
let n = factor(n); let n = factor(n);
let ans = match FromStrRadix::from_str_radix(s, 10) { let ans = match FromStrRadix::from_str_radix(s, 10) {
Some(x) => x, None => panic!() Ok(x) => x, Err(_) => panic!()
}; };
assert_eq!(n, ans); assert_eq!(n, ans);
} }
@ -3256,7 +3288,7 @@ mod bigint_tests {
let x: BigInt = FromPrimitive::from_int(n).unwrap(); let x: BigInt = FromPrimitive::from_int(n).unwrap();
x x
}); });
assert_eq!(FromStrRadix::from_str_radix(s, 10), ans); assert_eq!(FromStrRadix::from_str_radix(s, 10).ok(), ans);
} }
check("10", Some(10)); check("10", Some(10));
check("1", Some(1)); check("1", Some(1));

View File

@ -44,7 +44,7 @@
//! //!
//! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method //! [newt]: https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method
#![feature(slicing_syntax)] #![feature(slicing_syntax, core)]
#![cfg_attr(test, deny(warnings))] #![cfg_attr(test, deny(warnings))]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
@ -54,6 +54,7 @@
#![allow(unstable)] #![allow(unstable)]
extern crate "rustc-serialize" as rustc_serialize; extern crate "rustc-serialize" as rustc_serialize;
extern crate core;
pub use bigint::{BigInt, BigUint}; pub use bigint::{BigInt, BigUint};
pub use rational::{Rational, BigRational}; pub use rational::{Rational, BigRational};

View File

@ -13,6 +13,7 @@
use Integer; use Integer;
use std::cmp; use std::cmp;
use std::error::Error;
use std::fmt; use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use std::str::FromStr; use std::str::FromStr;
@ -419,42 +420,60 @@ impl<T: fmt::Display + Eq + One> fmt::Display for Ratio<T> {
impl<T: FromStr + Clone + Integer + PartialOrd> impl<T: FromStr + Clone + Integer + PartialOrd>
FromStr for Ratio<T> { FromStr for Ratio<T> {
type Err = ParseRatioError;
/// Parses `numer/denom` or just `numer`. /// Parses `numer/denom` or just `numer`.
fn from_str(s: &str) -> Option<Ratio<T>> { fn from_str(s: &str) -> Result<Ratio<T>, ParseRatioError> {
let mut split = s.splitn(1, '/'); let mut split = s.splitn(1, '/');
let num = split.next().and_then(|n| FromStr::from_str(n)); let n = try!(split.next().ok_or(ParseRatioError));
let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d)); let num = try!(FromStr::from_str(n).map_err(|_| ParseRatioError));
match (num, den) { let d = split.next().unwrap_or("1");
(Some(n), Some(d)) => Some(Ratio::new(n, d)), let den = try!(FromStr::from_str(d).map_err(|_| ParseRatioError));
_ => None
} Ok(Ratio::new(num, den))
} }
} }
impl<T: FromStrRadix + Clone + Integer + PartialOrd> impl<T: FromStrRadix + Clone + Integer + PartialOrd>
FromStrRadix for Ratio<T> { FromStrRadix for Ratio<T> {
type Err = ParseRatioError;
/// Parses `numer/denom` where the numbers are in base `radix`. /// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: usize) -> Option<Ratio<T>> { fn from_str_radix(s: &str, radix: usize) -> Result<Ratio<T>, ParseRatioError> {
let split: Vec<&str> = s.splitn(1, '/').collect(); let split: Vec<&str> = s.splitn(1, '/').collect();
if split.len() < 2 { if split.len() < 2 {
None Err(ParseRatioError)
} else { } else {
let a_option: Option<T> = FromStrRadix::from_str_radix( let a_result: Result<T, _> = FromStrRadix::from_str_radix(
split[0], split[0],
radix); radix).map_err(|_| ParseRatioError);
a_option.and_then(|a| { a_result.and_then(|a| {
let b_option: Option<T> = let b_result: Result<T, _> =
FromStrRadix::from_str_radix(split[1], radix); FromStrRadix::from_str_radix(split[1], radix).map_err(|_| ParseRatioError);
b_option.and_then(|b| { b_result.and_then(|b| {
Some(Ratio::new(a.clone(), b.clone())) Ok(Ratio::new(a.clone(), b.clone()))
}) })
}) })
} }
} }
} }
// FIXME: Bubble up specific errors
#[derive(Copy, Debug, PartialEq)]
pub struct ParseRatioError;
impl fmt::Display for ParseRatioError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"failed to parse provided string".fmt(f)
}
}
impl Error for ParseRatioError {
fn description(&self) -> &str { "failed to parse bigint/biguint" }
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -740,7 +759,7 @@ mod test {
#[test] #[test]
fn test_to_from_str() { fn test_to_from_str() {
fn test(r: Rational, s: String) { fn test(r: Rational, s: String) {
assert_eq!(FromStr::from_str(&s[]), Some(r)); assert_eq!(FromStr::from_str(&s[]), Ok(r));
assert_eq!(r.to_string(), s); assert_eq!(r.to_string(), s);
} }
test(_1, "1".to_string()); test(_1, "1".to_string());
@ -753,8 +772,8 @@ mod test {
#[test] #[test]
fn test_from_str_fail() { fn test_from_str_fail() {
fn test(s: &str) { fn test(s: &str) {
let rational: Option<Rational> = FromStr::from_str(s); let rational: Result<Rational, _> = FromStr::from_str(s);
assert_eq!(rational, None); assert!(rational.is_err());
} }
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"]; let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];