#![warn(missing_docs)]
use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::str::FromStr;
pub use Error::*;
#[doc(inline)]
pub trait ParseResult<E> {
fn parse<F>(self) -> Result<F, Error<E, F::Err>>
where F: FromStr;
}
#[derive(Debug, PartialEq, Eq)]
pub enum Error<E, P> {
OriginalErr(E),
ParseFailure(P)
}
impl<T, E> ParseResult<E> for Result<T, E>
where T: AsRef<str> {
fn parse<F>(self) -> Result<F, Error<E, F::Err>>
where F: FromStr {
self.map_err(OriginalErr)
.and_then(|s| s.as_ref().parse().map_err(ParseFailure))
}
}
impl<E, P> StdError for Error<E, P>
where E: StdError, P: StdError {
fn description(&self) -> &str {
match *self {
OriginalErr(ref e) => e.description(),
ParseFailure(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&StdError> {
match *self {
OriginalErr(ref e) => Some(e),
ParseFailure(ref e) => Some(e),
}
}
}
impl<E, P> Display for Error<E, P>
where E: Display, P: Display {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
OriginalErr(ref e) => e.fmt(f),
ParseFailure(ref e) => e.fmt(f),
}
}
}
#[test]
fn parses_ok_with_type_inference() {
let val: Result<&str, ()> = Ok("42");
assert_eq!(val.parse(), Ok(42));
}
#[test]
fn allows_turbofish_usage() {
use std::any::Any;
use std::net::{IpAddr, AddrParseError};
let val: Result<&str, &str> = Ok("42");
if let Err(ParseFailure(err)) = val.parse::<IpAddr>() {
assert!(Any::is::<AddrParseError>(&err));
} else {
panic!("Should have failed to parse as an IpAddr");
}
assert_eq!(val.parse::<u32>(), Ok(42));
assert_eq!(val.parse::<i64>(), Ok(42));
}
#[test]
fn fails_to_parse_an_original_err() {
let val: Result<&str, &str> = Err("Failed to load data");
assert_eq!(val.parse::<i32>(), Err(OriginalErr("Failed to load data")));
}
#[test]
fn returns_parse_error_on_parse_failure() {
use std::any::Any;
use std::num::ParseIntError;
let val: Result<&str, &str> = Ok("hello");
if let Err(ParseFailure(err)) = val.parse::<i32>() {
assert!(Any::is::<ParseIntError>(&err));
} else {
panic!("Should have failed to parse as an i32");
}
}
#[test]
fn boxed_error_works() {
use std::env;
use std::error::Error;
fn get_port() -> Result<u16, Box<Error>> {
Ok(try!(env::var("PORT").parse()))
}
assert!(get_port().is_err())
}