# What code is generated by 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
```rust
use snafu::{prelude::*, Backtrace};
use std::path::PathBuf;
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not open config at {}", filename.display()))]
OpenConfig {
filename: PathBuf,
source: std::io::Error,
},
#[snafu(display("Could not open config"))]
SaveConfig { source: std::io::Error },
#[snafu(display("The user id {user_id} is invalid"))]
UserIdInvalid { user_id: i32, backtrace: Backtrace },
#[snafu(display("Could not validate config with key {key}: checksum was {checksum}"))]
ConfigValidationFailed {
checksum: u64,
key: String,
source: crypto::Error,
},
}
# mod crypto { #[derive(Debug, snafu::Snafu)] pub struct Error; }
```
### Generated code
<div style="color: #000; background: #ffffd0; padding: 0.6em; margin-bottom: 0.6em;">
**Note** — The actual generated code may differ in exact names and
details. This section is only intended to provide general
guidance. Use a tool like [cargo-expand][] to see the exact generated
code for your situation.
</div>
[cargo-expand]: https://crates.io/crates/cargo-expand
#### Context selectors
Each enum variant will generate an additional type called a *context
selector*:
```rust,ignore
struct OpenConfigSnafu<P> {
filename: P,
}
struct SaveConfigSnafu<P>;
struct UserIdInvalidSnafu<I> {
user_id: I,
}
struct ConfigValidationFailedSnafu<I, S> {
checksum: I,
key: S,
}
```
Notably:
1. The name of the selector is the enum variant's name with the suffix
`Snafu` added. If the name originally ended in `Error`, that is
removed.
1. The `source` and `backtrace` fields have been removed; the
library will automatically handle these for you.
1. Each remaining field's type has been replaced with a generic
type.
1. 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`]:
```rust,ignore
impl<P> IntoError<Error> for OpenConfigSnafu<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:
```rust,ignore
impl<I> UserIdInvalidSnafu<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:
```rust,ignore
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::ConfigValidationFailed { source, .. } => Some(source),
}
}
}
```
[`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:
```rust,ignore
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()),
Error::SaveConfig { source } =>
write!(f, "Could not open config"),
Error::UserIdInvalid { user_id, backtrace } =>
write!(f, "The user id {} is invalid", user_id = user_id),
Error::ConfigValidationFailed { key, checksum, source } =>
write!(f, "Could not validate config with key {}: checksum was {}", key = key, checksum = checksum),
}
}
}
```
If no display format is specified, the variant's name will be used
by default.
#### `ErrorCompat`
Every variant that carries a backtrace will return a reference to
that backtrace.
```rust,ignore
impl snafu::ErrorCompat for Error {
fn backtrace(&self) -> Option<&Backtrace> {
match self {
Error::OpenConfig { .. } => None,
Error::SaveConfig { .. } => None,
Error::UserIdInvalid { backtrace, .. } => Some(backtrace),
Error::ConfigValidationFailed { .. } => None,
}
}
}
```
[`Display`]: std::fmt::Display
[`Error`]: std::error::Error