24 releases
0.6.3 | Nov 9, 2020 |
---|---|
0.6.2 | Oct 16, 2019 |
0.5.1 | Oct 9, 2019 |
#16 in #longer
27 downloads per month
Used in mango-client
21KB
278 lines
strerror
A string-based error type. No longer developed. Recommended replacement: Anyhow and Thiserror crates.
Documentation
See included rustdoc documentation or visit https://docs.rs/strerror.
Note that when building the documentation locally you currently need a nightly compiler to correctly render the RFC1946 intra-rustdoc links.
License
This project is licensed under the MIT license (LICENSE-MIT) or the Apache License, Version 2.0 (LICENSE-APACHE), at your option.
lib.rs
:
A string-based error type. No longer developed. Recommended replacement: Anyhow and Thiserror crates.
Introduction
This crate provides a string-based error type,
StrError
, that implements
std::error::Error
. It is for simple use
cases where you wish to work with string errors and/or box
existing errors of any type, adding context to them.
StrError
s behave in many ways like
String
s, except they may also contain another error
boxed inside them, known as the "source" or "cause". Since the
source can have a source itself, sources form chains of errors,
each error adding context to the preceeding one.
When a StrError
is returned from main
, its
Debug
implementation causes the output of a CLI
application to look like this
Error: ...
Caused by: ...
Caused by: ...
...
Each "Caused by:" line corresponds to a boxed error in the chain of sources.
The prelude
This crate has a prelude to bring in all the things you need at once.
use strerror::prelude::*;
The examples below all assume use of the prelude.
Creating StrError
s
As with String
s, there are quite a few ways to create
a StrError
. Some have an analagous
String
equivalent, so are presented side-by-side with
them.
// String // StrError
let str1 = "Error!".to_string(); let err1 = "Error!".into_error();
let str2 = String::from("Error!"); let err2 = StrError::from("Error!");
let str3: String = "Error!".into(); let err3: StrError = "Error!".into();
let str4 = format!("Error! #{}", 1); let err4 = eformat!("Error! #{}", 1);
The above lines all create StrError
s without a
"source" or "cause". To create a StrError
with a
source you can use chain_error
.
use std::io::Error as IoError;
let source = IoError::from_raw_os_error(5);
let err = source.chain_error("I/O error occurred");
Chaining chain_error
method calls
together creates an error chain.
fn main() -> Result<(), StrError> {
let err = "Base error".into_error()
.chain_error("Higher level error")
.chain_error("Application error");
Err(err)
}
gives output
Error: Application error
Caused by: Higher level error
Caused by: Base error
Returning Result
s
While the chain_error
method adds
context to error types directly, we can do a similar thing with
the Err
variant values in Result
s, with the
chain_err
method.
use std::fs::File;
fn main() -> Result<(), StrError> {
let file = "missing-file";
let _ = File::open(file) // a Result
.chain_err(|| format!("Failed to open {}", file))?; // main exits
Ok(())
}
gives output
Error: Failed to open missing-file
Caused by: No such file or directory (os error 2)
The Result
is converted to the correct type by
chain_err
and context is applied to the
boxed error. Note that in the example above
chair_err
takes a closure, and not a
String
directly. This is so the construction of the
String
is not performed unless needed. You do not need
to use closures however, since chair_err
accepts String
s, and &str
s as well.
Returning a new StrError
in a Result
can
be done in the following way, taking advantage of From
conversion from &str
.
fn main() -> Result<(), StrError> {
return Err("an error".into());
}
An alternative is the into_err
method,
which will call into
and create the Err
variant in one step.
fn main() -> Result<(), StrError> {
return "an error".into_err();
}
Converting Option
s
Sometimes None
represents an application error and it is
desirable to convert an Option<T>
into a
Result<T, StrError>
. There is no special method needed in this
case. You can use ok_or
or
ok_or_else
.
use std::env;
fn main() -> Result<(), StrError> {
let _ = env::var_os("MISSING_VAR") // an Option
.ok_or("MISSING_VAR not found")?; // main exits
Ok(())
}
gives output
Error: MISSING_VAR not found
We take advantage again of From
conversion from
&str
to return a StrError
.
From
conversions to StrError
From
conversions are implemented for most of the
standard library error types, so you can return a
Result
containing one directly from a function
expecting a Result<T, StrError>
, using the ?
operator.
use std::fs::File;
fn main() -> Result<(), StrError> {
let file = "missing-file";
let _ = File::open(file)?; // main exits
Ok(())
}
gives output
Error: std::io::Error
Caused by: No such file or directory (os error 2)
From
conversions are also implemented for &str
and String
, as mentioned previously.
However, for other error types, if you wish to use the ?
operator you will first need to call the
chain_err
method to convert the
Result<T, E>
into a Result<T, StrError>
. Of course
you may choose to use a Box<dyn std::error::Error>
instead of a
StrError
in the the return type of your function, in
which case ?
will work for all error types.
Deref
StrError
s deref to a String
, so you can
use many of the usual String
methods.
fn main() -> Result<(), StrError> {
let mut err = "This is".into_error();
*err += " an error";
err.push_str(" message");
Err(err)
}
gives output
Error: This is an error message
Iterating through the source chain
A reference to a StrError
can be iterated over to
examine its chain of boxed sources.
use std::io::Error as IoError;
fn main() -> Result<(), StrError> {
let err = IoError::from_raw_os_error(5)
.chain_error("Failure reading disk")
.chain_error("Application error");
for e in &err {
println!(
"Error: {:31} Is StrError?: {}",
e,
e.downcast_ref::<StrError>().is_some()
);
}
Ok(())
}
gives output
Error: Application error Is StrError?: true
Error: Failure reading disk Is StrError?: true
Error: Input/output error (os error 5) Is StrError?: false