The aim of this library is to support writing command line programs in Rust by simplifying error handling in program code.
It introduces Problem
type which can be used on high level APIs for which error handling boils down to:
* reporting error message (e.g. log with error!
macro),
* aborting program on error other than a bug (e.g. using panic!
macro),
* ignoring error.
Display
formattingOk
pathErr
path - e.g. zero allocationSync
and Send
compatibilityProblem
type is core of this library. It is basically a wrapper around String
.
In order to support conversion from types implementing Error
trait it does not implement this trait.
When converting other errors to Problem
the Display
message is produced of the original error and stored in Problem
as cause message.
Additionally Problem
can also store message and another Problem
which allows for nesting multiple contexts and problem causes.
There are multiple ways to crate Problem
value.
Using Problem::cause(msg)
function.
rust,skt-problem
Problem::cause("foo");
Types implementing Error
trait can be converted to Problem
via From
trait so that ?
will work.
rust,skt-problem
fn foo() -> Result<String, Problem> {
let str = String::from_utf8(vec![0, 123, 255])?;
Ok(str)
}
assert_eq!(foo().unwrap_err().to_string(), "invalid utf-8 sequence of 1 bytes from index 2");
Any type that implements ToString
or Display
can be converted to Problem
with .to_problem()
.
rust,skt-problem
assert_eq!("oops".to_problem().to_string(), "oops");
Often when working with C libraries actual errors may be unknown and function Result
will have Option<impl Error>
for their Err
variant type.
.to_problem()
method is implemented for Option<E>
and will contain "\
```rust,skt-problem let unknown: Option<&'static str> = None; let known: Option<&'static str> = Some("oops");
asserteq!(unknown.toproblem().tostring(), "
Result<T, E>
can be mapped into Result<T, Problem>
with .map_problem()
function.
```rust,skt-problem let res: Result<(), &'static str> = Err("oops");
asserteq!(res.mapproblem().unwraperr().tostring(), "oops"); ```
Option<T>
can be converted into Result<T, Problem>
with .ok_or_problem(message)
function.
```rust,skt-problem let opt: Option<()> = None;
asserteq!(opt.okorproblem("oops").unwraperr().to_string(), "oops"); ```
Methods .problem_while(message)
and .problem_while_with(|| message)
can be called on any Result
that error type can be implicitly converted to Problem
.
The _with
variant can be used to delay computation of error message to the moment when actual Err
variant has occurred.
```rust,skt-problem let res = String::from_utf8(vec![0, 123, 255]);
asserteq!(res.problemwhile("creating string").unwraperr().tostring(), "while creating string got problem caused by: invalid utf-8 sequence of 1 bytes from index 2"); ```
Functions in_context_of(message, closure)
and in_context_of_with(|| message, closure)
can be used to wrap block of code in closure.
This is useful when you want to add context to any error that can happen in the block of code with ?
operator.
The return type of the closure needs to be Result<T, Problem>
.
The _with
variant can be used to delay computation of error message to the moment when actual Err
variant has occurred.
```rust,skt-problem let res = incontextof("processing string", || { let s = String::fromutf8(vec![0, 123, 255])?; // do some processing of _s Ok(()) });
asserteq!(res.unwraperr().to_string(), "while processing string got problem caused by: invalid utf-8 sequence of 1 bytes from index 2"); ```
Context methods can be used multiple times to add another layer of context.
```rust,skt-problem
fn foo() -> Result
let res = incontextof("doing stuff", || { let s = foo().problemwhile("running foo")?; // do some processing of _s Ok(()) });
asserteq!(res.unwraperr().to_string(), "while doing stuff, while running foo got problem caused by: invalid utf-8 sequence of 1 bytes from index 2"); ```
panic!(msg, problem)
macro can be used directly to abort program execution but error message printed on the screen will be formatted with Debug
implementation.
This library provides function format_panic_to_stderr()
to set up hook that will use eprintln!("{}", message)
to report panics.
Function format_panic_to_error_log()
will set up hook that will log with error!("{}", message)
to report panics.
Similarly to .expect(message)
, method .or_failed_to(message)
can be used to abort the program via panic!()
with Display
formatted message when called on Err
variant of Result
with error type implementing Display
trait.
```rust,shouldpanic,skt-problem formatpanictostderr();
// Prints message: Failed to convert string due to: invalid utf-8 sequence of 1 bytes from index 2 let s = String::fromutf8(vec![0, 123, 255]).orfailedto("convert string"); ```
Similarly to .ok_or(error)
, method .or_failed_to(message)
can be used to abort the program via panic!()
with formatted message on None
variant of Option
type.
```rust,shouldpanic,skt-problem formatpanictostderr(); let nothing: Option<&'static str> = None;
// Prints message: Failed to get something let s = nothing.orfailed_to("get something"); ```
Method .or_failed_to(message)
can be used to abort the program via panic!()
with formatted message on iterators with Result
item when first Err
is encountered otherwise unwrapping the Ok
value.
```rust,shouldpanic,skt-problem formatpanictostderr();
let results = vec![Ok(1u32), Ok(2u32), Err("oops")];
// Prints message: Failed to collect numbers due to: oops
let ok: Vec