Skip to content

Commit

Permalink
Merge pull request #4 from kherge/enhancement/3
Browse files Browse the repository at this point in the history
Enhancement/3
  • Loading branch information
kherge authored Jan 18, 2022
2 parents 063b700 + 8691a5f commit edede96
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --all-features
args: --all-targets --all-features -- -D warnings
93 changes: 79 additions & 14 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
//! No such file or directory (os error 2)
//! ```
use std::{fmt, io, process, sync};
use std::{fmt, process};

/// A trait to add context to an error result.
///
Expand Down Expand Up @@ -265,22 +265,42 @@ impl fmt::Display for Error {
}
}

impl From<io::Error> for Error {
fn from(error: io::Error) -> Self {
Self {
context: None,
message: Some(error.to_string()),
status: error.raw_os_error().unwrap_or(1),
impl<T: std::error::Error + 'static> From<T> for Error {
fn from(error: T) -> Self {
let mut context = None;
let mut current = &error as &dyn std::error::Error;
let message;
let mut status = 1;

// Allow for error source traversal.
loop {
// If not at the lowest level, capture the error as context.
if let Some(next) = current.source() {
context
.get_or_insert_with(Vec::new)
.push(current.to_string());

current = next;

// If at the lowest level, capture the message.
} else {
message = Some(current.to_string());

// If std::io::Error, capture the OS error code as the status.
if let Some(other) = current.downcast_ref::<std::io::Error>() {
if let Some(code) = other.raw_os_error() {
status = code;
}
}

break;
}
}
}
}

impl<T> From<sync::PoisonError<T>> for Error {
fn from(error: sync::PoisonError<T>) -> Self {
Self {
context: None,
message: Some(error.to_string()),
status: 1,
context,
message,
status,
}
}
}
Expand Down Expand Up @@ -594,6 +614,51 @@ mod test {
);
}

#[test]
fn from_error() {
fn generate_error() -> Result<()> {
fn source_error() -> Result<()> {
let _ = std::fs::File::open("/should/not/exist")?;

Ok(())
}

source_error().context(|| "The lower level message.")?;

Ok(())
}

let error = generate_error()
.context(|| "The higher level message.")
.unwrap_err();

assert_eq!(
error.context,
Some(vec![
"The lower level message.".to_string(),
"The higher level message.".to_string()
])
);

#[cfg(not(windows))]
{
assert_eq!(
error.message,
Some("No such file or directory (os error 2)".to_string())
);
assert_eq!(error.status, 2);
}

#[cfg(windows)]
{
assert_eq!(
error.message,
Some("The system cannot find the path specified. (os error 3)".to_string())
);
assert_eq!(error.status, 3);
}
}

#[test]
fn result_context() {
let err: Result<()> = Err(Error::default()).context(|| "The context message.");
Expand Down
2 changes: 1 addition & 1 deletion src/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ mod test {

assert_eq!(vec, b"test");
} else {
assert!(false, "Unexpected StreamKind.");
panic!("Unexpected StreamKind.");
}
}

Expand Down

0 comments on commit edede96

Please sign in to comment.