derive-error-chain 0.10.1

A Macros 1.1 implementation of error-chain
Documentation
A Macros 1.1 implementation of https://crates.io/crates/error-chain The error-chain example ```ignore mod other_error { error_chain! {} } error_chain! { types { Error, ErrorKind, ResultExt, Result; } links { Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)]; } foreign_links { Fmt(::std::fmt::Error); Io(::std::io::Error) #[cfg(unix)]; } errors { InvalidToolchainName(t: String) { description("invalid toolchain name") display("invalid toolchain name: '{}'", t) } } } ``` becomes ```ignore mod other_error { #[derive(Debug, error_chain)] pub enum ErrorKind { Msg(String), } } #[derive(Debug, error_chain)] pub enum ErrorKind { Msg(String), #[cfg(unix)] #[error_chain(link = "other_error::Error")] Another(other_error::ErrorKind), #[error_chain(foreign)] Fmt(::std::fmt::Error), #[cfg(unix)] #[error_chain(foreign)] Io(::std::io::Error), #[error_chain(custom)] #[error_chain(description = r#"|_| "invalid toolchain name""#)] #[error_chain(display = r#"|t| write!(f, "invalid toolchain name: '{}'", t)"#)] InvalidToolchainName(String), } ``` So the obvious differences from `error_chain!` are: - The ErrorKind is an enum instead of a macro invocation. - Error links are variants of the enum instead of lines inside the macro. - Links have explicit annotations marking them as chainable / foreign / custom instead of being grouped into corresponding sections of the macro. - Attributes like `#[cfg]` are applied to the variants directly instead of needing special syntax. - `description` and `display` are defined as function expressions specified as attribute values, instead of shorthands integrated into the macro syntax. The less obvious differences are: - The ErrorKind must explicitly implement `::std::fmt::Debug`, either automatically using `#[derive]` or manually implemented separately. `error_chain!` does this implicitly. - The ErrorKind must have `pub` visibility. `error_chain!` does this implicitly. - The ErrorKind must have a special `Msg(String)` member. `error_chain!` does this implicitly. - Doc comments, since they're effectively attributes, can be applied on the enum variants without any special syntax like `error_chain!` has. - The ErrorKind can be generic. # Enum attributes - `#[error_chain(error = "ErrorName")]` Override the name of the generated `Error` struct to the given name. If not provided, the struct will be named `Error`. - `#[error_chain(result_ext = "ResultExtName")]` Override the name of the generated `ResultExt` trait to the given name. If not provided, the trait will be named `ResultExt`. - `#[error_chain(result = "ResultName")]` Override the name of the generated `Result` type alias to the given name. If not provided, the alias will be named `Result`. If set to the empty string `""`, the alias will not be generated at all. - `#[error_chain(backtrace = "false")]` or `#[error_chain(backtrace = false)]` Disable backtrace functionality in the generated code. This should be kept in sync with the value of the `backtrace` feature of the `error-chain` crate. In other words, if you set `backtrace = "false"` here, you must also specify `default-features = false` for `error-chain` in your `Cargo.toml` # Variant definitions - Chainable links ```ignore #[error_chain(link = "other_error::Error")] Another(other_error::ErrorKind), ``` A chainable link is an error and errorkind that have been generated using `error-chain` or `derive-error-chain`. The variant must have a single field to hold the chained errorkind, and the `link` attribute must specify a path to the chained error. - Foreign links ```ignore #[error_chain(foreign)] Fmt(::std::fmt::Error), ``` A foreign link is an error that implements `::std::error::Error` but otherwise does not follow `error-chain`'s conventions. The variant must have a single field to hold the foreign error. - Custom links ```ignore #[error_chain(custom)] InvalidToolchainName(String), ``` A custom link is an arbitrary variant that can hold any members. # Variant attributes In addition to the above attributes that identify the type of the variant's link, the below attributes can be used on all links. - `#[error_chain(description = "some_function_expression")]` Specifies a function expression to be used to implement `ErrorKind::description()`. This value is also returned from the implementation of `::std::error::Error::description()` on the generated `Error`. This can be an inline lambda: ```ignore #[error_chain(description = r#"|_| "invalid toolchain name""#)] InvalidToolchainName(String), ``` or it can be a separate function: ```ignore #[error_chain(description = "invalid_toolchain_name_error_description")] InvalidToolchainName(String), // fn invalid_toolchain_name_error_description(_: &str) -> &str { "invalid toolchain name" } ``` The function expression must have the signature `(...) -> &'static str`. It should have one parameter for each field of the variant. The fields are passed in by reference. Thus in the above example, since `InvalidToolchainName` had a single field of type `String`, the function expression needed to be of type `(&str) -> &'static str` If not specified, the default implementation behaves in this way: - Chainable links: Forwards to the chained error kind's `description()` - Foreign links: Forwards to the foreign error's implementation of `::std::error::Error::description()` - Custom links: Returns the stringified name of the variant. - `#[error_chain(display = "some_function_expression")]` Specifies a function expression to be used to implement `::std::fmt::Display::fmt()` on the `ErrorKind` and generated `Error` This can be an inline lambda: ```ignore #[error_chain(display = r#"|t| write!(f, "invalid toolchain name: '{}'", t)"#)] InvalidToolchainName(String), ``` or it can be a separate function: ```ignore #[error_chain(display = "invalid_toolchain_name_error_display")] InvalidToolchainName(String), // fn invalid_toolchain_name_error_display(f: &mut ::std::fmt::Formatter, t: &str) -> ::std::fmt::Result { write!(f, "invalid toolchain name: '{}'", t) } ``` The function expression must have the signature `(&mut ::std::fmt::Formatter, ...) -> ::std::fmt::Result`. It should have one `&mut ::std::fmt::Formatter` parameter, and one parameter for each field of the variant. The fields are passed in by reference. For brevity, closure expressions do not need the `&mut ::std::fmt::Formatter` parameter and instead capture `f` from the closure environment. Thus in the above example, since `InvalidToolchainName` had a single field of type `String`, the function expression needed to be of type `(&mut ::std::fmt::Formatter, &str) -> ::std::fmt::Result` If not specified, the default implementation of `::std::fmt::Display::fmt()` behaves in this way: - Chainable links: Forwards to the chained errorkind's implementation of `::std::fmt::Display::fmt()` - Foreign links: Forwards to the foreign error's implementation of `::std::fmt::Display::fmt()` - Custom links: Writes the description of the variant to the formatter. - `#[error_chain(cause = "some_function_expression")]` Specifies a function expression to be used to implement `::std::fmt::Error::cause()` on the generated `Error` This can be an inline lambda: ```ignore #[error_chain(cause = "|_, err| err")] JSON(::std::path::PathBuf, ::serde_json::Error), ``` or it can be a separate function: ```ignore #[error_chain(cause = "parse_json_file_error_cause")] JSON(::std::path::PathBuf, ::serde_json::Error), // fn parse_json_file_error_cause<'a>(_: &::std::path::Path, err: &'a ::serde_json::Error) -> &'a ::std::error::Error { err } ``` The function expression must have the signature `(...) -> &::std::error::Error`. It should have one parameter for each field of the variant. The fields are passed in by reference. The result is wrapped in `Option::Some()` for returning from `::std::error::Error::cause()` Thus in the above example, since `JSON` had two fields of type `::std::path::PathBuf` and `::serde_json::Error`, the function expression needed to be of type `(&::std::path::Path, &::serde_json::Error) -> &::std::error::Error` If not specified, the default implementation of `::std::error::Error::cause()` behaves in this way: - Chainable links: Returns `None` - Foreign links: Forwards to the foreign error's implementation of `::std::error::Error::cause()` - Custom links: Returns `None` # Notes If you want to use other macros from the `error_chain` like `bail!`, note that the following code: ```ignore #[macro_use] extern crate derive_error_chain; #[macro_use] extern crate error_chain; #[derive(Debug, error_chain)] enum ErrorKind { Msg(String), } ``` will fail to compile with: ```ignore error: macro `error_chain` may not be used for derive attributes ``` This is because both crates export a macro named `error_chain` and the macro from the second crate overrides the first. To fix this, import `error_chain` before `derive_error_chain`: ```ignore #[macro_use] extern crate error_chain; #[macro_use] extern crate derive_error_chain; ``` or use a fully-qualified path for the custom derive (nightly only): ```ignore #![feature(proc_macro)] extern crate derive_error_chain; #[macro_use] extern crate error_chain; #[derive(Debug, derive_error_chain::error_chain)] enum ErrorKind { Msg(String), } ```