A small crate works with thiserror to create errors with contexts, heavily inspired by snafu.
```rust
pub enum Error { #[error("I/O failed at '{1}'")] Io(#[source] std::io::Error, PathBuf), #[error(transparent)] ParseInt(std::num::ParseIntError), }
fn readfile(path: &Path) -> Result
You can use the #[thisctx]
attribute with the following options to customize
the expanded code:
| Option | Type | Inherited | Container | Variant | Field |
| ------------ | --------------- | --------- | --------- | ------- | ----- |
| attr
| TokenStream[]
| ✔ | ✔ | ✔ | ✔ |
| generic
| bool
| ✔ | ✔ | ✔ | ✔ |
| into
| Type[]
| ✔ | ✔ | ✔ | |
| module
| bool \| Ident
| | ✔ | | |
| skip
| Ident
| ✔ | ✔ | ✔ | |
| suffix
| bool \| Ident
| ✔ | ✔ | ✔ | |
| unit
| bool
| ✔ | ✔ | ✔ | |
| visibility
| Visibility
| ✔ | ✔ | ✔ | ✔ |
The #[source]
and #[error]
attributes defined in thiserror
will also be
checked to determine the source error type.
#[thisctx]
supports two syntaxes for passing arguments to an option:
#[thisctx(visibility(pub))]
#[thisctx(visibility = "pub")]
, this is useful in
older versions of rustc
that don't support arbitrary tokens in non-macro
attributes.An option of type T[]
can occur multiple times in the same node, while other
types will lead an error.
You can omit the true
value in boolean options, e.g. #[thisctx(skip)]
is
equal to #[thisctx(skip(true))]
.
Reversed boolean options starts with no_
can also be used as a shortcut to
pass false
, e.g. #[thisctx(no_skip)]
is equal to #[thisctx(skip(false))]
.
An inherited option uses the value of its parent node if no value is provided, for example:
```rust
enum Error {
// This variant will be ignored since skip=true
is inherited.
Io(#[source] std::io::Error),
// This variant will be processed.
#[thisctx(no_skip)]
ParseInt(#[source] std::num::ParseIntError),
}
```
An option of type T[]
will concatenate arguments from its ancestors instead of
overriding them.
```rust
enum Error { #[thisctx(attr(derive(Clone, Copy)))] Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
```rust // The order of attributes (and other options) is guaranteed by the order of // inheritance. // Attributes from the child node.
// Attributes from the parent node.
struct Io;
struct ParseInt; ```
source
If a field has the #[source]
attribute or is named source
, the type of this
field will be assigned to IntoError::Source
and won't appear in the generated
context types.
```rust
struct Error(#[source] std::io::Error, PathBuf); ```
Expanded example:
```rust
struct ErrorContext
impl
fn into_error(self, source: Self::Source) -> Error {
Error(source, self.0.into())
}
} ```
error
If a variant is transparent (which has #[error(transparent)]
), the first field
(which should also be the only field) will be considered as the source field.
thisctx.attr
An option used to add extra attributes to a generated node.
```rust
struct Error { reason: String, } ```
Expanded example:
```rust
struct ErrorContext
thisctx
allows you to add some common attributes without attr(...)
,
including:
cfg
cfg_attr
derive
doc
This means the above example can also be written as:
```rust
struct Error { reason: String, } ```
thisctx.generic
An option to disable generics of a generated node.
```rust
struct Error { reason: String, #[thisctx(no_generic)] path: PathBuf, } ```
Expanded example:
rust
struct ErrorContext<T1 = String> {
reason: T1,
path: PathBuf,
}
The generics provide a convenient way to construct context types, for example:
rust
let _: Error = ErrorContext {
// You can use &str directly because String implements From<&str>,
reason: "anyhow",
// whereas without generics you have to convert the data to PathBuf manually.
path: "/some/path".into(),
}.build();
thisctx.into
An option for converting generated types to a remote error type.
```rust // Probably an error defined in another crate. enum RemoteError { Custom(String), }
// From
struct MyError(String);
let _: MyError = MyErrorContext("anyhow").build(); // It's possible to construct a remote error from the local context type. let _: RemoteError = MyErrorContext("anyhow").build(); ```
thisctx.module
This option allows you put all generated context types into a single module.
```rust
pub enum Error { Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
rust
pub mod context {
pub struct Io;
pub struct ParseInt;
}
You can also set this option to
true
to use the snake case of the container name as the module name, e.g.#[thisctx(module)]
onenum MyError
is equal to#[thisctx(module(my_error))]
.
thisctx.skip
This option is used to skip generating context types for the specified variant.
```rust
enum Error { #[thisctx(skip)] Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
rust
struct ParseInt;
thisctx.suffix
An option to add a suffix to the names of the generated context types.
By default, only struct
s will be added the builtin suffix Context
since the
generated type without a suffix will confict with the error type.
```rust
enum Error { Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
rust
struct IoError;
struct ParseIntError;
The value
true
means to use the default suffixContext
and the valuefalse
will remove the suffix from the generated type.
thisctx.unit
In Rust, the parentheses are required to construct a tuple struct even if it's
empty. thisctx
will convert an empty struct to a unit struct by default. This
allows you use the struct name to create a new context without having to add
parentheses each time and can be disabled by passing #[thisctx(no_unit)]
.
```rust
enum Error { #[thisctx(no_unit)] Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
rust
struct IoError();
struct ParseIntError;
thisctx.visibility
This option is used to change the visibility of the generated types and fields
and can be written in shorthand as #[pub(...)]
.
```rust
pub enum Error { Io(#[source] std::io::Error), ParseInt(#[source] std::num::ParseIntError), } ```
Expanded example:
rust
pub(crate) struct IoError;
pub(crate) struct ParseIntError;
All tests under tests/*
passed with rustc v1.33
, previous versions may not
compile.
Licensed under either of
at your option.