diff --git a/src/bigint.rs b/src/bigint.rs index 78b2818..3e6ae9a 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -60,7 +60,10 @@ extern crate "rustc-serialize" as rustc_serialize; use Integer; +use core::num::ParseIntError; + use std::default::Default; +use std::error::{Error, FromError}; use std::iter::repeat; use std::num::{Int, ToPrimitive, FromPrimitive, FromStrRadix}; 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 { + type Err = ParseBigIntError; + #[inline] - fn from_str(s: &str) -> Option { + fn from_str(s: &str) -> Result { FromStrRadix::from_str_radix(s, 10) } } @@ -815,13 +820,15 @@ fn to_str_radix_signed(me: &BigInt, radix: usize) -> String { } impl FromStrRadix for BigUint { + type Err = ParseBigIntError; + /// Creates and initializes a `BigUint`. #[inline] - fn from_str_radix(s: &str, radix: usize) -> Option { + fn from_str_radix(s: &str, radix: usize) -> Result { let (base, unit_len) = get_radix_base(radix); let base_num = match base.to_biguint() { Some(base_num) => base_num, - None => { return None; } + None => { return Err(ParseBigIntError::Other); } }; let mut end = s.len(); @@ -829,22 +836,18 @@ impl FromStrRadix for BigUint { let mut power: BigUint = One::one(); loop { 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 = FromPrimitive::from_uint(d); + match d { Some(d) => { - let d: Option = FromPrimitive::from_uint(d); - match d { - Some(d) => { - // FIXME(#5992): assignment operator overloads - // n += d * &power; - n = n + d * &power; - } - None => { return None; } - } + // FIXME(#5992): assignment operator overloads + // n += d * &power; + n = n + d * &power; } - None => { return None; } + None => { return Err(ParseBigIntError::Other); } } if end <= unit_len { - return Some(n); + return Ok(n); } end -= unit_len; // FIXME(#5992): assignment operator overloads @@ -956,7 +959,7 @@ impl BigUint { /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: usize) -> Option { - 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] @@ -1110,8 +1113,10 @@ impl hash::Hash for BigInt { } impl FromStr for BigInt { + type Err = ParseBigIntError; + #[inline] - fn from_str(s: &str) -> Option { + fn from_str(s: &str) -> Result { 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 FromStrRadix for BigInt { + type Err = ParseBigIntError; + /// Creates and initializes a BigInt. #[inline] - fn from_str_radix(s: &str, radix: usize) -> Option { - if s.is_empty() { return None; } + fn from_str_radix(s: &str, radix: usize) -> Result { + if s.is_empty() { return Err(ParseBigIntError::Other); } let mut sign = Plus; let mut start = 0; if s.starts_with("-") { @@ -1703,7 +1710,7 @@ impl BigInt { /// ``` #[inline] pub fn parse_bytes(buf: &[u8], radix: usize) -> Option { - 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 for ParseBigIntError { + fn from_error(err: ParseIntError) -> ParseBigIntError { + ParseBigIntError::ParseInt(err) + } +} + #[cfg(test)] mod biguint_tests { use Integer; @@ -1929,7 +1961,7 @@ mod biguint_tests { #[test] fn test_shl() { fn check(s: &str, shift: usize, ans: &str) { - let opt_biguint: Option = FromStrRadix::from_str_radix(s, 16); + let opt_biguint: Option = FromStrRadix::from_str_radix(s, 16).ok(); let bu = to_str_radix(&(opt_biguint.unwrap() << shift), 16); assert_eq!(bu.as_slice(), ans); } @@ -2051,7 +2083,7 @@ mod biguint_tests { fn test_shr() { fn check(s: &str, shift: usize, ans: &str) { let opt_biguint: Option = - FromStrRadix::from_str_radix(s, 16); + FromStrRadix::from_str_radix(s, 16).ok(); let bu = to_str_radix(&(opt_biguint.unwrap() >> shift), 16); assert_eq!(bu.as_slice(), ans); } @@ -2571,12 +2603,12 @@ mod biguint_tests { } } - let zed: Option = FromStrRadix::from_str_radix("Z", 10); + let zed: Option = FromStrRadix::from_str_radix("Z", 10).ok(); assert_eq!(zed, None); - let blank: Option = FromStrRadix::from_str_radix("_", 2); + let blank: Option = FromStrRadix::from_str_radix("_", 2).ok(); assert_eq!(blank, None); let minus_one: Option = FromStrRadix::from_str_radix("-1", - 10); + 10).ok(); assert_eq!(minus_one, None); } @@ -2596,7 +2628,7 @@ mod biguint_tests { fn check(n: usize, s: &str) { let n = factor(n); let ans = match FromStrRadix::from_str_radix(s, 10) { - Some(x) => x, None => panic!() + Ok(x) => x, Err(_) => panic!() }; assert_eq!(n, ans); } @@ -3256,7 +3288,7 @@ mod bigint_tests { let x: BigInt = FromPrimitive::from_int(n).unwrap(); 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("1", Some(1)); diff --git a/src/lib.rs b/src/lib.rs index 5f5ad45..cdbfbd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ //! //! [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))] #![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", @@ -54,6 +54,7 @@ #![allow(unstable)] extern crate "rustc-serialize" as rustc_serialize; +extern crate core; pub use bigint::{BigInt, BigUint}; pub use rational::{Rational, BigRational}; diff --git a/src/rational.rs b/src/rational.rs index a37dd07..dde3a9e 100644 --- a/src/rational.rs +++ b/src/rational.rs @@ -13,6 +13,7 @@ use Integer; use std::cmp; +use std::error::Error; use std::fmt; use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use std::str::FromStr; @@ -419,42 +420,60 @@ impl fmt::Display for Ratio { impl FromStr for Ratio { + type Err = ParseRatioError; + /// Parses `numer/denom` or just `numer`. - fn from_str(s: &str) -> Option> { + fn from_str(s: &str) -> Result, ParseRatioError> { let mut split = s.splitn(1, '/'); - let num = split.next().and_then(|n| FromStr::from_str(n)); - let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d)); + let n = try!(split.next().ok_or(ParseRatioError)); + let num = try!(FromStr::from_str(n).map_err(|_| ParseRatioError)); - match (num, den) { - (Some(n), Some(d)) => Some(Ratio::new(n, d)), - _ => None - } + let d = split.next().unwrap_or("1"); + let den = try!(FromStr::from_str(d).map_err(|_| ParseRatioError)); + + Ok(Ratio::new(num, den)) } } impl FromStrRadix for Ratio { + type Err = ParseRatioError; + /// Parses `numer/denom` where the numbers are in base `radix`. - fn from_str_radix(s: &str, radix: usize) -> Option> { + fn from_str_radix(s: &str, radix: usize) -> Result, ParseRatioError> { let split: Vec<&str> = s.splitn(1, '/').collect(); if split.len() < 2 { - None + Err(ParseRatioError) } else { - let a_option: Option = FromStrRadix::from_str_radix( + let a_result: Result = FromStrRadix::from_str_radix( split[0], - radix); - a_option.and_then(|a| { - let b_option: Option = - FromStrRadix::from_str_radix(split[1], radix); - b_option.and_then(|b| { - Some(Ratio::new(a.clone(), b.clone())) + radix).map_err(|_| ParseRatioError); + a_result.and_then(|a| { + let b_result: Result = + FromStrRadix::from_str_radix(split[1], radix).map_err(|_| ParseRatioError); + b_result.and_then(|b| { + 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)] mod test { @@ -740,7 +759,7 @@ mod test { #[test] fn test_to_from_str() { 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); } test(_1, "1".to_string()); @@ -753,8 +772,8 @@ mod test { #[test] fn test_from_str_fail() { fn test(s: &str) { - let rational: Option = FromStr::from_str(s); - assert_eq!(rational, None); + let rational: Result = FromStr::from_str(s); + assert!(rational.is_err()); } let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];