Expand description
§Details about the output of the Snafu
macro
This procedural macro:
- produces the corresponding context selectors
- implements the
Error
trait - implements the
Display
trait - implements the
ErrorCompat
trait
§Detailed example
use snafu::{Backtrace, Snafu};
use std::path::PathBuf;
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not open config at {}: {}", filename.display(), source))]
OpenConfig {
filename: PathBuf,
source: std::io::Error,
},
#[snafu(display("Could not open config: {}", "source"))]
SaveConfig { source: std::io::Error },
#[snafu(display("The user id {} is invalid", user_id))]
UserIdInvalid { user_id: i32, backtrace: Backtrace },
}
§Generated code
Note — The actual generated code may differ in exact names and details. This section is only intended to provide general guidance.
§Context selectors
This will generate three additional types called context selectors:
struct OpenConfig<P> { filename: P }
struct SaveConfig<P>;
struct UserIdInvalid<I> { user_id: I }
Notably:
- One context selector is created for each enum variant.
- The name of the selector is the same as the enum variant’s name.
- The
source
andbacktrace
fields have been removed; the library will automatically handle this for you. - Each remaining field’s type has been replaced with a generic type.
- If there are no fields remaining for the user to specify, the selector will not require curly braces.
If the original variant had a source
field, its context selector
will have an implementation of IntoError
:
impl<P> IntoError<Error> for OpenConfig<P>
where
P: Into<PathBuf>,
Otherwise, the context selector will have the inherent methods build
and fail
and can be used with the ensure
macro:
impl<I> UserIdInvalid<I>
where
I: Into<i32>,
{
fn build(self) -> Error { /* ... */ }
fn fail<T>(self) -> Result<T, Error> { /* ... */ }
}
If the original variant had a backtrace
field, the backtrace
will be automatically constructed when either IntoError
or
build
/fail
are called.
§Error
Error::source
will return the underlying error, if
there is one:
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Error::OpenConfig { source, .. } => Some(source),
Error::SaveConfig { source, .. } => Some(source),
Error::UserIdInvalid { .. } => None,
}
}
}
Error::cause
will return the same as source
. As
Error::description
is soft-deprecated, it will
return a string matching the name of the variant.
§Display
Every field of the enum variant is made available to the format string, even if they are not used:
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter ) -> fmt::Result {
match self {
Error::OpenConfig { filename, source } =>
write!(f, "Could not open config at {}: {}", filename.display(), source),
Error::SaveConfig { source } =>
write!(f, "Could not open config: {}", source),
Error::UserIdInvalid { user_id, backtrace } =>
write!(f, "The user id {} is invalid", user_id),
}
}
}
If no display format is specified, the variant’s name will be used
by default. If the field is an underlying error, that error’s
Display
implementation will also be included.
§ErrorCompat
Every variant that carries a backtrace will return a reference to that backtrace.
impl snafu::ErrorCompat for Error {
fn backtrace(&self) -> Option<&Backtrace> {
match self {
Error::OpenConfig { .. } => None,
Error::SaveConfig { .. } => None,
Error::UserIdInvalid { backtrace, .. } => Some(backtrace),
}
}
}