Skip to content

Commit

Permalink
Merge pull request #87 from ncalexan/map-errors
Browse files Browse the repository at this point in the history
Add map functions for Error<> and Info<> ranges. (#86)
  • Loading branch information
Marwes authored Feb 20, 2017
2 parents 6f2cec6 + 9f77f43 commit f317fe7
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,4 +483,73 @@ mod tests {
err
});
}

#[test]
fn extract_std_error() {
// The previous test verified that we could map a ParseError to a StdError by dropping the
// internal error details. This test verifies that we can map a ParseError to a StdError
// without dropping the internal error details. Consumers using `error-chain` will
// appreciate this. For technical reasons this is pretty janky; see the discussion in
// https://github.com/Marwes/combine/issues/86, and excuse the test with significant
// boilerplate!
use std::fmt;
use std::error::Error as StdError;

#[derive(Clone, PartialEq, Debug)]
struct CloneOnly(String);

#[derive(Debug)]
struct DisplayVec<T>(Vec<T>);

#[derive(Debug)]
struct ExtractedError(usize, DisplayVec<Error<CloneOnly, DisplayVec<CloneOnly>>>);

impl StdError for ExtractedError {
fn description(&self) -> &str {
"extracted error"
}
}

impl fmt::Display for CloneOnly {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

impl<T: fmt::Debug> fmt::Display for DisplayVec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{:?}]", self.0)
}
}

impl fmt::Display for ExtractedError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "Parse error at {}", self.0));
Error::fmt_errors(&(self.1).0, f)
}
}

let input = &[CloneOnly("x".to_string()), CloneOnly("y".to_string())][..];
let result = token(CloneOnly("z".to_string()))
.parse(input)
.map_err(|e| e.translate_position(input))
.map_err(|e| {
ExtractedError(e.position,
DisplayVec(e.errors
.into_iter()
.map(|e| e.map_range(|r| DisplayVec(r.to_owned())))
.collect()))
});

assert!(result.is_err());
// Test that the fresh ExtractedError is Display, so that the internal errors can be
// inspected by consuming code; and that the ExtractedError can be coerced to StdError.
let _ = result.map_err(|err| {
let s = format!("{}", err);
assert!(s.starts_with("Parse error at 0"));
assert!(s.contains("Expected"));
let err: Box<StdError> = Box::new(err);
err
});
}
}
44 changes: 44 additions & 0 deletions src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ pub enum Info<T, R> {
Borrowed(&'static str),
}

impl<T, R> Info<T, R> {
pub fn map_token<F, U>(self, f: F) -> Info<U, R> where F: FnOnce(T) -> U {
use self::Info::*;
match self {
Token(t) => Token(f(t)),
Range(r) => Range(r),
Owned(s) => Owned(s),
Borrowed(x) => Borrowed(x),
}
}

pub fn map_range<F, S>(self, f: F) -> Info<T, S> where F: FnOnce(R) -> S {
use self::Info::*;
match self {
Token(t) => Token(t),
Range(r) => Range(f(r)),
Owned(s) => Owned(s),
Borrowed(x) => Borrowed(x),
}
}
}

impl<T: PartialEq, R: PartialEq> PartialEq for Info<T, R> {
fn eq(&self, other: &Info<T, R>) -> bool {
match (self, other) {
Expand Down Expand Up @@ -110,6 +132,28 @@ pub enum Error<T, R> {
Other(Box<StdError + Send + Sync>),
}

impl<T, R> Error<T, R> {
pub fn map_token<F, U>(self, f: F) -> Error<U, R> where F: FnOnce(T) -> U {
use self::Error::*;
match self {
Unexpected(x) => Unexpected(x.map_token(f)),
Expected(x) => Expected(x.map_token(f)),
Message(x) => Message(x.map_token(f)),
Other(x) => Other(x),
}
}

pub fn map_range<F, S>(self, f: F) -> Error<T, S> where F: FnOnce(R) -> S {
use self::Error::*;
match self {
Unexpected(x) => Unexpected(x.map_range(f)),
Expected(x) => Expected(x.map_range(f)),
Message(x) => Message(x.map_range(f)),
Other(x) => Other(x),
}
}
}

impl<T: PartialEq, R: PartialEq> PartialEq for Error<T, R> {
fn eq(&self, other: &Error<T, R>) -> bool {
match (self, other) {
Expand Down

0 comments on commit f317fe7

Please sign in to comment.