├── failure_derive ├── .gitignore ├── tests │ ├── no_derive_display.rs │ ├── custom_type_bounds.rs │ ├── tests.rs │ ├── backtrace.rs │ └── wraps.rs ├── Cargo.toml ├── build.rs └── src │ └── lib.rs ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── Makefile ├── book └── src │ ├── howto.md │ ├── SUMMARY.md │ ├── bail-and-ensure.md │ ├── guidance.md │ ├── use-error.md │ ├── intro.md │ ├── error-msg.md │ ├── custom-fail.md │ ├── error.md │ ├── string-custom-error.md │ ├── error-errorkind.md │ ├── derive-fail.md │ └── fail.md ├── examples ├── error_as_cause.rs ├── simple.rs ├── bail_ensure.rs └── string_custom_error_pattern.rs ├── src ├── box_std.rs ├── as_fail.rs ├── error_message.rs ├── error │ ├── error_impl.rs │ ├── error_impl_small.rs │ └── mod.rs ├── compat.rs ├── macros.rs ├── sync_failure.rs ├── backtrace │ ├── internal.rs │ └── mod.rs ├── context.rs ├── result_ext.rs ├── small_error.rs └── lib.rs ├── tests ├── basic_fail.rs ├── fail_compat.rs └── macro_trailing_comma.rs ├── travis.sh ├── Cargo.toml ├── LICENSE-MIT ├── RELEASES.md ├── CODE_OF_CONDUCT.md ├── README.md ├── Cargo.lock.ci └── LICENSE-APACHE /failure_derive/.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | **/*.rs.bk 3 | **/Cargo.lock 4 | public 5 | book/book 6 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: "rust:latest" 2 | 3 | pages: 4 | script: 5 | - sh ./build-docs.sh 6 | artifacts: 7 | paths: 8 | - public 9 | only: 10 | - master 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - 1.31.0 4 | - stable 5 | - beta 6 | - nightly 7 | cache: cargo 8 | script: 9 | - if [ "$TRAVIS_RUST_VERSION" == "1.31.0" ]; then cp Cargo.lock.ci Cargo.lock; fi 10 | - cargo test 11 | - cargo test --features backtrace 12 | - cargo check --no-default-features 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: test 2 | .PHONY: all 3 | 4 | test: 5 | @echo TEST DEFAULT FEATURES 6 | @cargo test --all 7 | @echo TEST WITH BACKTRACE 8 | @cargo test --features backtrace --all 9 | @echo TEST NO DEFAULT FEATURES 10 | @cargo check --no-default-features --all 11 | .PHONY: test 12 | 13 | check: 14 | @cargo check --all 15 | .PHONY: check 16 | -------------------------------------------------------------------------------- /book/src/howto.md: -------------------------------------------------------------------------------- 1 | # How to use failure 2 | 3 | This section of the documentation is about how the APIs exposed in failure can 4 | be used. It is organized around the major APIs of failure: 5 | 6 | - **[The Fail trait](./fail.md):** The primary abstraction provided by failure. 7 | - **[Deriving Fail](./derive-fail.md):** A custom derive for the Fail trait. 8 | - **[The Error type](./error.md):** A convenient wrapper around any Fail type. 9 | -------------------------------------------------------------------------------- /examples/error_as_cause.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::{err_msg, Error, Fail}; 5 | 6 | #[derive(Debug, Fail)] 7 | #[fail(display = "my wrapping error")] 8 | struct WrappingError(#[fail(cause)] Error); 9 | 10 | fn bad_function() -> Result<(), WrappingError> { 11 | Err(WrappingError(err_msg("this went bad"))) 12 | } 13 | 14 | fn main() { 15 | for cause in Fail::iter_causes(&bad_function().unwrap_err()) { 16 | println!("{}", cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/box_std.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use Fail; 4 | 5 | pub struct BoxStd(pub Box); 6 | 7 | impl fmt::Display for BoxStd { 8 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 9 | fmt::Display::fmt(&self.0, f) 10 | } 11 | } 12 | 13 | impl fmt::Debug for BoxStd { 14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 15 | fmt::Debug::fmt(&self.0, f) 16 | } 17 | } 18 | 19 | impl Fail for BoxStd {} 20 | -------------------------------------------------------------------------------- /tests/basic_fail.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Fail; 5 | 6 | #[test] 7 | fn test_name() { 8 | #[derive(Fail, Debug)] 9 | #[fail(display = "my error")] 10 | struct MyError; 11 | 12 | let err = MyError; 13 | 14 | assert_eq!(err.to_string(), "my error"); 15 | assert_eq!(err.name(), Some("basic_fail::MyError")); 16 | 17 | let ctx = err.context("whatever"); 18 | 19 | assert_eq!(ctx.to_string(), "whatever"); 20 | assert_eq!(ctx.name(), Some("basic_fail::MyError")); 21 | } -------------------------------------------------------------------------------- /failure_derive/tests/no_derive_display.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] 3 | extern crate failure_derive; 4 | 5 | use failure::Fail; 6 | use std::fmt::{self, Display}; 7 | 8 | #[derive(Debug, Fail)] 9 | struct Foo; 10 | 11 | impl Display for Foo { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | f.write_str("An error occurred.") 14 | } 15 | } 16 | 17 | #[test] 18 | fn handwritten_display() { 19 | assert!(Foo.cause().is_none()); 20 | assert_eq!(&format!("{}", Foo)[..], "An error occurred."); 21 | } 22 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Fail; 5 | 6 | #[derive(Debug, Fail)] 7 | #[fail(display = "my error")] 8 | struct MyError; 9 | 10 | #[derive(Debug, Fail)] 11 | #[fail(display = "my wrapping error")] 12 | struct WrappingError(#[fail(cause)] MyError); 13 | 14 | fn bad_function() -> Result<(), WrappingError> { 15 | Err(WrappingError(MyError)) 16 | } 17 | 18 | fn main() { 19 | for cause in Fail::iter_chain(&bad_function().unwrap_err()) { 20 | println!("{}: {}", cause.name().unwrap_or("Error"), cause); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [failure](./intro.md) 4 | - [How to use failure](./howto.md) 5 | - [The Fail trait](./fail.md) 6 | - [Deriving Fail](./derive-fail.md) 7 | - [The Error type](./error.md) 8 | - [`bail!` and `ensure!`](./bail-and-ensure.md) 9 | - [Patterns & Guidance](./guidance.md) 10 | - [Strings as errors](./error-msg.md) 11 | - [A Custom Fail type](./custom-fail.md) 12 | - [Using the Error type](./use-error.md) 13 | - [An Error and ErrorKind pair](./error-errorkind.md) 14 | - [Strings and custom fail type](./string-custom-error.md) 15 | -------------------------------------------------------------------------------- /examples/bail_ensure.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Error; 5 | 6 | fn bailer() -> Result<(), Error> { 7 | // bail!("ruh roh"); 8 | bail!("ruh {}", "roh"); 9 | } 10 | 11 | fn ensures() -> Result<(), Error> { 12 | ensure!(true, "true is false"); 13 | ensure!(false, "false is false"); 14 | Ok(()) 15 | } 16 | 17 | fn main() { 18 | match bailer() { 19 | Ok(_) => println!("ok"), 20 | Err(e) => println!("{}", e), 21 | } 22 | match ensures() { 23 | Ok(_) => println!("ok"), 24 | Err(e) => println!("{}", e), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /failure_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "derives for the failure crate" 4 | license = "MIT OR Apache-2.0" 5 | name = "failure_derive" 6 | repository = "https://github.com/rust-lang-nursery/failure" 7 | homepage = "https://rust-lang-nursery.github.io/failure/" 8 | documentation = "https://docs.rs/failure" 9 | version = "0.1.8" 10 | build = "build.rs" 11 | 12 | [dependencies] 13 | quote = "1" 14 | syn = "1.0.3" 15 | synstructure = "0.12.0" 16 | proc-macro2 = "1" 17 | 18 | [dev-dependencies.failure] 19 | version = "0.1.0" 20 | path = ".." 21 | 22 | [badges] 23 | maintenance = { status = "deprecated" } 24 | 25 | [lib] 26 | proc-macro = true 27 | 28 | [features] 29 | # This is kept for backward-compatibility reasons, but is otherwise a no-op 30 | std = [] 31 | -------------------------------------------------------------------------------- /travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | 5 | cargo_test() { 6 | cargo test "$@" || { exit 101; } 7 | } 8 | 9 | test_failure_in() { 10 | cd $1 11 | cargo_test 12 | cargo_test --no-default-features 13 | cargo_test --features backtrace 14 | test_derive_in "$1/failure_derive" 15 | cd $DIR 16 | } 17 | 18 | test_derive_in() { 19 | cd $1 20 | cargo_test 21 | cd $DIR 22 | } 23 | 24 | test_nightly_features_in() { 25 | cd $1 26 | #cargo_test --features small-error 27 | cargo_test --all-features 28 | cd $DIR 29 | } 30 | 31 | main() { 32 | test_failure_in "$DIR/failure-1.X" 33 | test_failure_in "$DIR/failure-0.1.X" 34 | if [ "${TRAVIS_RUST_VERSION}" = "nightly" ]; then 35 | test_nightly_features_in "$DIR/failure-1.X" 36 | fi 37 | } 38 | 39 | main 40 | -------------------------------------------------------------------------------- /tests/fail_compat.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use failure::Fail; 5 | 6 | fn return_failure() -> Result<(), failure::Error> { 7 | #[derive(Fail, Debug)] 8 | #[fail(display = "my error")] 9 | struct MyError; 10 | 11 | let err = MyError; 12 | Err(err.into()) 13 | } 14 | 15 | fn return_error() -> Result<(), Box> { 16 | return_failure()?; 17 | Ok(()) 18 | } 19 | 20 | fn return_error_send_sync() -> Result<(), Box> { 21 | return_failure()?; 22 | Ok(()) 23 | } 24 | 25 | #[test] 26 | fn smoke_default_compat() { 27 | let err = return_error(); 28 | assert!(err.is_err()); 29 | } 30 | 31 | #[test] 32 | fn smoke_compat_send_sync() { 33 | let err = return_error_send_sync(); 34 | assert!(err.is_err()); 35 | } 36 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Without Boats "] 3 | description = "Experimental error handling abstraction." 4 | documentation = "https://docs.rs/failure" 5 | homepage = "https://rust-lang-nursery.github.io/failure/" 6 | license = "MIT OR Apache-2.0" 7 | name = "failure" 8 | repository = "https://github.com/rust-lang-nursery/failure" 9 | 10 | version = "0.1.8" 11 | [dependencies.failure_derive] 12 | optional = true 13 | version = "0.1.7" 14 | path = "./failure_derive" 15 | 16 | [dependencies.backtrace] 17 | optional = true 18 | version = "0.3.3" 19 | 20 | [workspace] 21 | members = [".", "failure_derive"] 22 | 23 | [badges] 24 | maintenance = { status = "deprecated" } 25 | 26 | [features] 27 | default = ["std", "derive"] 28 | #small-error = ["std"] 29 | std = ["backtrace"] 30 | derive = ["failure_derive"] 31 | -------------------------------------------------------------------------------- /book/src/bail-and-ensure.md: -------------------------------------------------------------------------------- 1 | # `bail!` and `ensure!` 2 | 3 | If you were a fan of the `bail!` and ensure! macros from error-chain, good news. failure has a version of these macros as well. 4 | 5 | The `bail!` macro returns an error immediately, based on a format string. The `ensure!` macro additionally takes a conditional, and returns the error only if that conditional is false. You can think of `bail!` and `ensure!` as being analogous to `panic!` and `assert!`, but throwing errors instead of panicking. 6 | 7 | `bail!` and `ensure!` macros are useful when you are prototyping and you want to write your custom errors later. It is also the simplest example of using the failure crate. 8 | 9 | ## Example 10 | ```rust 11 | #[macro_use] extern crate failure; 12 | 13 | fn safe_cast_to_unsigned(n:i32) -> Result 14 | { 15 | ensure!(n>=0, "number cannot be smaller than 0!"); 16 | (u32) n 17 | } 18 | ``` -------------------------------------------------------------------------------- /src/as_fail.rs: -------------------------------------------------------------------------------- 1 | use Fail; 2 | 3 | /// The `AsFail` trait 4 | /// 5 | /// This trait is similar to `AsRef`, but it is specialized to handle 6 | /// the dynamic object of `Fail`. Implementors of `Fail` have a blanket 7 | /// implementation. It is used in `failure_derive` in order to generate a 8 | /// custom cause. 9 | pub trait AsFail { 10 | /// Converts a reference to `Self` into a dynamic trait object of `Fail`. 11 | fn as_fail(&self) -> &dyn Fail; 12 | } 13 | 14 | impl AsFail for T 15 | where 16 | T: Fail, 17 | { 18 | fn as_fail(&self) -> &dyn Fail { 19 | self 20 | } 21 | } 22 | 23 | impl AsFail for dyn Fail { 24 | fn as_fail(&self) -> &dyn Fail { 25 | self 26 | } 27 | } 28 | 29 | with_std! { 30 | use error::Error; 31 | 32 | impl AsFail for Error { 33 | fn as_fail(&self) -> &dyn Fail { 34 | self.as_fail() 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /failure_derive/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::process::Command; 3 | use std::str; 4 | use std::str::FromStr; 5 | 6 | fn main() { 7 | if rustc_has_dyn_trait() { 8 | println!("cargo:rustc-cfg=has_dyn_trait"); 9 | } 10 | } 11 | 12 | fn rustc_has_dyn_trait() -> bool { 13 | let rustc = match env::var_os("RUSTC") { 14 | Some(rustc) => rustc, 15 | None => return false, 16 | }; 17 | 18 | let output = match Command::new(rustc).arg("--version").output() { 19 | Ok(output) => output, 20 | Err(_) => return false, 21 | }; 22 | 23 | let version = match str::from_utf8(&output.stdout) { 24 | Ok(version) => version, 25 | Err(_) => return false, 26 | }; 27 | 28 | let mut pieces = version.split('.'); 29 | if pieces.next() != Some("rustc 1") { 30 | return true; 31 | } 32 | 33 | let next = match pieces.next() { 34 | Some(next) => next, 35 | None => return false, 36 | }; 37 | 38 | u32::from_str(next).unwrap_or(0) >= 27 39 | } 40 | -------------------------------------------------------------------------------- /src/error_message.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | 3 | use Fail; 4 | use Error; 5 | 6 | /// Constructs a `Fail` type from a string. 7 | /// 8 | /// This is a convenient way to turn a string into an error value that 9 | /// can be passed around, if you do not want to create a new `Fail` type for 10 | /// this use case. 11 | pub fn err_msg(msg: D) -> Error { 12 | Error::from(ErrorMessage { msg }) 13 | } 14 | 15 | /// A `Fail` type that just contains an error message. You can construct 16 | /// this from the `err_msg` function. 17 | #[derive(Debug)] 18 | struct ErrorMessage { 19 | msg: D, 20 | } 21 | 22 | impl Fail for ErrorMessage { 23 | fn name(&self) -> Option<&str> { 24 | Some("failure::ErrorMessage") 25 | } 26 | } 27 | 28 | impl Display for ErrorMessage { 29 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 30 | Display::fmt(&self.msg, f) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /book/src/guidance.md: -------------------------------------------------------------------------------- 1 | # Patterns & Guidance 2 | 3 | failure is not a "one size fits all" approach to error management. There are 4 | multiple patterns that emerge from the API this library provides, and users 5 | need to determine which pattern makes sense for them. This section documents 6 | some patterns and how users might use them. 7 | 8 | In brief, these are the patterns documented here: 9 | 10 | - **[Strings as errors](./error-msg.md):** Using strings as your error 11 | type. Good for prototyping. 12 | - **[A Custom Fail type](./custom-fail.md):** Defining a custom type to be 13 | your error type. Good for APIs where you control all or more of the 14 | possible failures. 15 | - **[Using the Error type](./use-error.md):** Using the Error type to pull 16 | together multiple failures of different types. Good for applications and 17 | APIs that know the error won't be inspected much more. 18 | - **[An Error and ErrorKind pair](./error-errorkind.md):** Using both a 19 | custom error type and an ErrorKind enum to create a very robust error 20 | type. Good for public APIs in large crates. 21 | 22 | (Though each of these items identifies a use case which this pattern would be 23 | good for, in truth each of them can be applied in various contexts. Its up to 24 | you to decide what makes the most sense for your particular use case.) 25 | -------------------------------------------------------------------------------- /failure_derive/tests/custom_type_bounds.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | use std::fmt::Debug; 5 | 6 | use failure::Fail; 7 | 8 | #[derive(Debug, Fail)] 9 | #[fail(display = "An error has occurred.")] 10 | pub struct UnboundedGenericTupleError(T); 11 | 12 | #[test] 13 | fn unbounded_generic_tuple_error() { 14 | let s = format!("{}", UnboundedGenericTupleError(())); 15 | assert_eq!(&s[..], "An error has occurred."); 16 | } 17 | 18 | #[derive(Debug, Fail)] 19 | #[fail(display = "An error has occurred: {}", _0)] 20 | pub struct FailBoundsGenericTupleError(T); 21 | 22 | #[test] 23 | fn fail_bounds_generic_tuple_error() { 24 | let error = FailBoundsGenericTupleError(UnboundedGenericTupleError(())); 25 | let s = format!("{}", error); 26 | assert_eq!(&s[..], "An error has occurred: An error has occurred."); 27 | } 28 | 29 | pub trait NoDisplay: 'static + Debug + Send + Sync {} 30 | 31 | impl NoDisplay for &'static str {} 32 | 33 | #[derive(Debug, Fail)] 34 | #[fail(display = "An error has occurred: {:?}", _0)] 35 | pub struct CustomBoundsGenericTupleError(T); 36 | 37 | #[test] 38 | fn custom_bounds_generic_tuple_error() { 39 | let error = CustomBoundsGenericTupleError("more details unavailable."); 40 | let s = format!("{}", error); 41 | assert_eq!( 42 | &s[..], 43 | "An error has occurred: \"more details unavailable.\"" 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/error/error_impl.rs: -------------------------------------------------------------------------------- 1 | use core::any::TypeId; 2 | 3 | use Fail; 4 | use backtrace::Backtrace; 5 | 6 | pub(crate) struct ErrorImpl { 7 | inner: Box>, 8 | } 9 | 10 | struct Inner { 11 | backtrace: Backtrace, 12 | pub(crate) failure: F, 13 | } 14 | 15 | impl From for ErrorImpl { 16 | fn from(failure: F) -> ErrorImpl { 17 | let inner: Inner = { 18 | let backtrace = if failure.backtrace().is_none() { 19 | Backtrace::new() 20 | } else { Backtrace::none() }; 21 | Inner { failure, backtrace } 22 | }; 23 | ErrorImpl { inner: Box::new(inner) } 24 | } 25 | } 26 | 27 | impl ErrorImpl { 28 | pub(crate) fn failure(&self) -> &dyn Fail { 29 | &self.inner.failure 30 | } 31 | 32 | pub(crate) fn failure_mut(&mut self) -> &mut dyn Fail { 33 | &mut self.inner.failure 34 | } 35 | 36 | pub(crate) fn backtrace(&self) -> &Backtrace { 37 | &self.inner.backtrace 38 | } 39 | 40 | pub(crate) fn downcast(self) -> Result { 41 | if self.failure().__private_get_type_id__() == TypeId::of::() { 42 | let ErrorImpl { inner } = self; 43 | let casted = unsafe { Box::from_raw(Box::into_raw(inner) as *mut Inner) }; 44 | let Inner { backtrace:_, failure } = *casted; 45 | Ok(failure) 46 | } else { 47 | Err(self) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /failure_derive/tests/tests.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] 3 | extern crate failure_derive; 4 | 5 | #[derive(Fail, Debug)] 6 | #[fail(display = "An error has occurred.")] 7 | struct UnitError; 8 | 9 | #[test] 10 | fn unit_struct() { 11 | let s = format!("{}", UnitError); 12 | assert_eq!(&s[..], "An error has occurred."); 13 | } 14 | 15 | #[derive(Fail, Debug)] 16 | #[fail(display = "Error code: {}", code)] 17 | struct RecordError { 18 | code: u32, 19 | } 20 | 21 | #[test] 22 | fn record_struct() { 23 | let s = format!("{}", RecordError { code: 0 }); 24 | assert_eq!(&s[..], "Error code: 0"); 25 | } 26 | 27 | #[derive(Fail, Debug)] 28 | #[fail(display = "Error code: {}", _0)] 29 | struct TupleError(i32); 30 | 31 | #[test] 32 | fn tuple_struct() { 33 | let s = format!("{}", TupleError(2)); 34 | assert_eq!(&s[..], "Error code: 2"); 35 | } 36 | 37 | #[derive(Fail, Debug)] 38 | enum EnumError { 39 | #[fail(display = "Error code: {}", code)] 40 | StructVariant { code: i32 }, 41 | #[fail(display = "Error: {}", _0)] 42 | TupleVariant(&'static str), 43 | #[fail(display = "An error has occurred.")] 44 | UnitVariant, 45 | } 46 | 47 | #[test] 48 | fn enum_error() { 49 | let s = format!("{}", EnumError::StructVariant { code: 2 }); 50 | assert_eq!(&s[..], "Error code: 2"); 51 | let s = format!("{}", EnumError::TupleVariant("foobar")); 52 | assert_eq!(&s[..], "Error: foobar"); 53 | let s = format!("{}", EnumError::UnitVariant); 54 | assert_eq!(&s[..], "An error has occurred."); 55 | } 56 | -------------------------------------------------------------------------------- /src/compat.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display}; 2 | 3 | /// A compatibility wrapper around an error type from this crate. 4 | /// 5 | /// `Compat` implements `std::error::Error`, allowing the types from this 6 | /// crate to be passed to interfaces that expect a type of that trait. 7 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] 8 | pub struct Compat { 9 | pub(crate) error: E, 10 | } 11 | 12 | impl Display for Compat { 13 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14 | Display::fmt(&self.error, f) 15 | } 16 | } 17 | 18 | impl Compat { 19 | /// Unwraps this into the inner error. 20 | pub fn into_inner(self) -> E { 21 | self.error 22 | } 23 | 24 | /// Gets a reference to the inner error. 25 | pub fn get_ref(&self) -> &E { 26 | &self.error 27 | } 28 | } 29 | 30 | with_std! { 31 | use std::fmt::Debug; 32 | use std::error::Error as StdError; 33 | 34 | use Error; 35 | 36 | impl StdError for Compat { 37 | fn description(&self) -> &'static str { 38 | "An error has occurred." 39 | } 40 | } 41 | 42 | impl From for Box { 43 | fn from(error: Error) -> Box { 44 | Box::new(Compat { error }) 45 | } 46 | } 47 | 48 | impl From for Box { 49 | fn from(error: Error) -> Box { 50 | Box::new(Compat { error }) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Exits a function early with an `Error`. 2 | /// 3 | /// The `bail!` macro provides an easy way to exit a function. `bail!(X)` is 4 | /// equivalent to writing: 5 | /// 6 | /// ```rust,ignore 7 | /// return Err(format_err!(X)) 8 | /// ``` 9 | #[macro_export] 10 | macro_rules! bail { 11 | ($e:expr) => { 12 | return Err($crate::err_msg($e)); 13 | }; 14 | ($fmt:expr, $($arg:tt)*) => { 15 | return Err($crate::err_msg(format!($fmt, $($arg)*))); 16 | }; 17 | } 18 | 19 | /// Exits a function early with an `Error` if the condition is not satisfied. 20 | /// 21 | /// Similar to `assert!`, `ensure!` takes a condition and exits the function 22 | /// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`, 23 | /// it does not panic. 24 | #[macro_export(local_inner_macros)] 25 | macro_rules! ensure { 26 | ($cond:expr) => { 27 | if !($cond) { 28 | bail!("{}", _failure__stringify!($cond)); 29 | } 30 | }; 31 | ($cond:expr, $e:expr) => { 32 | if !($cond) { 33 | bail!($e); 34 | } 35 | }; 36 | ($cond:expr, $fmt:expr, $($arg:tt)*) => { 37 | if !($cond) { 38 | bail!($fmt, $($arg)*); 39 | } 40 | }; 41 | } 42 | 43 | #[doc(hidden)] 44 | #[macro_export] 45 | macro_rules! _failure__stringify { 46 | ($($inner:tt)*) => { 47 | stringify! { $($inner)* } 48 | } 49 | } 50 | 51 | /// Constructs an `Error` using the standard string interpolation syntax. 52 | /// 53 | /// ```rust 54 | /// #[macro_use] extern crate failure; 55 | /// 56 | /// fn main() { 57 | /// let code = 101; 58 | /// let err = format_err!("Error code: {}", code); 59 | /// } 60 | /// ``` 61 | #[macro_export] 62 | macro_rules! format_err { 63 | ($($arg:tt)*) => { $crate::err_msg(format!($($arg)*)) } 64 | } 65 | -------------------------------------------------------------------------------- /failure_derive/tests/backtrace.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] 3 | extern crate failure_derive; 4 | 5 | use failure::{Backtrace, Fail}; 6 | 7 | #[derive(Fail, Debug)] 8 | #[fail(display = "Error code: {}", code)] 9 | struct BacktraceError { 10 | backtrace: Backtrace, 11 | code: u32, 12 | } 13 | 14 | #[test] 15 | fn backtrace_error() { 16 | let err = BacktraceError { 17 | backtrace: Backtrace::new(), 18 | code: 7, 19 | }; 20 | let s = format!("{}", err); 21 | assert_eq!(&s[..], "Error code: 7"); 22 | assert!(err.backtrace().is_some()); 23 | } 24 | 25 | #[derive(Fail, Debug)] 26 | #[fail(display = "An error has occurred.")] 27 | struct BacktraceTupleError(Backtrace); 28 | 29 | #[test] 30 | fn backtrace_tuple_error() { 31 | let err = BacktraceTupleError(Backtrace::new()); 32 | let s = format!("{}", err); 33 | assert_eq!(&s[..], "An error has occurred."); 34 | assert!(err.backtrace().is_some()); 35 | } 36 | 37 | #[derive(Fail, Debug)] 38 | enum BacktraceEnumError { 39 | #[fail(display = "Error code: {}", code)] 40 | StructVariant { code: i32, backtrace: Backtrace }, 41 | #[fail(display = "Error: {}", _0)] 42 | TupleVariant(&'static str, Backtrace), 43 | #[fail(display = "An error has occurred.")] 44 | UnitVariant, 45 | } 46 | 47 | #[test] 48 | fn backtrace_enum_error() { 49 | let err = BacktraceEnumError::StructVariant { 50 | code: 2, 51 | backtrace: Backtrace::new(), 52 | }; 53 | let s = format!("{}", err); 54 | assert_eq!(&s[..], "Error code: 2"); 55 | assert!(err.backtrace().is_some()); 56 | let err = BacktraceEnumError::TupleVariant("foobar", Backtrace::new()); 57 | let s = format!("{}", err); 58 | assert_eq!(&s[..], "Error: foobar"); 59 | assert!(err.backtrace().is_some()); 60 | let err = BacktraceEnumError::UnitVariant; 61 | let s = format!("{}", err); 62 | assert_eq!(&s[..], "An error has occurred."); 63 | assert!(err.backtrace().is_none()); 64 | } 65 | -------------------------------------------------------------------------------- /tests/macro_trailing_comma.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate failure; 3 | 4 | // NOTE: 5 | // 6 | // This test is in a separate file due to the fact that ensure! cannot be used 7 | // from within failure. 8 | // 9 | // (you get: 'macro-expanded `macro_export` macros from the current crate cannot 10 | // be referred to by absolute paths') 11 | 12 | // Encloses an early-returning macro in an IIFE so that we 13 | // can treat it as a Result-returning function. 14 | macro_rules! wrap_early_return { 15 | ($expr:expr) => {{ 16 | fn func() -> Result<(), failure::Error> { 17 | let _ = $expr; 18 | 19 | #[allow(unreachable_code)] 20 | Ok(()) 21 | } 22 | func().map_err(|e| e.to_string()) 23 | }}; 24 | } 25 | 26 | #[test] 27 | fn bail() { 28 | assert_eq!( 29 | wrap_early_return!(bail!("test")), 30 | wrap_early_return!(bail!("test",))); 31 | assert_eq!( 32 | wrap_early_return!(bail!("test {}", 4)), 33 | wrap_early_return!(bail!("test {}", 4,))); 34 | } 35 | 36 | #[test] 37 | fn ensure() { 38 | assert_eq!( 39 | wrap_early_return!(ensure!(false, "test")), 40 | wrap_early_return!(ensure!(false, "test",))); 41 | assert_eq!( 42 | wrap_early_return!(ensure!(false, "test {}", 4)), 43 | wrap_early_return!(ensure!(false, "test {}", 4,))); 44 | } 45 | 46 | #[test] 47 | fn single_arg_ensure() { 48 | assert_eq!( 49 | wrap_early_return!(ensure!(false)), 50 | Err("false".to_string())); 51 | assert_eq!( 52 | wrap_early_return!(ensure!(true == false)), 53 | Err("true == false".to_string())); 54 | assert_eq!( 55 | wrap_early_return!(ensure!(4 == 5)), 56 | Err("4 == 5".to_string())); 57 | } 58 | 59 | #[test] 60 | fn format_err() { 61 | assert_eq!( 62 | format_err!("test").to_string(), 63 | format_err!("test",).to_string()); 64 | assert_eq!( 65 | format_err!("test {}", 4).to_string(), 66 | format_err!("test {}", 4,).to_string()); 67 | } 68 | -------------------------------------------------------------------------------- /examples/string_custom_error_pattern.rs: -------------------------------------------------------------------------------- 1 | //! This example show the pattern "Strings and custom fail type" described in the book 2 | extern crate core; 3 | extern crate failure; 4 | 5 | use core::fmt::{self, Display}; 6 | use failure::{Backtrace, Context, Fail, ResultExt}; 7 | 8 | fn main() { 9 | let err = err1().unwrap_err(); 10 | // Print the error itself 11 | println!("error: {}", err); 12 | // Print the chain of errors that caused it 13 | for cause in Fail::iter_causes(&err) { 14 | println!("caused by: {}", cause); 15 | } 16 | } 17 | 18 | fn err1() -> Result<(), MyError> { 19 | // The context can be a String 20 | Ok(err2().context("err1".to_string())?) 21 | } 22 | 23 | fn err2() -> Result<(), MyError> { 24 | // The context can be a &'static str 25 | Ok(err3().context("err2")?) 26 | } 27 | 28 | fn err3() -> Result<(), MyError> { 29 | Ok(Err(MyError::from("err3"))?) 30 | } 31 | 32 | #[derive(Debug)] 33 | pub struct MyError { 34 | inner: Context, 35 | } 36 | 37 | impl Fail for MyError { 38 | fn cause(&self) -> Option<&Fail> { 39 | self.inner.cause() 40 | } 41 | 42 | fn backtrace(&self) -> Option<&Backtrace> { 43 | self.inner.backtrace() 44 | } 45 | } 46 | 47 | impl Display for MyError { 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | Display::fmt(&self.inner, f) 50 | } 51 | } 52 | 53 | // Allows writing `MyError::from("oops"))?` 54 | impl From<&'static str> for MyError { 55 | fn from(msg: &'static str) -> MyError { 56 | MyError { 57 | inner: Context::new(msg.into()), 58 | } 59 | } 60 | } 61 | 62 | // Allows adding more context via a String 63 | impl From> for MyError { 64 | fn from(inner: Context) -> MyError { 65 | MyError { inner } 66 | } 67 | } 68 | 69 | // Allows adding more context via a &str 70 | impl From> for MyError { 71 | fn from(inner: Context<&'static str>) -> MyError { 72 | MyError { 73 | inner: inner.map(|s| s.to_string()), 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /book/src/use-error.md: -------------------------------------------------------------------------------- 1 | # Use the `Error` type 2 | 3 | This pattern is a way to manage errors when you have multiple kinds of failure 4 | that could occur during a single function. It has several distinct advantages: 5 | 6 | 1. You can start using it without defining any of your own failure types. 7 | 2. All types that implement `Fail` can be thrown into the `Error` type using 8 | the `?` operator. 9 | 3. As you start adding new dependencies with their own failure types, you can 10 | start throwing them without making a breaking change. 11 | 12 | To use this pattern, all you need to do is return `Result<_, Error>` from your 13 | functions: 14 | 15 | ```rust 16 | use std::io; 17 | use std::io::BufRead; 18 | 19 | use failure::Error; 20 | use failure::err_msg; 21 | 22 | fn my_function() -> Result<(), Error> { 23 | let stdin = io::stdin(); 24 | 25 | for line in stdin.lock().lines() { 26 | let line = line?; 27 | 28 | if line.chars().all(|c| c.is_whitespace()) { 29 | break 30 | } 31 | 32 | if !line.starts_with("$") { 33 | return Err(format_err!("Input did not begin with `$`")); 34 | } 35 | 36 | println!("{}", &line[1..]); 37 | } 38 | 39 | Ok(()) 40 | } 41 | ``` 42 | 43 | ## When might you use this pattern? 44 | 45 | This pattern is very effective when you know you will usually not need to 46 | destructure the error this function returns. For example: 47 | 48 | - When prototyping. 49 | - When you know you are going to log this error, or display it to the user, 50 | either all of the time or nearly all of the time. 51 | - When it would be impractical for this API to report more custom context for 52 | the error (e.g. because it is a trait that doesn't want to add a new Error 53 | associated type). 54 | 55 | ## Caveats on this pattern 56 | 57 | There are two primary downsides to this pattern: 58 | 59 | - The `Error` type allocates. There are cases where this would be too 60 | expensive. In those cases you should use a [custom failure][custom-fail]. 61 | - You cannot recover more information about this error without downcasting. If 62 | your API needs to express more contextual information about the error, use 63 | the [Error and ErrorKind][error-errorkind] pattern. 64 | 65 | [custom-fail]: ./custom-fail.html 66 | [error-errorkind]: ./error-errorkind.html 67 | -------------------------------------------------------------------------------- /book/src/intro.md: -------------------------------------------------------------------------------- 1 | # failure 2 | 3 | This is the documentation for the failure crate, which provides a system for 4 | creating and managing errors in Rust. Additional documentation is found here: 5 | 6 | * [API documentation][api] 7 | * [failure source code][repo] 8 | 9 | [api]: https://docs.rs/failure 10 | [repo]: https://github.com/rust-lang-nursery/failure 11 | 12 | ```rust 13 | extern crate serde; 14 | extern crate toml; 15 | 16 | #[macro_use] extern crate failure; 17 | #[macro_use] extern crate serde_derive; 18 | 19 | use std::collections::HashMap; 20 | use std::path::PathBuf; 21 | use std::str::FromStr; 22 | 23 | use failure::Error; 24 | 25 | // This is a new error type that you've created. It represents the ways a 26 | // toolchain could be invalid. 27 | // 28 | // The custom derive for Fail derives an impl of both Fail and Display. 29 | // We don't do any other magic like creating new types. 30 | #[derive(Debug, Fail)] 31 | enum ToolchainError { 32 | #[fail(display = "invalid toolchain name: {}", name)] 33 | InvalidToolchainName { 34 | name: String, 35 | }, 36 | #[fail(display = "unknown toolchain version: {}", version)] 37 | UnknownToolchainVersion { 38 | version: String, 39 | } 40 | } 41 | 42 | pub struct ToolchainId { 43 | // ... etc 44 | } 45 | 46 | impl FromStr for ToolchainId { 47 | type Err = ToolchainError; 48 | 49 | fn from_str(s: &str) -> Result { 50 | // ... etc 51 | } 52 | } 53 | 54 | pub type Toolchains = HashMap; 55 | 56 | // This opens a toml file containing associations between ToolchainIds and 57 | // Paths (the roots of those toolchains). 58 | // 59 | // This could encounter an io Error, a toml parsing error, or a ToolchainError, 60 | // all of them will be thrown into the special Error type 61 | pub fn read_toolchains(path: PathBuf) -> Result 62 | { 63 | use std::fs::File; 64 | use std::io::Read; 65 | 66 | let mut string = String::new(); 67 | File::open(path)?.read_to_string(&mut string)?; 68 | 69 | let toml: HashMap = toml::from_str(&string)?; 70 | 71 | let toolchains = toml.iter().map(|(key, path)| { 72 | let toolchain_id = key.parse()?; 73 | Ok((toolchain_id, path)) 74 | }).collect::>()?; 75 | 76 | Ok(toolchains) 77 | } 78 | -------------------------------------------------------------------------------- /RELEASES.md: -------------------------------------------------------------------------------- 1 | # Version 0.1.6 2 | 3 | - Update `syn`, `quote`, and `proc_macro2` dependencies to 1.0. 4 | - Bump MSRV to 1.31.0. 5 | 6 | # Version 0.1.5 7 | 8 | - Resolve a regression with error conversions (#290) 9 | - Added `name()` to `Fail` and `Error` 10 | 11 | # Version 0.1.4 12 | 13 | - Improved error reporting of the derive feature 14 | - Resolved a potential internal ambiguity when using the backtrace feature 15 | that prevented backtrace from improving an upstream API. 16 | - Changed the bounds on std error compat conversions through the From trait 17 | to take Sync and Send into account. 18 | 19 | # Version 0.1.3 20 | 21 | - Added `Context::map` 22 | - Fixed a memory leak for older rust versions on error downcast 23 | 24 | # Version 0.1.2 25 | 26 | The original plan to release 1.0.0 was changed so that version 0.1.1 is released and a related [RFC to fix the error trait](https://github.com/rust-lang/rfcs/pull/2504) is submitted. See README for details. 27 | 28 | - Fix `failure_derive` to work with Rust 2018. 29 | - Add `#[fail(cause)]` that works similarly with `#[cause]`. The new form is preferred. 30 | - Fix `"backtrace"` feature to work without `"std"` feature. 31 | - Add `Compat::get_ref`. 32 | - Add `Fallible`. 33 | - Deprecate `Fail::causes` and `::causes` in favor of newly added `::iter_causes`. 34 | - Deprecate `Fail::root_cause` and `::root_cause` in favor of newly added `::find_root_cause`. 35 | - Add `::iter_chain`. 36 | - Implement `Box: Fail`. 37 | - Add `Error::from_boxed_compat`. 38 | - Deprecate `Error::cause` in favor of newly added `Error::as_fail`. 39 | - Deprecate `Error::causes` in favor of newly added `Error::iter_chain`. 40 | - Deprecate `Error::root_cause` in favor of newly added `Error::find_root_cause`. 41 | - Add `Error::iter_causes`. 42 | - Implement `Error: AsRef`. 43 | - Fix `Debug` implementation of `SyncFailure`. 44 | 45 | # Version 0.1.1 46 | 47 | - Add a `Causes` iterator, which iterates over the causes of a failure. Can be 48 | accessed through the `Fail::causes` or `Error::causes` methods. 49 | - Add the `bail!` macro, which "throws" from the function. 50 | - Add the `ensure!` macro, which is like an "assert" which throws instead of 51 | panicking. 52 | - The derive now supports a no_std mode. 53 | - The derive is re-exported from `failure` by default, so that users do not 54 | have to directly depend on `failure_derive`. 55 | - Add a impl of `From for Context`, allowing users to `?` the `D` type to 56 | produce a `Context` (for cases where there is no further underlying 57 | error). 58 | 59 | # Version 0.1.0 60 | 61 | - Initial version. 62 | -------------------------------------------------------------------------------- /book/src/error-msg.md: -------------------------------------------------------------------------------- 1 | # Strings as errors 2 | 3 | This pattern is a way to create new errors without doing much set up. It is 4 | definitely the sloppiest way to throw errors. It can be great to use this 5 | during prototyping, but maybe not in the final product. 6 | 7 | String types do not implement `Fail`, which is why there are two adapters to 8 | create failures from a string: 9 | 10 | - [`failure::err_msg`][err-msg-api] - a function that takes a displayable 11 | type and creates a failure from it. This can take a String or a string 12 | literal. 13 | - [`format_err!`][format-err-api] - a macro with string interpolation, similar 14 | to `format!` or `println!`. 15 | 16 | ```rust 17 | fn check_range(x: usize, range: Range) -> Result { 18 | if x < range.start { 19 | return Err(format_err!("{} is below {}", x, range.start)); 20 | } 21 | if x >= range.end { 22 | return Err(format_err!("{} is above {}", x, range.end)); 23 | } 24 | Ok(x) 25 | } 26 | ``` 27 | 28 | If you're going to use strings as errors, we recommend [using 29 | `Error`][use-error] as your error type, rather than `ErrorMessage`; this way, 30 | if some of your strings are `String` and some are `&'static str`, you don't 31 | need worry about merging them into a single string type. 32 | 33 | ## When might you use this pattern? 34 | 35 | This pattern is the easiest to set up and get going with, so it can be great 36 | when prototyping or spiking out an early design. It can also be great when you 37 | know that an error variant is extremely uncommon, and that there is really no 38 | way to handle it other than to log the error and move on. 39 | 40 | ## Caveats on this pattern 41 | 42 | If you are writing a library you plan to publish to crates.io, this is probably 43 | not a good way to handle errors, because it doesn't give your clients very much 44 | control. For public, open source libraries, we'd recommend using [custom 45 | failures][custom-fail] in the cases where you would use a string as an error. 46 | 47 | This pattern can also be very brittle. If you ever want to branch over which 48 | error was returned, you would have to match on the exact contents of the 49 | string. If you ever change the string contents, that will silently break that 50 | match. 51 | 52 | For these reasons, we strongly recommend against using this pattern except for 53 | prototyping and when you know the error is just going to get logged or reported 54 | to the users. 55 | 56 | [custom-fail]: ./custom-fail.html 57 | [use-error]: ./use-error.html 58 | [err-msg-api]: https://docs.rs/failure/latest/failure/fn.err_msg.html 59 | [format-err-api]: https://docs.rs/failure/latest/failure/macro.format_err.html 60 | -------------------------------------------------------------------------------- /failure_derive/tests/wraps.rs: -------------------------------------------------------------------------------- 1 | extern crate failure; 2 | #[macro_use] 3 | extern crate failure_derive; 4 | 5 | use std::fmt; 6 | use std::io; 7 | 8 | use failure::{Backtrace, Fail}; 9 | 10 | #[derive(Fail, Debug)] 11 | #[fail(display = "An error has occurred: {}", inner)] 12 | struct WrapError { 13 | #[fail(cause)] 14 | inner: io::Error, 15 | } 16 | 17 | #[test] 18 | fn wrap_error() { 19 | let inner = io::Error::from_raw_os_error(98); 20 | let err = WrapError { inner }; 21 | assert!(err 22 | .cause() 23 | .and_then(|err| err.downcast_ref::()) 24 | .is_some()); 25 | } 26 | 27 | #[derive(Fail, Debug)] 28 | #[fail(display = "An error has occurred: {}", _0)] 29 | struct WrapTupleError(#[fail(cause)] io::Error); 30 | 31 | #[test] 32 | fn wrap_tuple_error() { 33 | let io_error = io::Error::from_raw_os_error(98); 34 | let err: WrapTupleError = WrapTupleError(io_error); 35 | assert!(err 36 | .cause() 37 | .and_then(|err| err.downcast_ref::()) 38 | .is_some()); 39 | } 40 | 41 | #[derive(Fail, Debug)] 42 | #[fail(display = "An error has occurred: {}", inner)] 43 | struct WrapBacktraceError { 44 | #[fail(cause)] 45 | inner: io::Error, 46 | backtrace: Backtrace, 47 | } 48 | 49 | #[test] 50 | fn wrap_backtrace_error() { 51 | let inner = io::Error::from_raw_os_error(98); 52 | let err: WrapBacktraceError = WrapBacktraceError { 53 | inner, 54 | backtrace: Backtrace::new(), 55 | }; 56 | assert!(err 57 | .cause() 58 | .and_then(|err| err.downcast_ref::()) 59 | .is_some()); 60 | assert!(err.backtrace().is_some()); 61 | assert!(err.backtrace().unwrap().is_empty()); 62 | assert!(err.backtrace().unwrap().to_string().trim().is_empty()); 63 | } 64 | 65 | #[derive(Fail, Debug)] 66 | enum WrapEnumError { 67 | #[fail(display = "An error has occurred: {}", _0)] 68 | Io(#[fail(cause)] io::Error), 69 | #[fail(display = "An error has occurred: {}", inner)] 70 | Fmt { 71 | #[fail(cause)] 72 | inner: fmt::Error, 73 | backtrace: Backtrace, 74 | }, 75 | } 76 | 77 | #[test] 78 | fn wrap_enum_error() { 79 | let io_error = io::Error::from_raw_os_error(98); 80 | let err: WrapEnumError = WrapEnumError::Io(io_error); 81 | assert!(err 82 | .cause() 83 | .and_then(|err| err.downcast_ref::()) 84 | .is_some()); 85 | assert!(err.backtrace().is_none()); 86 | let fmt_error = fmt::Error::default(); 87 | let err: WrapEnumError = WrapEnumError::Fmt { 88 | inner: fmt_error, 89 | backtrace: Backtrace::new(), 90 | }; 91 | assert!(err 92 | .cause() 93 | .and_then(|err| err.downcast_ref::()) 94 | .is_some()); 95 | assert!(err.backtrace().is_some()); 96 | assert!(err.backtrace().unwrap().is_empty()); 97 | assert!(err.backtrace().unwrap().to_string().trim().is_empty()); 98 | } 99 | -------------------------------------------------------------------------------- /src/sync_failure.rs: -------------------------------------------------------------------------------- 1 | use Fail; 2 | use std::error::Error; 3 | use std::fmt::{self, Debug, Display}; 4 | use std::sync::Mutex; 5 | 6 | /// Wrapper for `std` errors to make them `Sync`. 7 | /// 8 | /// This exists to coerce existing types that are only `Error + Send + 9 | /// 'static` into a `Fail`-compatible representation, most notably for 10 | /// types generated by `error-chain`. 11 | /// 12 | /// Unfortunately, this requires wrapping the error in a `Mutex`, which must 13 | /// be locked for every `Debug`/`Display`. Therefore, this should be 14 | /// something of a last resort in making the error work with `failure`. 15 | /// 16 | pub struct SyncFailure { 17 | inner: Mutex, 18 | } 19 | 20 | impl SyncFailure { 21 | /// Wraps a non-`Sync` `Error` in order to make it implement `Fail`. 22 | /// 23 | /// # Example 24 | /// 25 | /// ```rust 26 | /// extern crate failure; 27 | /// 28 | /// # use std::error::Error as StdError; 29 | /// # use std::fmt::{self, Display}; 30 | /// use failure::{Error, SyncFailure}; 31 | /// use std::cell::RefCell; 32 | /// 33 | /// #[derive(Debug)] 34 | /// struct NonSyncError { 35 | /// // RefCells are non-Sync, so structs containing them will be 36 | /// // non-Sync as well. 37 | /// count: RefCell, 38 | /// } 39 | /// 40 | /// // implement Display/Error for NonSyncError... 41 | /// # 42 | /// # impl StdError for NonSyncError { 43 | /// # fn description(&self) -> &str { 44 | /// # "oops!" 45 | /// # } 46 | /// # } 47 | /// # 48 | /// # impl Display for NonSyncError { 49 | /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 50 | /// # write!(f, "oops!") 51 | /// # } 52 | /// # } 53 | /// 54 | /// fn returns_error() -> Result<(), NonSyncError> { 55 | /// // Do stuff 56 | /// # Ok(()) 57 | /// } 58 | /// 59 | /// fn my_function() -> Result<(), Error> { 60 | /// // without the map_err here, we end up with a compile error 61 | /// // complaining that NonSyncError doesn't implement Sync. 62 | /// returns_error().map_err(SyncFailure::new)?; 63 | /// // Do more stuff 64 | /// # Ok(()) 65 | /// } 66 | /// # 67 | /// # fn main() { 68 | /// # my_function().unwrap(); 69 | /// # } 70 | /// ``` 71 | /// 72 | pub fn new(err: E) -> Self { 73 | SyncFailure { 74 | inner: Mutex::new(err), 75 | } 76 | } 77 | } 78 | 79 | impl Display for SyncFailure 80 | where 81 | T: Display, 82 | { 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 84 | self.inner.lock().unwrap().fmt(f) 85 | } 86 | } 87 | 88 | impl Debug for SyncFailure 89 | where 90 | T: Debug, 91 | { 92 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 93 | (*self.inner.lock().unwrap()).fmt(f) 94 | } 95 | } 96 | 97 | impl Fail for SyncFailure {} 98 | -------------------------------------------------------------------------------- /book/src/custom-fail.md: -------------------------------------------------------------------------------- 1 | # A Custom Fail type 2 | 3 | This pattern is a way to define a new kind of failure. Defining a new kind of 4 | failure can be an effective way of representing an error for which you control 5 | all of the possible failure cases. It has several advantages: 6 | 7 | 1. You can enumerate exactly all of the possible failures that can occur in 8 | this context. 9 | 2. You have total control over the representation of the failure type. 10 | 3. Callers can destructure your error without any sort of downcasting. 11 | 12 | To implement this pattern, you should define your own type that implements 13 | `Fail`. You can use the [custom derive][derive-fail] to make this easier. For 14 | example: 15 | 16 | ```rust 17 | #[derive(Fail, Debug)] 18 | #[fail(display = "Input was invalid UTF-8")] 19 | pub struct Utf8Error; 20 | ``` 21 | 22 | This type can become as large and complicated as is appropriate to your use 23 | case. It can be an enum with a different variant for each possible error, and 24 | it can carry data with more precise information about the error. For example: 25 | 26 | ```rust 27 | #[derive(Fail, Debug)] 28 | #[fail(display = "Input was invalid UTF-8 at index {}", index)] 29 | pub struct Utf8Error { 30 | index: usize, 31 | } 32 | ``` 33 | 34 | ## When might you use this pattern? 35 | 36 | If you need to raise an error that doesn't come from one of your dependencies, 37 | this is a great pattern to use. 38 | 39 | You can also use this pattern in conjunction with [using `Error`][use-error] or 40 | defining an [Error and ErrorKind pair][error-errorkind]. Those functions which 41 | are "pure logic" and have a very constrained set of errors (such as parsing 42 | simple formats) might each return a different custom Fail type, and then the 43 | function which merges them all together, does IO, and so on, would return a 44 | more complex type like `Error` or your custom Error/ErrorKind. 45 | 46 | ## Caveats on this pattern 47 | 48 | When you have a dependency which returns a different error type, often you will 49 | be inclined to add it as a variant on your own error type. When you do that, 50 | you should tag the underlying error as the `#[fail(cause)]` of your error: 51 | 52 | ```rust 53 | #[derive(Fail, Debug)] 54 | pub enum MyError { 55 | #[fail(display = "Input was invalid UTF-8 at index {}", _0)] 56 | Utf8Error(usize), 57 | #[fail(display = "{}", _0)] 58 | Io(#[fail(cause)] io::Error), 59 | } 60 | ``` 61 | 62 | Up to a limit, this design can work. However, it has some problems: 63 | 64 | - It can be hard to be forward compatible with new dependencies that raise 65 | their own kinds of errors in the future. 66 | - It defines a 1-1 relationship between a variant of the error and an 67 | underlying error. 68 | 69 | Depending on your use case, as your function grows in complexity, it can be 70 | better to transition to [using Error][use-error] or [defining an Error & 71 | ErrorKind pair][error-errorkind]. 72 | 73 | [derive-fail]: ./derive-fail.html 74 | [use-error]: ./use-error.html 75 | [error-errorkind]: ./error-errorkind.html 76 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at boats@mozilla.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/error/error_impl_small.rs: -------------------------------------------------------------------------------- 1 | use std::heap::{Heap, Alloc, Layout}; 2 | 3 | use core::mem; 4 | use core::ptr; 5 | 6 | use Fail; 7 | use backtrace::Backtrace; 8 | 9 | pub(crate) struct ErrorImpl { 10 | inner: &'static mut Inner, 11 | } 12 | 13 | // Dynamically sized inner value 14 | struct Inner { 15 | backtrace: Backtrace, 16 | vtable: *const VTable, 17 | failure: FailData, 18 | } 19 | 20 | unsafe impl Send for Inner { } 21 | unsafe impl Sync for Inner { } 22 | 23 | extern { 24 | type VTable; 25 | type FailData; 26 | } 27 | 28 | #[allow(dead_code)] 29 | struct InnerRaw { 30 | header: InnerHeader, 31 | failure: F, 32 | } 33 | 34 | #[allow(dead_code)] 35 | struct InnerHeader { 36 | backtrace: Backtrace, 37 | vtable: *const VTable, 38 | } 39 | 40 | struct TraitObject { 41 | #[allow(dead_code)] 42 | data: *const FailData, 43 | vtable: *const VTable, 44 | } 45 | 46 | impl From for ErrorImpl { 47 | fn from(failure: F) -> ErrorImpl { 48 | let backtrace = if failure.backtrace().is_none() { 49 | Backtrace::new() 50 | } else { 51 | Backtrace::none() 52 | }; 53 | 54 | unsafe { 55 | let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; 56 | 57 | let ptr: *mut InnerRaw = match Heap.alloc(Layout::new::>()) { 58 | Ok(p) => p as *mut InnerRaw, 59 | Err(e) => Heap.oom(e), 60 | }; 61 | 62 | // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` 63 | ptr::write(ptr, InnerRaw { 64 | header: InnerHeader { 65 | backtrace, 66 | vtable, 67 | }, 68 | failure, 69 | }); 70 | 71 | let inner: &'static mut Inner = mem::transmute(ptr); 72 | 73 | ErrorImpl { inner } 74 | } 75 | } 76 | } 77 | 78 | impl ErrorImpl { 79 | pub(crate) fn failure(&self) -> &Fail { 80 | unsafe { 81 | mem::transmute::(TraitObject { 82 | data: &self.inner.failure as *const FailData, 83 | vtable: self.inner.vtable, 84 | }) 85 | } 86 | } 87 | 88 | pub(crate) fn failure_mut(&mut self) -> &mut Fail { 89 | unsafe { 90 | mem::transmute::(TraitObject { 91 | data: &mut self.inner.failure as *const FailData, 92 | vtable: self.inner.vtable, 93 | }) 94 | } 95 | } 96 | 97 | pub(crate) fn backtrace(&self) -> &Backtrace { 98 | &self.inner.backtrace 99 | } 100 | 101 | pub(crate) fn downcast(self) -> Result { 102 | let ret: Option = self.failure().downcast_ref().map(|fail| { 103 | unsafe { 104 | // drop the backtrace 105 | let _ = ptr::read(&self.inner.backtrace as *const Backtrace); 106 | // read out the fail type 107 | ptr::read(fail as *const T) 108 | } 109 | }); 110 | match ret { 111 | Some(ret) => { 112 | // forget self (backtrace is dropped, failure is moved 113 | mem::forget(self); 114 | Ok(ret) 115 | } 116 | _ => Err(self) 117 | } 118 | } 119 | } 120 | 121 | 122 | #[cfg(test)] 123 | mod test { 124 | use std::mem::size_of; 125 | 126 | use super::ErrorImpl; 127 | 128 | #[test] 129 | fn assert_is_one_word() { 130 | assert_eq!(size_of::(), size_of::()); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /book/src/error.md: -------------------------------------------------------------------------------- 1 | # The `Error` type 2 | 3 | In addition to the trait `Fail`, failure provides a type called `Error`. Any 4 | type that implements `Fail` can be cast into `Error` using From and Into, which 5 | allows users to throw errors using `?` which have different types, if the 6 | function returns an `Error`. 7 | 8 | For example: 9 | 10 | ```rust 11 | // Something you can deserialize 12 | #[derive(Deserialize)] 13 | struct Object { 14 | ... 15 | } 16 | 17 | impl Object { 18 | // This throws both IO Errors and JSON Errors, but they both get converted 19 | // into the Error type. 20 | fn from_file(path: &Path) -> Result { 21 | let mut string = String::new(); 22 | File::open(path)?.read_to_string(&mut string)?; 23 | let object = json::from_str(&string)?; 24 | Ok(object) 25 | } 26 | } 27 | ``` 28 | 29 | ## Causes and Backtraces 30 | 31 | The Error type has all of the methods from the Fail trait, with a few notable 32 | differences. Most importantly, the cause and backtrace methods on Error do not 33 | return Options - an Error is *guaranteed* to have a cause and a backtrace. 34 | 35 | ```rust 36 | // Both methods are guaranteed to return an &Fail and an &Backtrace 37 | println!("{}, {}", error.cause(), error.backtrace()) 38 | ``` 39 | 40 | An `Error`'s cause is always the failure that was cast into this `Error`. 41 | That failure may have further underlying causes. Unlike Fail, this means that 42 | the cause of an Error will have the same Display representation as the Error 43 | itself. 44 | 45 | As to the error's guaranteed backtrace, when the conversion into the Error type 46 | happens, if the underlying failure does not provide a backtrace, a new 47 | backtrace is constructed pointing to that conversion point (rather than the 48 | origin of the error). This construction only happens if there is no underlying 49 | backtrace; if it does have a backtrace no new backtrace is constructed. 50 | 51 | ## Downcasting 52 | 53 | The Error type also supports downcasting into any concrete Fail type. It can be 54 | downcast by reference or by value - when downcasting by value, the return type 55 | is `Result`, allowing you to get the error back out of it. 56 | 57 | ```rust 58 | match error.downcast::() { 59 | Ok(io_error) => { ... } 60 | Err(error) => { ... } 61 | } 62 | ``` 63 | 64 | ## Implementation details 65 | 66 | `Error` is essentially a trait object, but with some fanciness it may generate 67 | and store the backtrace if the underlying failure did not have one. In 68 | particular, we use a custom dynamically sized type to store the backtrace 69 | information inline with the trait object data. 70 | 71 | ```rust 72 | struct Error { 73 | // Inner is a dynamically sized type 74 | inner: Box>, 75 | } 76 | 77 | struct Inner { 78 | backtrace: Backtrace, 79 | failure: F, 80 | } 81 | ``` 82 | 83 | By storing the backtrace in the heap this way, we avoid increasing the size of 84 | the Error type beyond that of two non-nullable pointers. This keeps the size of 85 | the `Result` type from getting too large, avoiding having a negative impact on 86 | the "happy path" of returning Ok. For example, a `Result<(), Error>` should be 87 | represented as a pair of nullable pointers, with the null case representing 88 | `Ok`. Similar optimizations can be applied to values up to at least a pointer 89 | in size. 90 | 91 | To emphasize: Error is intended for use cases where the error case is 92 | considered relatively uncommon. This optimization makes the overhead of an 93 | error less than it otherwise would be for the Ok branch. In cases where errors 94 | are going to be returned extremely frequently, returning this Error type is 95 | probably not appropriate, but you should benchmark in those cases. 96 | 97 | (As a rule of thumb: if you're not sure if you can afford to have a trait 98 | object, you probably *can* afford it. Heap allocations are not nearly as cheap 99 | as stack allocations, but they're cheap enough that you can almost always 100 | afford them.) 101 | -------------------------------------------------------------------------------- /src/backtrace/internal.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::env; 3 | use std::ffi::OsString; 4 | use std::fmt; 5 | #[allow(deprecated)] // to allow for older Rust versions (<1.24) 6 | use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; 7 | use std::sync::Mutex; 8 | 9 | pub use super::backtrace::Backtrace; 10 | 11 | const GENERAL_BACKTRACE: &str = "RUST_BACKTRACE"; 12 | const FAILURE_BACKTRACE: &str = "RUST_FAILURE_BACKTRACE"; 13 | 14 | pub(super) struct InternalBacktrace { 15 | backtrace: Option, 16 | } 17 | 18 | struct MaybeResolved { 19 | resolved: Mutex, 20 | backtrace: UnsafeCell, 21 | } 22 | 23 | unsafe impl Send for MaybeResolved {} 24 | unsafe impl Sync for MaybeResolved {} 25 | 26 | impl InternalBacktrace { 27 | pub(super) fn new() -> InternalBacktrace { 28 | #[allow(deprecated)] // to allow for older Rust versions (<1.24) 29 | static ENABLED: AtomicUsize = ATOMIC_USIZE_INIT; 30 | 31 | match ENABLED.load(Ordering::SeqCst) { 32 | 0 => { 33 | let enabled = is_backtrace_enabled(|var| env::var_os(var)); 34 | ENABLED.store(enabled as usize + 1, Ordering::SeqCst); 35 | if !enabled { 36 | return InternalBacktrace { backtrace: None } 37 | } 38 | } 39 | 1 => return InternalBacktrace { backtrace: None }, 40 | _ => {} 41 | } 42 | 43 | InternalBacktrace { 44 | backtrace: Some(MaybeResolved { 45 | resolved: Mutex::new(false), 46 | backtrace: UnsafeCell::new(Backtrace::new_unresolved()), 47 | }), 48 | } 49 | } 50 | 51 | pub(super) fn none() -> InternalBacktrace { 52 | InternalBacktrace { backtrace: None } 53 | } 54 | 55 | pub(super) fn as_backtrace(&self) -> Option<&Backtrace> { 56 | let bt = match self.backtrace { 57 | Some(ref bt) => bt, 58 | None => return None, 59 | }; 60 | let mut resolved = bt.resolved.lock().unwrap(); 61 | unsafe { 62 | if !*resolved { 63 | (*bt.backtrace.get()).resolve(); 64 | *resolved = true; 65 | } 66 | Some(&*bt.backtrace.get()) 67 | } 68 | } 69 | 70 | pub(super) fn is_none(&self) -> bool { 71 | self.backtrace.is_none() 72 | } 73 | } 74 | 75 | impl fmt::Debug for InternalBacktrace { 76 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 | f.debug_struct("InternalBacktrace") 78 | .field("backtrace", &self.as_backtrace()) 79 | .finish() 80 | } 81 | } 82 | 83 | fn is_backtrace_enabled Option>(get_var: F) -> bool { 84 | match get_var(FAILURE_BACKTRACE) { 85 | Some(ref val) if val != "0" => true, 86 | Some(ref val) if val == "0" => false, 87 | _ => match get_var(GENERAL_BACKTRACE) { 88 | Some(ref val) if val != "0" => true, 89 | _ => false, 90 | } 91 | } 92 | } 93 | 94 | #[cfg(test)] 95 | mod tests { 96 | use super::*; 97 | 98 | const YEA: Option<&str> = Some("1"); 99 | const NAY: Option<&str> = Some("0"); 100 | const NOT_SET: Option<&str> = None; 101 | 102 | macro_rules! test_enabled { 103 | (failure: $failure:ident, general: $general:ident => $result:expr) => {{ 104 | assert_eq!(is_backtrace_enabled(|var| match var { 105 | FAILURE_BACKTRACE => $failure.map(OsString::from), 106 | GENERAL_BACKTRACE => $general.map(OsString::from), 107 | _ => panic!() 108 | }), $result); 109 | }} 110 | } 111 | 112 | #[test] 113 | fn always_enabled_if_failure_is_set_to_yes() { 114 | test_enabled!(failure: YEA, general: YEA => true); 115 | test_enabled!(failure: YEA, general: NOT_SET => true); 116 | test_enabled!(failure: YEA, general: NAY => true); 117 | } 118 | 119 | #[test] 120 | fn never_enabled_if_failure_is_set_to_no() { 121 | test_enabled!(failure: NAY, general: YEA => false); 122 | test_enabled!(failure: NAY, general: NOT_SET => false); 123 | test_enabled!(failure: NAY, general: NAY => false); 124 | } 125 | 126 | #[test] 127 | fn follows_general_if_failure_is_not_set() { 128 | test_enabled!(failure: NOT_SET, general: YEA => true); 129 | test_enabled!(failure: NOT_SET, general: NOT_SET => false); 130 | test_enabled!(failure: NOT_SET, general: NAY => false); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # failure - a new error management story 2 | 3 | **Notice**: `failure` is deprecated. If you liked `failure`'s API, consider using: 4 | - [Anyhow](https://github.com/dtolnay/anyhow) is a good replacement for `failure::Error`. 5 | - [thiserror](https://github.com/dtolnay/thiserror) is a good, near drop-in replacement for `#[derive(Fail)]`. 6 | 7 | --- 8 | 9 | [![Build Status](https://travis-ci.org/rust-lang-nursery/failure.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/failure) 10 | [![Latest Version](https://img.shields.io/crates/v/failure.svg)](https://crates.io/crates/failure) 11 | [![docs](https://docs.rs/failure/badge.svg)](https://docs.rs/failure) 12 | 13 | `failure` is designed to make it easier to manage errors in Rust. It is 14 | intended to replace error management based on `std::error::Error` with a new 15 | system based on lessons learned over the past several years, including those 16 | learned from experience with quick-error and error-chain. 17 | 18 | `failure` provides two core components: 19 | 20 | * `Fail`: A new trait for custom error types. 21 | * `Error`: A struct which any type that implements `Fail` can be cast into. 22 | 23 | ## Evolution 24 | 25 | Failure is currently evolving as a library. First of all there is work going 26 | on in Rust itself to [fix the error trait](https://github.com/rust-lang/rfcs/pull/2504) 27 | secondarily the original plan for Failure towards 1.0 is unlikely to happen 28 | in the current form. 29 | 30 | As such the original master branch towards 1.0 of failure was removed and 31 | master now represents the future iteration steps of 0.1 until it's clear 32 | what happens in the stdlib. 33 | 34 | The original 1.0 branch can be found in [evolution/1.0](https://github.com/rust-lang-nursery/failure/tree/evolution/1.0). 35 | 36 | ## Example 37 | 38 | ```rust 39 | extern crate serde; 40 | extern crate toml; 41 | 42 | #[macro_use] extern crate failure; 43 | #[macro_use] extern crate serde_derive; 44 | 45 | use std::collections::HashMap; 46 | use std::path::PathBuf; 47 | use std::str::FromStr; 48 | 49 | use failure::Error; 50 | 51 | // This is a new error type that you've created. It represents the ways a 52 | // toolchain could be invalid. 53 | // 54 | // The custom derive for Fail derives an impl of both Fail and Display. 55 | // We don't do any other magic like creating new types. 56 | #[derive(Debug, Fail)] 57 | enum ToolchainError { 58 | #[fail(display = "invalid toolchain name: {}", name)] 59 | InvalidToolchainName { 60 | name: String, 61 | }, 62 | #[fail(display = "unknown toolchain version: {}", version)] 63 | UnknownToolchainVersion { 64 | version: String, 65 | } 66 | } 67 | 68 | pub struct ToolchainId { 69 | // ... etc 70 | } 71 | 72 | impl FromStr for ToolchainId { 73 | type Err = ToolchainError; 74 | 75 | fn from_str(s: &str) -> Result { 76 | // ... etc 77 | } 78 | } 79 | 80 | pub type Toolchains = HashMap; 81 | 82 | // This opens a toml file containing associations between ToolchainIds and 83 | // Paths (the roots of those toolchains). 84 | // 85 | // This could encounter an io Error, a toml parsing error, or a ToolchainError, 86 | // all of them will be thrown into the special Error type 87 | pub fn read_toolchains(path: PathBuf) -> Result 88 | { 89 | use std::fs::File; 90 | use std::io::Read; 91 | 92 | let mut string = String::new(); 93 | File::open(path)?.read_to_string(&mut string)?; 94 | 95 | let toml: HashMap = toml::from_str(&string)?; 96 | 97 | let toolchains = toml.iter().map(|(key, path)| { 98 | let toolchain_id = key.parse()?; 99 | Ok((toolchain_id, path)) 100 | }).collect::>()?; 101 | 102 | Ok(toolchains) 103 | } 104 | ``` 105 | 106 | ## Requirements 107 | 108 | Both failure and failure_derive are intended to compile on all stable versions 109 | of Rust newer than 1.31.0, as well as the latest beta and the latest nightly. 110 | If either crate fails to compile on any version newer than 1.31.0, please open 111 | an issue. 112 | 113 | failure is **no_std** compatible, though some aspects of it (primarily the 114 | `Error` type) will not be available in no_std mode. 115 | 116 | ## License 117 | 118 | failure is licensed under the terms of the MIT License or the Apache License 119 | 2.0, at your choosing. 120 | 121 | ## Code of Conduct 122 | 123 | Contribution to the failure crate is organized under the terms of the 124 | Contributor Covenant, the maintainer of failure, @withoutboats, promises to 125 | intervene to uphold that code of conduct. 126 | -------------------------------------------------------------------------------- /book/src/string-custom-error.md: -------------------------------------------------------------------------------- 1 | # Strings and custom fail type 2 | 3 | This pattern is an hybrid between the [_An Error and ErrorKind pair_](./error-errorkind.md) and 4 | [_Using the Error type_](./use-error.md). 5 | 6 | Such an error type can be implemented in the same way that what was shown in 7 | the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern, but here, the context is a 8 | simple string: 9 | 10 | ```rust 11 | extern crate core; 12 | extern crate failure; 13 | 14 | use core::fmt::{self, Display}; 15 | use failure::{Backtrace, Context, Fail, ResultExt}; 16 | 17 | #[derive(Debug)] 18 | pub struct MyError { 19 | inner: Context, 20 | } 21 | 22 | impl Fail for MyError { 23 | fn name(&self) -> Option<&str> { 24 | self.inner.name() 25 | } 26 | 27 | fn cause(&self) -> Option<&Fail> { 28 | self.inner.cause() 29 | } 30 | 31 | fn backtrace(&self) -> Option<&Backtrace> { 32 | self.inner.backtrace() 33 | } 34 | } 35 | 36 | impl Display for MyError { 37 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 38 | Display::fmt(&self.inner, f) 39 | } 40 | } 41 | ``` 42 | 43 | To make the type easier to use, a few impls can be added: 44 | 45 | ```rust 46 | // Allows writing `MyError::from("oops"))?` 47 | impl From<&'static str> for MyError { 48 | fn from(msg: &'static str) -> MyError { 49 | MyError { 50 | inner: Context::new(msg), 51 | } 52 | } 53 | } 54 | 55 | // Allows adding more context via a String 56 | impl From> for MyError { 57 | fn from(inner: Context) -> MyError { 58 | MyError { inner } 59 | } 60 | } 61 | 62 | // Allows adding more context via a &str 63 | impl From> for MyError { 64 | fn from(inner: Context<&'static str>) -> MyError { 65 | MyError { 66 | inner: inner.map(|s| s.to_string()), 67 | } 68 | } 69 | } 70 | ``` 71 | 72 | Here is how it is used: 73 | 74 | ```rust 75 | fn main() { 76 | println!("{:?}", err2()); 77 | } 78 | 79 | // Unlike the "Using the Error type" pattern, functions return our own error 80 | // type here. 81 | fn err1() -> Result<(), MyError> { 82 | Ok(Err(MyError::from("err1"))?) 83 | } 84 | 85 | fn err2() -> Result<(), MyError> { 86 | // Unlike the "An Error and ErrorKind pair" pattern, our context is a 87 | // simple string. We can chain errors and provide detailed error messages, 88 | // but we don't have to deal with the complexity of an error kind type 89 | Ok(err1().context("err2")?) 90 | } 91 | ``` 92 | 93 | ## Variant with `&'static str` 94 | 95 | If you don't need to format strings, you can avoid an 96 | allocation by using a `Context<&'static str>` instead of a 97 | `Context`. 98 | 99 | ```rust 100 | extern crate core; 101 | extern crate failure; 102 | 103 | use core::fmt::{self, Display}; 104 | use failure::{Backtrace, Context, Fail, ResultExt}; 105 | 106 | #[derive(Debug)] 107 | pub struct MyError { 108 | inner: Context<&'static str>, 109 | } 110 | 111 | impl Fail for MyError { 112 | fn name(&self) -> Option<&str> { 113 | self.inner.name() 114 | } 115 | 116 | fn cause(&self) -> Option<&Fail> { 117 | self.inner.cause() 118 | } 119 | 120 | fn backtrace(&self) -> Option<&Backtrace> { 121 | self.inner.backtrace() 122 | } 123 | } 124 | 125 | impl Display for MyError { 126 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 127 | Display::fmt(&self.inner, f) 128 | } 129 | } 130 | 131 | impl From<&'static str> for MyError { 132 | fn from(msg: &'static str) -> MyError { 133 | MyError { 134 | inner: Context::new(msg.into()), 135 | } 136 | } 137 | } 138 | 139 | impl From> for MyError { 140 | fn from(inner: Context<&'static str>) -> MyError { 141 | MyError { 142 | inner, 143 | } 144 | } 145 | } 146 | ``` 147 | 148 | ## When might you use this pattern? 149 | 150 | Sometimes, you don't want to use the [_Using the Error type_](./use-error.md) 151 | pattern, because you want to expose a few different error types. But you don't 152 | want to use the [_An Error and ErrorKind pair_](./error-errorkind.md) pattern 153 | either, because there is no need to provide the context as an enum or because 154 | it would be too much work, if the error can occur in many different contexts. 155 | 156 | For instance, if you're writing a library that decodes/encodes a complex binary 157 | format, you might want to expose a `DecodeError` and an `EncodeError` error 158 | type, but provide the context as a simple string instead of an error kind, because: 159 | 160 | - users may not care too much about the context in which a `DecodeError` or 161 | `EncodeError` was encountered, they just want a nice message to explain it 162 | - your binary format is really complex, errors can occur in many different 163 | places, and you don't want to end up with a giant `ErrorKind` enum 164 | 165 | 166 | ## Caveats on this pattern 167 | 168 | If using the `Context` variant, an extra allocation is used for the string. 169 | -------------------------------------------------------------------------------- /book/src/error-errorkind.md: -------------------------------------------------------------------------------- 1 | # An Error and ErrorKind pair 2 | 3 | This pattern is the most robust way to manage errors - and also the most high 4 | maintenance. It combines some of the advantages of the [using Error][use-error] 5 | pattern and the [custom failure][custom-fail] patterns, while avoiding some of 6 | the disadvantages each of those patterns has: 7 | 8 | 1. Like `Error`, this is forward compatible with new underlying kinds of 9 | errors from your dependencies. 10 | 2. Like custom failures, this pattern allows you to specify additional information about the error that your dependencies don't give you. 11 | 3. Like `Error`, it can be easier to convert underlying errors from dependency 12 | into this type than for custom failures. 13 | 4. Like custom failures, users can gain some information about the error 14 | without downcasting. 15 | 16 | The pattern is to create two new failure types: an `Error` and an `ErrorKind`, 17 | and to leverage [the `Context` type][context-api] provided by failure. 18 | 19 | ```rust 20 | #[derive(Debug)] 21 | struct MyError { 22 | inner: Context, 23 | } 24 | 25 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)] 26 | enum MyErrorKind { 27 | // A plain enum with no data in any of its variants 28 | // 29 | // For example: 30 | #[fail(display = "A contextual error message.")] 31 | OneVariant, 32 | // ... 33 | } 34 | ``` 35 | 36 | Unfortunately, it is not easy to correctly derive `Fail` for `MyError` so that 37 | it delegates things to its inner `Context`. You should write those impls 38 | yourself: 39 | 40 | ```rust 41 | impl Fail for MyError { 42 | fn name(&self) -> Option<&str> { 43 | self.inner.name() 44 | } 45 | 46 | fn cause(&self) -> Option<&Fail> { 47 | self.inner.cause() 48 | } 49 | 50 | fn backtrace(&self) -> Option<&Backtrace> { 51 | self.inner.backtrace() 52 | } 53 | } 54 | 55 | impl Display for MyError { 56 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 57 | Display::fmt(&self.inner, f) 58 | } 59 | } 60 | ``` 61 | 62 | You should also provide some conversions and accessors, to go between a 63 | Context, your ErrorKind, and your Error: 64 | 65 | ```rust 66 | impl MyError { 67 | pub fn kind(&self) -> MyErrorKind { 68 | *self.inner.get_context() 69 | } 70 | } 71 | 72 | impl From for MyError { 73 | fn from(kind: MyErrorKind) -> MyError { 74 | MyError { inner: Context::new(kind) } 75 | } 76 | } 77 | 78 | impl From> for MyError { 79 | fn from(inner: Context) -> MyError { 80 | MyError { inner: inner } 81 | } 82 | } 83 | ``` 84 | 85 | With this code set up, you can use the context method from failure to apply 86 | your ErrorKind to `Result`s in underlying libraries: 87 | 88 | ```rust 89 | use failure::ResultExt; 90 | perform_some_io().context(ErrorKind::NetworkFailure)?; 91 | ``` 92 | 93 | You can also directly throw `ErrorKind` without an underlying error when 94 | appropriate: 95 | 96 | ```rust 97 | Err(ErrorKind::DomainSpecificError)? 98 | ``` 99 | 100 | ### What should your ErrorKind contain? 101 | 102 | Your error kind probably should not carry data - and if it does, it should only 103 | carry stateless data types that provide additional information about what the 104 | `ErrorKind` means. This way, your `ErrorKind` can be `Eq`, making it 105 | easy to use as a way of comparing errors. 106 | 107 | Your ErrorKind is a way of providing information about what errors mean 108 | appropriate to the level of abstraction that your library operates at. As some 109 | examples: 110 | 111 | - If your library expects to read from the user's `Cargo.toml`, you might have 112 | a `InvalidCargoToml` variant, to capture what `io::Error` and `toml::Error` 113 | mean in the context of your library. 114 | - If your library does both file system activity and network activity, you 115 | might have `Filesystem` and `Network` variants, to divide up the `io::Error`s 116 | between which system in particular failed. 117 | 118 | Exactly what semantic information is appropriate depends entirely on what this 119 | bit of code is intended to do. 120 | 121 | ## When might you use this pattern? 122 | 123 | The most likely use cases for this pattern are mid-layer which perform a 124 | function that requires many dependencies, and that are intended to be used in 125 | production. Libraries with few dependencies do not need to manage many 126 | underlying error types and can probably suffice with a simpler [custom 127 | failure][custom-fail]. Applications that know they are almost always just going 128 | to log these errors can get away with [using the Error type][use-error] rather 129 | than managing extra context information. 130 | 131 | That said, when you need to provide the most expressive information about an 132 | error possible, this can be a good approach. 133 | 134 | ## Caveats on this pattern 135 | 136 | This pattern is the most involved pattern documented in this book. It involves 137 | a lot of boilerplate to set up (which may be automated away eventually), and it 138 | requires you to apply a contextual message to every underlying error that is 139 | thrown inside your code. It can be a lot of work to maintain this pattern. 140 | 141 | Additionally, like the Error type, the Context type may use an allocation and a 142 | dynamic dispatch internally. If you know this is too expensive for your use 143 | case, you should not use this pattern. 144 | 145 | [use-error]: ./use-error.html 146 | [custom-fail]: ./custom-fail.html 147 | [context-api]: https://docs.rs/failure/latest/failure/struct.Context.html 148 | -------------------------------------------------------------------------------- /book/src/derive-fail.md: -------------------------------------------------------------------------------- 1 | # Deriving `Fail` 2 | 3 | Though you can implement `Fail` yourself, we also provide a derive macro to 4 | generate the impl for you. To get access to this macro, you must tag the extern 5 | crate declaration with `#[macro_use]`, as in: 6 | 7 | ```rust 8 | #[macro_use] extern crate failure; 9 | ``` 10 | 11 | In its smallest form, deriving Fail looks like this: 12 | 13 | ```rust 14 | #[macro_use] extern crate failure; 15 | 16 | use std::fmt; 17 | 18 | #[derive(Fail, Debug)] 19 | struct MyError; 20 | 21 | impl fmt::Display for MyError { 22 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 23 | write!(f, "An error occurred.") 24 | } 25 | } 26 | ``` 27 | 28 | All failures need to implement `Display`, so we have added an impl of 29 | Display. However, implementing `Display` is much more boilerplate than 30 | implementing `Fail` - this is why we support deriving `Display` for you. 31 | 32 | ## Deriving `Display` 33 | 34 | You can derive an implementation of `Display` with a special attribute: 35 | 36 | ```rust 37 | #[macro_use] extern crate failure; 38 | 39 | #[derive(Fail, Debug)] 40 | #[fail(display = "An error occurred.")] 41 | struct MyError; 42 | ``` 43 | 44 | This attribute will cause the `Fail` derive to also generate an impl of 45 | `Display`, so that you don't have to implement one yourself. 46 | 47 | ### String interpolation 48 | 49 | String literals are not enough for error messages in many cases. Often, you 50 | want to include parts of the error value interpolated into the message. You can 51 | do this with failure using the same string interpolation syntax as Rust's 52 | formatting and printing macros: 53 | 54 | ```rust 55 | #[macro_use] extern crate failure; 56 | 57 | #[derive(Fail, Debug)] 58 | #[fail(display = "An error occurred with error code {}. ({})", code, message)] 59 | struct MyError { 60 | code: i32, 61 | message: String, 62 | } 63 | ``` 64 | 65 | Note that unlike code that would appear in a method, this does not use 66 | something like `self.code` or `self.message`; it just uses the field names 67 | directly. This is because of a limitation in Rust's current attribute syntax. 68 | As a result, you can only interpolate fields through the derivation; you cannot 69 | perform method calls or use other arbitrary expressions. 70 | 71 | ### Tuple structs 72 | 73 | With regular structs, you can use the name of the field in string 74 | interpolation. When deriving Fail for a tuple struct, you might expect to use 75 | the numeric index to refer to fields `0`, `1`, et cetera. However, a compiler 76 | limitation prevents this from parsing today. 77 | 78 | For the time being, tuple field accesses in the display attribute need to be 79 | prefixed with an underscore: 80 | 81 | ```rust 82 | #[macro_use] extern crate failure; 83 | 84 | #[derive(Fail, Debug)] 85 | #[fail(display = "An error occurred with error code {}.", _0)] 86 | struct MyError(i32); 87 | 88 | 89 | #[derive(Fail, Debug)] 90 | #[fail(display = "An error occurred with error code {} ({}).", _0, _1)] 91 | struct MyOtherError(i32, String); 92 | ``` 93 | 94 | ### Enums 95 | 96 | Implementing Display is also supported for enums by applying the attribute to 97 | each variant of the enum, rather than to the enum as a whole. The Display impl 98 | will match over the enum to generate the correct error message. For example: 99 | 100 | ```rust 101 | #[macro_use] extern crate failure; 102 | 103 | #[derive(Fail, Debug)] 104 | enum MyError { 105 | #[fail(display = "{} is not a valid version.", _0)] 106 | InvalidVersion(u32), 107 | #[fail(display = "IO error: {}", error)] 108 | IoError { error: io::Error }, 109 | #[fail(display = "An unknown error has occurred.")] 110 | UnknownError, 111 | } 112 | ``` 113 | 114 | ## Overriding `backtrace` 115 | 116 | The backtrace method will be automatically overridden if the type contains a 117 | field with the type `Backtrace`. This works for both structs and enums. 118 | 119 | ```rust 120 | #[macro_use] extern crate failure; 121 | 122 | use failure::Backtrace; 123 | 124 | /// MyError::backtrace will return a reference to the backtrace field 125 | #[derive(Fail, Debug)] 126 | #[fail(display = "An error occurred.")] 127 | struct MyError { 128 | backtrace: Backtrace, 129 | } 130 | 131 | /// MyEnumError::backtrace will return a reference to the backtrace only if it 132 | /// is Variant2, otherwise it will return None. 133 | #[derive(Fail, Debug)] 134 | enum MyEnumError { 135 | #[fail(display = "An error occurred.")] 136 | Variant1, 137 | #[fail(display = "A different error occurred.")] 138 | Variant2(Backtrace), 139 | } 140 | ``` 141 | 142 | This happens automatically; no other annotations are necessary. It only works 143 | if the type is named Backtrace, and not if you have created an alias for the 144 | Backtrace type. 145 | 146 | ## Overriding `cause` 147 | 148 | In contrast to `backtrace`, the cause cannot be determined by type name alone 149 | because it could be any type which implements `Fail`. For this reason, if your 150 | error has an underlying cause field, you need to annotate that field with 151 | the `#[fail(cause)]` attribute. 152 | 153 | This can be used in fields of enums as well as structs. 154 | 155 | 156 | ```rust 157 | #[macro_use] extern crate failure; 158 | 159 | use std::io; 160 | 161 | /// MyError::cause will return a reference to the io_error field 162 | #[derive(Fail, Debug)] 163 | #[fail(display = "An error occurred.")] 164 | struct MyError { 165 | #[fail(cause)] io_error: io::Error, 166 | } 167 | 168 | /// MyEnumError::cause will return a reference only if it is Variant2, 169 | /// otherwise it will return None. 170 | #[derive(Fail, Debug)] 171 | enum MyEnumError { 172 | #[fail(display = "An error occurred.")] 173 | Variant1, 174 | #[fail(display = "A different error occurred.")] 175 | Variant2(#[fail(cause)] io::Error), 176 | } 177 | ``` 178 | -------------------------------------------------------------------------------- /src/backtrace/mod.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Debug, Display}; 2 | 3 | macro_rules! with_backtrace { ($($i:item)*) => ($(#[cfg(all(feature = "backtrace", feature = "std"))]$i)*) } 4 | macro_rules! without_backtrace { ($($i:item)*) => ($(#[cfg(not(all(feature = "backtrace", feature = "std")))]$i)*) } 5 | 6 | without_backtrace! { 7 | /// A `Backtrace`. 8 | /// 9 | /// This is an opaque wrapper around the backtrace provided by 10 | /// libbacktrace. A variety of optimizations have been performed to avoid 11 | /// unnecessary or ill-advised work: 12 | /// 13 | /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` 14 | /// is an empty struct, and will be completely compiled away. 15 | /// - If this crate is run without the `RUST_BACKTRACE` environmental 16 | /// variable enabled, the backtrace will not be generated at runtime. 17 | /// - Even if a backtrace is generated, the most expensive part of 18 | /// generating a backtrace is symbol resolution. This backtrace does not 19 | /// perform symbol resolution until it is actually read (e.g. by 20 | /// printing it). If the Backtrace is never used for anything, symbols 21 | /// never get resolved. 22 | /// 23 | /// Even with these optimizations, including a backtrace in your failure 24 | /// may not be appropriate to your use case. You are not required to put a 25 | /// backtrace in a custom `Fail` type. 26 | /// 27 | /// > (We have detected that this crate was documented with no_std 28 | /// > compatibility turned on. The version of this crate that has been 29 | /// > documented here will never generate a backtrace.) 30 | pub struct Backtrace { 31 | _secret: (), 32 | } 33 | 34 | impl Backtrace { 35 | /// Constructs a new backtrace. This will only create a real backtrace 36 | /// if the crate is compiled in std mode and the `RUST_BACKTRACE` 37 | /// environmental variable is activated. 38 | /// 39 | /// > (We have detected that this crate was documented with no_std 40 | /// > compatibility turned on. The version of this crate that has been 41 | /// > documented here will never generate a backtrace.) 42 | pub fn new() -> Backtrace { 43 | Backtrace { _secret: () } 44 | } 45 | 46 | #[cfg(feature = "std")] 47 | pub(crate) fn none() -> Backtrace { 48 | Backtrace { _secret: () } 49 | } 50 | 51 | #[cfg(feature = "std")] 52 | pub(crate) fn is_none(&self) -> bool { 53 | true 54 | } 55 | 56 | /// Returns true if displaying this backtrace would be an empty string. 57 | /// 58 | /// > (We have detected that this crate was documented with no_std 59 | /// > compatibility turned on. The version of this crate that has been 60 | /// > documented here will never generate a backtrace and this method 61 | /// > will always return true.) 62 | pub fn is_empty(&self) -> bool { 63 | true 64 | } 65 | } 66 | 67 | impl Default for Backtrace { 68 | fn default() -> Backtrace { 69 | Backtrace::new() 70 | } 71 | } 72 | 73 | impl Debug for Backtrace { 74 | fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { 75 | Ok(()) 76 | } 77 | } 78 | 79 | impl Display for Backtrace { 80 | fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { 81 | Ok(()) 82 | } 83 | } 84 | } 85 | 86 | with_backtrace! { 87 | extern crate backtrace; 88 | 89 | mod internal; 90 | 91 | use self::internal::InternalBacktrace; 92 | 93 | /// A `Backtrace`. 94 | /// 95 | /// This is an opaque wrapper around the backtrace provided by 96 | /// libbacktrace. A variety of optimizations have been performed to avoid 97 | /// unnecessary or ill-advised work: 98 | /// 99 | /// - If this crate is compiled in `no_std` compatible mode, `Backtrace` 100 | /// is an empty struct, and will be completely compiled away. 101 | /// - If this crate is run without the `RUST_BACKTRACE` environmental 102 | /// variable enabled, the backtrace will not be generated at runtime. 103 | /// - Even if a backtrace is generated, the most expensive part of 104 | /// generating a backtrace is symbol resolution. This backtrace does not 105 | /// perform symbol resolution until it is actually read (e.g. by 106 | /// printing it). If the Backtrace is never used for anything, symbols 107 | /// never get resolved. 108 | /// 109 | /// Even with these optimizations, including a backtrace in your failure 110 | /// may not be appropriate to your use case. You are not required to put a 111 | /// backtrace in a custom `Fail` type. 112 | pub struct Backtrace { 113 | internal: InternalBacktrace 114 | } 115 | 116 | impl Backtrace { 117 | /// Constructs a new backtrace. This will only create a real backtrace 118 | /// if the crate is compiled in std mode and the `RUST_BACKTRACE` 119 | /// environmental variable is activated. 120 | pub fn new() -> Backtrace { 121 | Backtrace { internal: InternalBacktrace::new() } 122 | } 123 | 124 | pub(crate) fn none() -> Backtrace { 125 | Backtrace { internal: InternalBacktrace::none() } 126 | } 127 | 128 | pub(crate) fn is_none(&self) -> bool { 129 | self.internal.is_none() 130 | } 131 | 132 | /// Returns true if displaying this backtrace would be an empty string. 133 | pub fn is_empty(&self) -> bool { 134 | self.internal.is_none() 135 | } 136 | } 137 | 138 | impl Default for Backtrace { 139 | fn default() -> Backtrace { 140 | Backtrace::new() 141 | } 142 | } 143 | 144 | impl Debug for Backtrace { 145 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 146 | if let Some(bt) = self.internal.as_backtrace() { 147 | Debug::fmt(bt, f) 148 | } else { Ok(()) } 149 | } 150 | } 151 | 152 | impl Display for Backtrace { 153 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 154 | if let Some(bt) = self.internal.as_backtrace() { 155 | Debug::fmt(bt, f) 156 | } else { Ok(()) } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Cargo.lock.ci: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "backtrace" 3 | version = "0.3.9" 4 | source = "registry+https://github.com/rust-lang/crates.io-index" 5 | dependencies = [ 6 | "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", 7 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 8 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 9 | "rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", 10 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 11 | ] 12 | 13 | [[package]] 14 | name = "backtrace-sys" 15 | version = "0.1.24" 16 | source = "registry+https://github.com/rust-lang/crates.io-index" 17 | dependencies = [ 18 | "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", 19 | "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", 20 | ] 21 | 22 | [[package]] 23 | name = "cc" 24 | version = "1.0.28" 25 | source = "registry+https://github.com/rust-lang/crates.io-index" 26 | 27 | [[package]] 28 | name = "cfg-if" 29 | version = "0.1.6" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | 32 | [[package]] 33 | name = "failure" 34 | version = "0.1.6" 35 | dependencies = [ 36 | "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 37 | "failure_derive 0.1.6", 38 | ] 39 | 40 | [[package]] 41 | name = "failure_derive" 42 | version = "0.1.6" 43 | dependencies = [ 44 | "failure 0.1.6", 45 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 49 | ] 50 | 51 | [[package]] 52 | name = "libc" 53 | version = "0.2.43" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | 56 | [[package]] 57 | name = "proc-macro2" 58 | version = "0.4.24" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | dependencies = [ 61 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "quote" 66 | version = "0.6.10" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | dependencies = [ 69 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 70 | ] 71 | 72 | [[package]] 73 | name = "rustc-demangle" 74 | version = "0.1.11" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | 77 | [[package]] 78 | name = "syn" 79 | version = "0.15.23" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | dependencies = [ 82 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 83 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 84 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 85 | ] 86 | 87 | [[package]] 88 | name = "synstructure" 89 | version = "0.10.1" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | dependencies = [ 92 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 93 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 94 | "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", 95 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 96 | ] 97 | 98 | [[package]] 99 | name = "unicode-xid" 100 | version = "0.1.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | 103 | [[package]] 104 | name = "winapi" 105 | version = "0.3.6" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | dependencies = [ 108 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 109 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 110 | ] 111 | 112 | [[package]] 113 | name = "winapi-i686-pc-windows-gnu" 114 | version = "0.4.0" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | 117 | [[package]] 118 | name = "winapi-x86_64-pc-windows-gnu" 119 | version = "0.4.0" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | 122 | [metadata] 123 | "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" 124 | "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" 125 | "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" 126 | "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" 127 | "checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" 128 | "checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" 129 | "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" 130 | "checksum rustc-demangle 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "01b90379b8664dd83460d59bdc5dd1fd3172b8913788db483ed1325171eab2f7" 131 | "checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" 132 | "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" 133 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 134 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 135 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 136 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 137 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Debug, Display}; 2 | 3 | use Fail; 4 | 5 | without_std! { 6 | /// An error with context around it. 7 | /// 8 | /// The context is intended to be a human-readable, user-facing explanation for the 9 | /// error that has occurred. The underlying error is not assumed to be end-user-relevant 10 | /// information. 11 | /// 12 | /// The `Display` impl for `Context` only prints the human-readable context, while the 13 | /// `Debug` impl also prints the underlying error. 14 | pub struct Context { 15 | context: D, 16 | } 17 | 18 | impl Context { 19 | /// Creates a new context without an underlying error message. 20 | pub fn new(context: D) -> Context { 21 | Context { context } 22 | } 23 | 24 | /// Returns a reference to the context provided with this error. 25 | pub fn get_context(&self) -> &D { 26 | &self.context 27 | } 28 | 29 | /// Maps `Context` to `Context` by applying a function to the contained context. 30 | pub fn map(self, op: F) -> Context 31 | where F: FnOnce(D) -> T, 32 | T: Display + Send + Sync + 'static 33 | { 34 | Context { 35 | context: op(self.context), 36 | } 37 | } 38 | 39 | pub(crate) fn with_err(context: D, _: E) -> Context { 40 | Context { context } 41 | } 42 | } 43 | 44 | impl Fail for Context { } 45 | 46 | impl Debug for Context { 47 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 48 | write!(f, "{}", self.context) 49 | } 50 | } 51 | 52 | impl Display for Context { 53 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 54 | write!(f, "{}", self.context) 55 | } 56 | } 57 | 58 | #[test] 59 | fn test_map() { 60 | let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); 61 | assert_eq!(ctx.context, String::from("a string with some more stuff")); 62 | } 63 | } 64 | 65 | with_std! { 66 | use {Error, Backtrace}; 67 | 68 | /// An error with context around it. 69 | /// 70 | /// The context is intended to be a human-readable, user-facing explanation for the 71 | /// error that has occurred. The underlying error is not assumed to be end-user-relevant 72 | /// information. 73 | /// 74 | /// The `Display` impl for `Context` only prints the human-readable context, while the 75 | /// `Debug` impl also prints the underlying error. 76 | pub struct Context { 77 | context: D, 78 | failure: Either, 79 | } 80 | 81 | impl Context { 82 | /// Creates a new context without an underlying error message. 83 | pub fn new(context: D) -> Context { 84 | let failure = Either::This(Backtrace::new()); 85 | Context { context, failure } 86 | } 87 | 88 | /// Returns a reference to the context provided with this error. 89 | pub fn get_context(&self) -> &D { 90 | &self.context 91 | } 92 | 93 | /// Maps `Context` to `Context` by applying a function to the contained context. 94 | pub fn map(self, op: F) -> Context 95 | where F: FnOnce(D) -> T, 96 | T: Display + Send + Sync + 'static 97 | { 98 | Context { 99 | context: op(self.context), 100 | failure: self.failure, 101 | } 102 | } 103 | 104 | pub(crate) fn with_err>(context: D, error: E) -> Context { 105 | let failure = Either::That(error.into()); 106 | Context { context, failure } 107 | } 108 | } 109 | 110 | impl Fail for Context { 111 | fn name(&self) -> Option<&str> { 112 | self.failure.as_cause().and_then(|x| x.name()) 113 | } 114 | 115 | fn cause(&self) -> Option<&dyn Fail> { 116 | self.failure.as_cause() 117 | } 118 | 119 | fn backtrace(&self) -> Option<&Backtrace> { 120 | Some(self.failure.backtrace()) 121 | } 122 | } 123 | 124 | impl Debug for Context { 125 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 126 | write!(f, "{:?}\n\n{}", self.failure, self.context) 127 | } 128 | } 129 | 130 | impl Display for Context { 131 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 132 | write!(f, "{}", self.context) 133 | } 134 | } 135 | 136 | enum Either { 137 | This(A), 138 | That(B), 139 | } 140 | 141 | impl Either { 142 | fn backtrace(&self) -> &Backtrace { 143 | match *self { 144 | Either::This(ref backtrace) => backtrace, 145 | Either::That(ref error) => error.backtrace(), 146 | } 147 | } 148 | 149 | fn as_cause(&self) -> Option<&dyn Fail> { 150 | match *self { 151 | Either::This(_) => None, 152 | Either::That(ref error) => Some(error.as_fail()) 153 | } 154 | } 155 | } 156 | 157 | impl Debug for Either { 158 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 159 | match *self { 160 | Either::This(ref backtrace) => write!(f, "{:?}", backtrace), 161 | Either::That(ref error) => write!(f, "{:?}", error), 162 | } 163 | } 164 | } 165 | 166 | #[test] 167 | fn test_map() { 168 | let ctx = Context::new("a string").map(|s| format!("{} with some more stuff", s)); 169 | assert_eq!(ctx.context, String::from("a string with some more stuff")); 170 | } 171 | } 172 | 173 | impl From for Context 174 | where 175 | D: Display + Send + Sync + 'static, 176 | { 177 | fn from(display: D) -> Context { 178 | Context::new(display) 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/result_ext.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Display; 2 | 3 | use {Compat, Context, Fail}; 4 | 5 | /// Extension methods for `Result`. 6 | pub trait ResultExt { 7 | /// Wraps the error in `Compat` to make it compatible with older error 8 | /// handling APIs that expect `std::error::Error`. 9 | /// 10 | /// # Examples 11 | /// 12 | /// ``` 13 | /// # fn main() { 14 | /// # tests::run_test(); 15 | /// # } 16 | /// # 17 | /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } 18 | /// # 19 | /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { 20 | /// use std::error::Error; 21 | /// # use std::fmt; 22 | /// # 23 | /// # extern crate failure; 24 | /// # 25 | /// # use tests::failure::ResultExt; 26 | /// # 27 | /// # #[derive(Debug)] 28 | /// struct CustomError; 29 | /// 30 | /// impl Error for CustomError { 31 | /// fn description(&self) -> &str { 32 | /// "My custom error message" 33 | /// } 34 | /// 35 | /// fn cause(&self) -> Option<&Error> { 36 | /// None 37 | /// } 38 | /// } 39 | /// # 40 | /// # impl fmt::Display for CustomError { 41 | /// # fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 42 | /// # write!(f, "{}", self.description()) 43 | /// # } 44 | /// # } 45 | /// # 46 | /// # pub fn run_test() { 47 | /// 48 | /// let x = (|| -> Result<(), failure::Error> { 49 | /// Err(CustomError).compat()? 50 | /// })().with_context(|e| { 51 | /// format!("An error occured: {}", e) 52 | /// }).unwrap_err(); 53 | /// 54 | /// let x = format!("{}", x); 55 | /// 56 | /// assert_eq!(x, "An error occured: My custom error message"); 57 | /// # } 58 | /// 59 | /// # } 60 | /// ``` 61 | fn compat(self) -> Result>; 62 | 63 | /// Wraps the error type in a context type. 64 | /// 65 | /// # Examples 66 | /// 67 | /// ``` 68 | /// # #[cfg(all(feature = "std", feature = "derive"))] 69 | /// # #[macro_use] extern crate failure; 70 | /// # 71 | /// # #[cfg(all(feature = "std", feature = "derive"))] 72 | /// # #[macro_use] extern crate failure_derive; 73 | /// # 74 | /// # fn main() { 75 | /// # tests::run_test(); 76 | /// # } 77 | /// # 78 | /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } 79 | /// # 80 | /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { 81 | /// # 82 | /// # use failure::{self, ResultExt}; 83 | /// # 84 | /// #[derive(Fail, Debug)] 85 | /// #[fail(display = "")] 86 | /// struct CustomError; 87 | /// # 88 | /// # pub fn run_test() { 89 | /// 90 | /// let x = (|| -> Result<(), failure::Error> { 91 | /// Err(CustomError)? 92 | /// })().context(format!("An error occured")).unwrap_err(); 93 | /// 94 | /// let x = format!("{}", x); 95 | /// 96 | /// assert_eq!(x, "An error occured"); 97 | /// # } 98 | /// 99 | /// # } 100 | /// ``` 101 | fn context(self, context: D) -> Result> 102 | where 103 | D: Display + Send + Sync + 'static; 104 | 105 | /// Wraps the error type in a context type generated by looking at the 106 | /// error value. 107 | /// 108 | /// # Examples 109 | /// 110 | /// ``` 111 | /// # #[cfg(all(feature = "std", feature = "derive"))] 112 | /// # #[macro_use] extern crate failure; 113 | /// # 114 | /// # #[cfg(all(feature = "std", feature = "derive"))] 115 | /// # #[macro_use] extern crate failure_derive; 116 | /// # 117 | /// # fn main() { 118 | /// # tests::run_test(); 119 | /// # } 120 | /// # 121 | /// # #[cfg(not(all(feature = "std", feature = "derive")))] mod tests { pub fn run_test() { } } 122 | /// # 123 | /// # #[cfg(all(feature = "std", feature = "derive"))] mod tests { 124 | /// # 125 | /// # use failure::{self, ResultExt}; 126 | /// # 127 | /// #[derive(Fail, Debug)] 128 | /// #[fail(display = "My custom error message")] 129 | /// struct CustomError; 130 | /// # 131 | /// # pub fn run_test() { 132 | /// 133 | /// let x = (|| -> Result<(), failure::Error> { 134 | /// Err(CustomError)? 135 | /// })().with_context(|e| { 136 | /// format!("An error occured: {}", e) 137 | /// }).unwrap_err(); 138 | /// 139 | /// let x = format!("{}", x); 140 | /// 141 | /// assert_eq!(x, "An error occured: My custom error message"); 142 | /// # } 143 | /// 144 | /// # } 145 | /// ``` 146 | fn with_context(self, f: F) -> Result> 147 | where 148 | F: FnOnce(&E) -> D, 149 | D: Display + Send + Sync + 'static; 150 | } 151 | 152 | impl ResultExt for Result 153 | where 154 | E: Fail, 155 | { 156 | fn compat(self) -> Result> { 157 | self.map_err(|err| err.compat()) 158 | } 159 | 160 | fn context(self, context: D) -> Result> 161 | where 162 | D: Display + Send + Sync + 'static, 163 | { 164 | self.map_err(|failure| failure.context(context)) 165 | } 166 | 167 | fn with_context(self, f: F) -> Result> 168 | where 169 | F: FnOnce(&E) -> D, 170 | D: Display + Send + Sync + 'static, 171 | { 172 | self.map_err(|failure| { 173 | let context = f(&failure); 174 | failure.context(context) 175 | }) 176 | } 177 | } 178 | 179 | with_std! { 180 | use Error; 181 | 182 | impl ResultExt for Result { 183 | fn compat(self) -> Result> { 184 | self.map_err(|err| err.compat()) 185 | } 186 | 187 | fn context(self, context: D) -> Result> where 188 | D: Display + Send + Sync + 'static 189 | { 190 | self.map_err(|failure| failure.context(context)) 191 | } 192 | 193 | fn with_context(self, f: F) -> Result> where 194 | F: FnOnce(&Error) -> D, 195 | D: Display + Send + Sync + 'static 196 | { 197 | self.map_err(|failure| { 198 | let context = f(&failure); 199 | failure.context(context) 200 | }) 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /book/src/fail.md: -------------------------------------------------------------------------------- 1 | # The `Fail` trait 2 | 3 | The `Fail` trait is a replacement for [`std::error::Error`][stderror]. It has 4 | been designed to support a number of operations: 5 | 6 | - Because it is bound by both `Debug` and `Display`, any failure can be 7 | printed in two ways. 8 | - It has both a `backtrace` and a `cause` method, allowing users to get 9 | information about how the error occurred. 10 | - It supports wrapping failures in additional contextual information. 11 | - Because it is bound by `Send` and `Sync`, failures can be moved and shared 12 | between threads easily. 13 | - Because it is bound by `'static`, the abstract `Fail` trait object can be 14 | downcast into concrete types. 15 | 16 | Every new error type in your code should implement `Fail`, so it can be 17 | integrated into the entire system built around this trait. You can manually 18 | implement `Fail` yourself, or you can use the derive for `Fail` defined 19 | in a separate crate and documented [here][derive-docs]. 20 | 21 | Implementors of this trait are called 'failures'. 22 | 23 | ## Cause 24 | 25 | Often, an error type contains (or could contain) another underlying error type 26 | which represents the "cause" of this error - for example, if your custom error 27 | contains an `io::Error`, that is the cause of your error. 28 | 29 | The cause method on the `Fail` trait allows all errors to expose their underlying 30 | cause - if they have one - in a consistent way. Users can loop over the chain 31 | of causes, for example, getting the entire series of causes for an error: 32 | 33 | ```rust 34 | // Assume err is a type that implements `Fail` 35 | let mut fail: &Fail = err; 36 | 37 | while let Some(cause) = fail.cause() { 38 | println!("{}", cause); 39 | 40 | // Make `fail` the reference to the cause of the previous fail, making the 41 | // loop "dig deeper" into the cause chain. 42 | fail = cause; 43 | } 44 | ``` 45 | 46 | Because `&Fail` supports downcasting, you can also inspect causes in more 47 | detail if you are expecting a certain failure: 48 | 49 | ```rust 50 | while let Some(cause) = fail.cause() { 51 | 52 | if let Some(err) = cause.downcast_ref::() { 53 | // treat io::Error specially 54 | } else { 55 | // fallback case 56 | } 57 | 58 | fail = cause; 59 | } 60 | ``` 61 | 62 | For convenience an iterator is also provided: 63 | 64 | ```rust 65 | // Assume err is a type that implements `Fail` 66 | let mut fail: &Fail = err; 67 | 68 | for cause in fail.iter_causes() { 69 | println!("{}", cause); 70 | } 71 | ``` 72 | 73 | ## Backtraces 74 | 75 | Errors can also generate a backtrace when they are constructed, helping you 76 | determine the place the error was generated and the function chain that called into 77 | that. Like causes, this is entirely optional - the authors of each failure 78 | have to decide if generating a backtrace is appropriate in their use case. 79 | 80 | The backtrace method allows all errors to expose their backtrace if they have 81 | one. This enables a consistent method for getting the backtrace from an error: 82 | 83 | ```rust 84 | // We don't even know the type of the cause, but we can still get its 85 | // backtrace. 86 | if let Some(bt) = err.cause().and_then(|cause| cause.backtrace()) { 87 | println!("{}", bt) 88 | } 89 | ``` 90 | 91 | The `Backtrace` type exposed by `failure` is different from the `Backtrace` exposed 92 | by the [backtrace crate][backtrace-crate], in that it has several optimizations: 93 | 94 | - It has a `no_std` compatible form which will never be generated (because 95 | backtraces require heap allocation), and should be entirely compiled out. 96 | - It will not be generated unless the `RUST_BACKTRACE` environment variable has 97 | been set at runtime. 98 | - Symbol resolution is delayed until the backtrace is actually printed, because 99 | this is the most expensive part of generating a backtrace. 100 | 101 | ## Context 102 | 103 | Often, the libraries you are using will present error messages that don't 104 | provide very helpful information about what exactly has gone wrong. For 105 | example, if an `io::Error` says that an entity was "Not Found," that doesn't 106 | communicate much about what specific file was missing - if it even was a file 107 | (as opposed to a directory for example). 108 | 109 | You can inject additional context to be carried with this error value, 110 | providing semantic information about the nature of the error appropriate to the 111 | level of abstraction that the code you are writing operates at. The `context` 112 | method on `Fail` takes any displayable value (such as a string) to act as 113 | context for this error. 114 | 115 | Using the `ResultExt` trait, you can also get `context` as a convenient method on 116 | `Result` directly. For example, suppose that your code attempted to read from a 117 | Cargo.toml. You can wrap the `io::Error`s that occur with additional context 118 | about what operation has failed: 119 | 120 | ```rust 121 | use failure::ResultExt; 122 | 123 | let mut file = File::open(cargo_toml_path).context("Missing Cargo.toml")?; 124 | file.read_to_end(&buffer).context("Could not read Cargo.toml")?; 125 | ``` 126 | 127 | The `Context` object also has a constructor that does not take an underlying 128 | error, allowing you to create ad hoc Context errors alongside those created by 129 | applying the `context` method to an underlying error. 130 | 131 | ## Backwards compatibility 132 | 133 | We've taken several steps to make transitioning from `std::error` to `failure` as 134 | painless as possible. 135 | 136 | First, there is a blanket implementation of `Fail` for all types that implement 137 | `std::error::Error`, as long as they are `Send + Sync + 'static`. If you are 138 | dealing with a library that hasn't shifted to `Fail`, it is automatically 139 | compatible with `failure` already. 140 | 141 | Second, `Fail` contains a method called `compat`, which produces a type that 142 | implements `std::error::Error`. If you have a type that implements `Fail`, but 143 | not the older `Error` trait, you can call `compat` to get a type that does 144 | implement that trait (for example, if you need to return a `Box`). 145 | 146 | The biggest hole in our backwards compatibility story is that you cannot 147 | implement `std::error::Error` and also override the backtrace and cause methods 148 | on `Fail`. We intend to enable this with specialization when it becomes stable. 149 | 150 | [derive-docs]: ./derive-fail.html 151 | [stderror]: https://doc.rust-lang.org/std/error/trait.Error.html 152 | [backtrace-crate]: http://alexcrichton.com/backtrace-rs 153 | -------------------------------------------------------------------------------- /src/small_error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | use std::heap::{Heap, Alloc, Layout}; 3 | 4 | use core::mem; 5 | use core::ptr; 6 | 7 | use {Causes, Fail}; 8 | use backtrace::Backtrace; 9 | use context::Context; 10 | use compat::Compat; 11 | 12 | /// The `Error` type, which can contain any failure. 13 | /// 14 | /// Functions which accumulate many kinds of errors should return this type. 15 | /// All failures can be converted into it, so functions which catch those 16 | /// errors can be tried with `?` inside of a function that returns this kind 17 | /// of error. 18 | /// 19 | /// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` 20 | /// information, and can be downcast into the failure that underlies it for 21 | /// more detailed inspection. 22 | pub struct Error { 23 | inner: &'static mut Inner, 24 | } 25 | 26 | // Dynamically sized inner value 27 | struct Inner { 28 | backtrace: Backtrace, 29 | vtable: *const VTable, 30 | failure: FailData, 31 | } 32 | 33 | unsafe impl Send for Inner { } 34 | unsafe impl Sync for Inner { } 35 | 36 | extern { 37 | type VTable; 38 | type FailData; 39 | } 40 | 41 | struct InnerRaw { 42 | header: InnerHeader, 43 | failure: F, 44 | } 45 | 46 | struct InnerHeader { 47 | backtrace: Backtrace, 48 | vtable: *const VTable, 49 | } 50 | 51 | struct TraitObject { 52 | #[allow(dead_code)] 53 | data: *const FailData, 54 | vtable: *const VTable, 55 | } 56 | 57 | impl From for Error { 58 | fn from(failure: F) -> Error { 59 | let backtrace = if failure.backtrace().is_none() { 60 | Backtrace::new() 61 | } else { 62 | Backtrace::none() 63 | }; 64 | 65 | unsafe { 66 | let vtable = mem::transmute::<_, TraitObject>(&failure as &Fail).vtable; 67 | 68 | let ptr: *mut InnerRaw = match Heap.alloc(Layout::new::>()) { 69 | Ok(p) => p as *mut InnerRaw, 70 | Err(e) => Heap.oom(e), 71 | }; 72 | 73 | // N.B. must use `ptr::write`, not `=`, to avoid dropping the contents of `*ptr` 74 | ptr::write(ptr, InnerRaw { 75 | header: InnerHeader { 76 | backtrace, 77 | vtable, 78 | }, 79 | failure, 80 | }); 81 | 82 | let inner: &'static mut Inner = mem::transmute(ptr); 83 | 84 | Error { inner } 85 | } 86 | } 87 | } 88 | 89 | impl Inner { 90 | fn failure(&self) -> &Fail { 91 | unsafe { 92 | mem::transmute::(TraitObject { 93 | data: &self.failure as *const FailData, 94 | vtable: self.vtable, 95 | }) 96 | } 97 | } 98 | 99 | fn failure_mut(&mut self) -> &mut Fail { 100 | unsafe { 101 | mem::transmute::(TraitObject { 102 | data: &mut self.failure as *const FailData, 103 | vtable: self.vtable, 104 | }) 105 | } 106 | } 107 | } 108 | 109 | impl Error { 110 | /// Returns a reference to the underlying cause of this `Error`. Unlike the 111 | /// method on `Fail`, this does not return an `Option`. The `Error` type 112 | /// always has an underlying failure. 113 | pub fn cause(&self) -> &Fail { 114 | self.inner.failure() 115 | } 116 | 117 | /// Gets a reference to the `Backtrace` for this `Error`. 118 | /// 119 | /// If the failure this wrapped carried a backtrace, that backtrace will 120 | /// be returned. Otherwise, the backtrace will have been constructed at 121 | /// the point that failure was cast into the `Error` type. 122 | pub fn backtrace(&self) -> &Backtrace { 123 | self.inner.failure().backtrace().unwrap_or(&self.inner.backtrace) 124 | } 125 | 126 | /// Provides context for this `Error`. 127 | /// 128 | /// This can provide additional information about this error, appropriate 129 | /// to the semantics of the current layer. That is, if you have a 130 | /// lower-level error, such as an IO error, you can provide additional context 131 | /// about what that error means in the context of your function. This 132 | /// gives users of this function more information about what has gone 133 | /// wrong. 134 | /// 135 | /// This takes any type that implements `Display`, as well as 136 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 137 | /// or a string literal, or a failure, or some other custom context-carrying 138 | /// type. 139 | pub fn context(self, context: D) -> Context { 140 | Context::with_err(context, self) 141 | } 142 | 143 | /// Wraps `Error` in a compatibility type. 144 | /// 145 | /// This type implements the `Error` trait from `std::error`. If you need 146 | /// to pass failure's `Error` to an interface that takes any `Error`, you 147 | /// can use this method to get a compatible type. 148 | pub fn compat(self) -> Compat { 149 | Compat { error: self } 150 | } 151 | 152 | /// Attempts to downcast this `Error` to a particular `Fail` type. 153 | /// 154 | /// This downcasts by value, returning an owned `T` if the underlying 155 | /// failure is of the type `T`. For this reason it returns a `Result` - in 156 | /// the case that the underlying error is of a different type, the 157 | /// original `Error` is returned. 158 | pub fn downcast(self) -> Result { 159 | let ret: Option = self.downcast_ref().map(|fail| { 160 | unsafe { 161 | // drop the backtrace 162 | let _ = ptr::read(&self.inner.backtrace as *const Backtrace); 163 | // read out the fail type 164 | ptr::read(fail as *const T) 165 | } 166 | }); 167 | match ret { 168 | Some(ret) => { 169 | // forget self (backtrace is dropped, failure is moved 170 | mem::forget(self); 171 | Ok(ret) 172 | } 173 | _ => Err(self) 174 | } 175 | } 176 | 177 | /// Returns the "root cause" of this error - the last value in the 178 | /// cause chain which does not return an underlying `cause`. 179 | pub fn root_cause(&self) -> &Fail { 180 | ::find_root_cause(self.cause()) 181 | } 182 | 183 | /// Attempts to downcast this `Error` to a particular `Fail` type by 184 | /// reference. 185 | /// 186 | /// If the underlying error is not of type `T`, this will return `None`. 187 | pub fn downcast_ref(&self) -> Option<&T> { 188 | self.inner.failure().downcast_ref() 189 | } 190 | 191 | /// Attempts to downcast this `Error` to a particular `Fail` type by 192 | /// mutable reference. 193 | /// 194 | /// If the underlying error is not of type `T`, this will return `None`. 195 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 196 | self.inner.failure_mut().downcast_mut() 197 | } 198 | 199 | /// Returns a iterator over the causes of the `Error`, beginning with 200 | /// the failure returned by the `cause` method and ending with the failure 201 | /// returned by `root_cause`. 202 | pub fn causes(&self) -> Causes { 203 | Causes { fail: Some(self.cause()) } 204 | } 205 | } 206 | 207 | impl Display for Error { 208 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 209 | Display::fmt(self.inner.failure(), f) 210 | } 211 | } 212 | 213 | impl Debug for Error { 214 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 215 | if self.inner.backtrace.is_none() { 216 | Debug::fmt(self.inner.failure(), f) 217 | } else { 218 | write!(f, "{:?}\n\n{:?}", self.inner.failure(), self.inner.backtrace) 219 | } 220 | } 221 | } 222 | 223 | impl Drop for Error { 224 | fn drop(&mut self) { 225 | unsafe { 226 | let layout = { 227 | let header = Layout::new::(); 228 | header.extend(Layout::for_value(self.inner.failure())).unwrap().0 229 | }; 230 | Heap.dealloc(self.inner as *const _ as *const u8 as *mut u8, layout); 231 | } 232 | } 233 | } 234 | 235 | #[cfg(test)] 236 | mod test { 237 | use std::mem::size_of; 238 | use std::io; 239 | 240 | use super::Error; 241 | 242 | #[test] 243 | fn assert_error_is_just_data() { 244 | fn assert_just_data() { } 245 | assert_just_data::(); 246 | } 247 | 248 | #[test] 249 | fn assert_is_one_word() { 250 | assert_eq!(size_of::(), size_of::()); 251 | } 252 | 253 | #[test] 254 | fn methods_seem_to_work() { 255 | let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); 256 | let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); 257 | assert!(error.downcast_ref::().is_some()); 258 | let _: ::Backtrace = *error.backtrace(); 259 | assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); 260 | assert_eq!(format!("{}", io_error), format!("{}", error)); 261 | drop(error); 262 | assert!(true); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/error/mod.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::{self, Display, Debug}; 2 | 3 | use {Causes, Fail}; 4 | use backtrace::Backtrace; 5 | use context::Context; 6 | use compat::Compat; 7 | 8 | #[cfg(feature = "std")] 9 | use box_std::BoxStd; 10 | 11 | #[cfg_attr(feature = "small-error", path = "./error_impl_small.rs")] 12 | mod error_impl; 13 | use self::error_impl::ErrorImpl; 14 | 15 | #[cfg(feature = "std")] 16 | use std::error::Error as StdError; 17 | 18 | 19 | /// The `Error` type, which can contain any failure. 20 | /// 21 | /// Functions which accumulate many kinds of errors should return this type. 22 | /// All failures can be converted into it, so functions which catch those 23 | /// errors can be tried with `?` inside of a function that returns this kind 24 | /// of error. 25 | /// 26 | /// In addition to implementing `Debug` and `Display`, this type carries `Backtrace` 27 | /// information, and can be downcast into the failure that underlies it for 28 | /// more detailed inspection. 29 | pub struct Error { 30 | imp: ErrorImpl, 31 | } 32 | 33 | impl From for Error { 34 | fn from(failure: F) -> Error { 35 | Error { 36 | imp: ErrorImpl::from(failure) 37 | } 38 | } 39 | } 40 | 41 | impl Error { 42 | /// Creates an `Error` from `Box`. 43 | /// 44 | /// This method is useful for comparability with code, 45 | /// which does not use the `Fail` trait. 46 | /// 47 | /// # Example 48 | /// 49 | /// ``` 50 | /// use std::error::Error as StdError; 51 | /// use failure::Error; 52 | /// 53 | /// fn app_fn() -> Result { 54 | /// let x = library_fn().map_err(Error::from_boxed_compat)?; 55 | /// Ok(x * 2) 56 | /// } 57 | /// 58 | /// fn library_fn() -> Result> { 59 | /// Ok(92) 60 | /// } 61 | /// ``` 62 | #[cfg(feature = "std")] 63 | pub fn from_boxed_compat(err: Box) -> Error { 64 | Error::from(BoxStd(err)) 65 | } 66 | 67 | /// Return a reference to the underlying failure that this `Error` 68 | /// contains. 69 | pub fn as_fail(&self) -> &dyn Fail { 70 | self.imp.failure() 71 | } 72 | 73 | /// Returns the name of the underlying fail. 74 | pub fn name(&self) -> Option<&str> { 75 | self.as_fail().name() 76 | } 77 | 78 | /// Returns a reference to the underlying cause of this `Error`. Unlike the 79 | /// method on `Fail`, this does not return an `Option`. The `Error` type 80 | /// always has an underlying failure. 81 | /// 82 | /// This method has been deprecated in favor of the [Error::as_fail] method, 83 | /// which does the same thing. 84 | #[deprecated(since = "0.1.2", note = "please use 'as_fail()' method instead")] 85 | pub fn cause(&self) -> &dyn Fail { 86 | self.as_fail() 87 | } 88 | 89 | /// Gets a reference to the `Backtrace` for this `Error`. 90 | /// 91 | /// If the failure this wrapped carried a backtrace, that backtrace will 92 | /// be returned. Otherwise, the backtrace will have been constructed at 93 | /// the point that failure was cast into the `Error` type. 94 | pub fn backtrace(&self) -> &Backtrace { 95 | self.imp.failure().backtrace().unwrap_or(&self.imp.backtrace()) 96 | } 97 | 98 | /// Provides context for this `Error`. 99 | /// 100 | /// This can provide additional information about this error, appropriate 101 | /// to the semantics of the current layer. That is, if you have a 102 | /// lower-level error, such as an IO error, you can provide additional context 103 | /// about what that error means in the context of your function. This 104 | /// gives users of this function more information about what has gone 105 | /// wrong. 106 | /// 107 | /// This takes any type that implements `Display`, as well as 108 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 109 | /// or a string literal, or a failure, or some other custom context-carrying 110 | /// type. 111 | pub fn context(self, context: D) -> Context { 112 | Context::with_err(context, self) 113 | } 114 | 115 | /// Wraps `Error` in a compatibility type. 116 | /// 117 | /// This type implements the `Error` trait from `std::error`. If you need 118 | /// to pass failure's `Error` to an interface that takes any `Error`, you 119 | /// can use this method to get a compatible type. 120 | pub fn compat(self) -> Compat { 121 | Compat { error: self } 122 | } 123 | 124 | /// Attempts to downcast this `Error` to a particular `Fail` type. 125 | /// 126 | /// This downcasts by value, returning an owned `T` if the underlying 127 | /// failure is of the type `T`. For this reason it returns a `Result` - in 128 | /// the case that the underlying error is of a different type, the 129 | /// original `Error` is returned. 130 | pub fn downcast(self) -> Result { 131 | self.imp.downcast().map_err(|imp| Error { imp }) 132 | } 133 | 134 | /// Returns the "root cause" of this error - the last value in the 135 | /// cause chain which does not return an underlying `cause`. 136 | pub fn find_root_cause(&self) -> &dyn Fail { 137 | self.as_fail().find_root_cause() 138 | } 139 | 140 | /// Returns a iterator over the causes of this error with the cause 141 | /// of the fail as the first item and the `root_cause` as the final item. 142 | /// 143 | /// Use `iter_chain` to also include the fail of this error itself. 144 | pub fn iter_causes(&self) -> Causes { 145 | self.as_fail().iter_causes() 146 | } 147 | 148 | /// Returns a iterator over all fails up the chain from the current 149 | /// as the first item up to the `root_cause` as the final item. 150 | /// 151 | /// This means that the chain also includes the fail itself which 152 | /// means that it does *not* start with `cause`. To skip the outermost 153 | /// fail use `iter_causes` instead. 154 | pub fn iter_chain(&self) -> Causes { 155 | self.as_fail().iter_chain() 156 | } 157 | 158 | /// Attempts to downcast this `Error` to a particular `Fail` type by 159 | /// reference. 160 | /// 161 | /// If the underlying error is not of type `T`, this will return `None`. 162 | pub fn downcast_ref(&self) -> Option<&T> { 163 | self.imp.failure().downcast_ref() 164 | } 165 | 166 | /// Attempts to downcast this `Error` to a particular `Fail` type by 167 | /// mutable reference. 168 | /// 169 | /// If the underlying error is not of type `T`, this will return `None`. 170 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 171 | self.imp.failure_mut().downcast_mut() 172 | } 173 | 174 | /// Deprecated alias to `find_root_cause`. 175 | #[deprecated(since = "0.1.2", note = "please use the 'find_root_cause()' method instead")] 176 | pub fn root_cause(&self) -> &dyn Fail { 177 | ::find_root_cause(self.as_fail()) 178 | } 179 | 180 | /// Deprecated alias to `iter_causes`. 181 | #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] 182 | pub fn causes(&self) -> Causes { 183 | Causes { fail: Some(self.as_fail()) } 184 | } 185 | } 186 | 187 | impl Display for Error { 188 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 189 | Display::fmt(&self.imp.failure(), f) 190 | } 191 | } 192 | 193 | impl Debug for Error { 194 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 195 | let backtrace = self.imp.backtrace(); 196 | if backtrace.is_none() { 197 | Debug::fmt(&self.imp.failure(), f) 198 | } else { 199 | write!(f, "{:?}\n\n{:?}", &self.imp.failure(), backtrace) 200 | } 201 | } 202 | } 203 | 204 | impl AsRef for Error { 205 | fn as_ref(&self) -> &dyn Fail { 206 | self.as_fail() 207 | } 208 | } 209 | 210 | #[cfg(test)] 211 | mod test { 212 | use std::io; 213 | use super::Error; 214 | 215 | fn assert_just_data() { } 216 | 217 | #[test] 218 | fn assert_error_is_just_data() { 219 | assert_just_data::(); 220 | } 221 | 222 | #[test] 223 | fn methods_seem_to_work() { 224 | let io_error: io::Error = io::Error::new(io::ErrorKind::NotFound, "test"); 225 | let error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); 226 | assert!(error.downcast_ref::().is_some()); 227 | let _: ::Backtrace = *error.backtrace(); 228 | assert_eq!(format!("{:?}", io_error), format!("{:?}", error)); 229 | assert_eq!(format!("{}", io_error), format!("{}", error)); 230 | drop(error); 231 | assert!(true); 232 | } 233 | 234 | #[test] 235 | fn downcast_can_be_used() { 236 | let mut error: Error = io::Error::new(io::ErrorKind::NotFound, "test").into(); 237 | { 238 | let real_io_error_ref = error.downcast_ref::().unwrap(); 239 | assert_eq!(real_io_error_ref.to_string(), "test"); 240 | } 241 | { 242 | let real_io_error_mut = error.downcast_mut::().unwrap(); 243 | assert_eq!(real_io_error_mut.to_string(), "test"); 244 | } 245 | let real_io_error = error.downcast::().unwrap(); 246 | assert_eq!(real_io_error.to_string(), "test"); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /failure_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate proc_macro2; 2 | extern crate syn; 3 | 4 | #[macro_use] 5 | extern crate synstructure; 6 | #[macro_use] 7 | extern crate quote; 8 | 9 | use proc_macro2::{TokenStream, Span}; 10 | use syn::LitStr; 11 | use syn::spanned::Spanned; 12 | 13 | #[derive(Debug)] 14 | struct Error(TokenStream); 15 | 16 | impl Error { 17 | fn new(span: Span, message: &str) -> Error { 18 | Error(quote_spanned! { span => 19 | compile_error!(#message); 20 | }) 21 | } 22 | 23 | fn into_tokens(self) -> TokenStream { 24 | self.0 25 | } 26 | } 27 | 28 | impl From for Error { 29 | fn from(e: syn::Error) -> Error { 30 | Error(e.to_compile_error()) 31 | } 32 | } 33 | 34 | decl_derive!([Fail, attributes(fail, cause)] => fail_derive); 35 | 36 | fn fail_derive(s: synstructure::Structure) -> TokenStream { 37 | match fail_derive_impl(s) { 38 | Err(err) => err.into_tokens(), 39 | Ok(tokens) => tokens, 40 | } 41 | } 42 | 43 | fn fail_derive_impl(s: synstructure::Structure) -> Result { 44 | let make_dyn = if cfg!(has_dyn_trait) { 45 | quote! { &dyn } 46 | } else { 47 | quote! { & } 48 | }; 49 | 50 | let ty_name = LitStr::new(&s.ast().ident.to_string(), Span::call_site()); 51 | 52 | let cause_body = s.each_variant(|v| { 53 | if let Some(cause) = v.bindings().iter().find(is_cause) { 54 | quote!(return Some(::failure::AsFail::as_fail(#cause))) 55 | } else { 56 | quote!(return None) 57 | } 58 | }); 59 | 60 | let bt_body = s.each_variant(|v| { 61 | if let Some(bi) = v.bindings().iter().find(is_backtrace) { 62 | quote!(return Some(#bi)) 63 | } else { 64 | quote!(return None) 65 | } 66 | }); 67 | 68 | let fail = s.unbound_impl( 69 | quote!(::failure::Fail), 70 | quote! { 71 | fn name(&self) -> Option<&str> { 72 | Some(concat!(module_path!(), "::", #ty_name)) 73 | } 74 | 75 | #[allow(unreachable_code)] 76 | fn cause(&self) -> ::failure::_core::option::Option<#make_dyn(::failure::Fail)> { 77 | match *self { #cause_body } 78 | None 79 | } 80 | 81 | #[allow(unreachable_code)] 82 | fn backtrace(&self) -> ::failure::_core::option::Option<&::failure::Backtrace> { 83 | match *self { #bt_body } 84 | None 85 | } 86 | }, 87 | ); 88 | let display = display_body(&s)?.map(|display_body| { 89 | s.unbound_impl( 90 | quote!(::failure::_core::fmt::Display), 91 | quote! { 92 | #[allow(unreachable_code)] 93 | fn fmt(&self, f: &mut ::failure::_core::fmt::Formatter) -> ::failure::_core::fmt::Result { 94 | match *self { #display_body } 95 | write!(f, "An error has occurred.") 96 | } 97 | }, 98 | ) 99 | }); 100 | 101 | Ok(quote! { 102 | #fail 103 | #display 104 | }) 105 | } 106 | 107 | fn display_body(s: &synstructure::Structure) -> Result, Error> { 108 | let mut msgs = s.variants().iter().map(|v| find_error_msg(&v.ast().attrs)); 109 | if msgs.all(|msg| msg.map(|m| m.is_none()).unwrap_or(true)) { 110 | return Ok(None); 111 | } 112 | 113 | let mut tokens = TokenStream::new(); 114 | for v in s.variants() { 115 | let msg = 116 | find_error_msg(&v.ast().attrs)? 117 | .ok_or_else(|| Error::new( 118 | v.ast().ident.span(), 119 | "All variants must have display attribute." 120 | ))?; 121 | if msg.nested.is_empty() { 122 | return Err(Error::new( 123 | msg.span(), 124 | "Expected at least one argument to fail attribute" 125 | )); 126 | } 127 | 128 | let format_string = match msg.nested[0] { 129 | syn::NestedMeta::Meta(syn::Meta::NameValue(ref nv)) if nv.path.is_ident("display") => { 130 | nv.lit.clone() 131 | } 132 | _ => { 133 | return Err(Error::new( 134 | msg.span(), 135 | "Fail attribute must begin `display = \"\"` to control the Display message." 136 | )); 137 | } 138 | }; 139 | let args = msg.nested.iter().skip(1).map(|arg| match *arg { 140 | syn::NestedMeta::Lit(syn::Lit::Int(ref i)) => { 141 | let bi = &v.bindings()[i.base10_parse::()?]; 142 | Ok(quote!(#bi)) 143 | } 144 | syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => { 145 | let id_s = path.get_ident().map(syn::Ident::to_string).unwrap_or("".to_string()); 146 | if id_s.starts_with("_") { 147 | if let Ok(idx) = id_s[1..].parse::() { 148 | let bi = match v.bindings().get(idx) { 149 | Some(bi) => bi, 150 | None => { 151 | return Err(Error::new( 152 | arg.span(), 153 | &format!( 154 | "display attempted to access field `{}` in `{}::{}` which \ 155 | does not exist (there are {} field{})", 156 | idx, 157 | s.ast().ident, 158 | v.ast().ident, 159 | v.bindings().len(), 160 | if v.bindings().len() != 1 { "s" } else { "" } 161 | ) 162 | )); 163 | } 164 | }; 165 | return Ok(quote!(#bi)); 166 | } 167 | } 168 | for bi in v.bindings() { 169 | let id = bi.ast().ident.as_ref(); 170 | if id.is_some() && path.is_ident(id.unwrap()) { 171 | return Ok(quote!(#bi)); 172 | } 173 | } 174 | return Err(Error::new( 175 | arg.span(), 176 | &format!( 177 | "Couldn't find field `{:?}` in `{}::{}`", 178 | path, 179 | s.ast().ident, 180 | v.ast().ident 181 | ) 182 | )); 183 | } 184 | ref arg => { 185 | return Err(Error::new( 186 | arg.span(), 187 | "Invalid argument to fail attribute!" 188 | )); 189 | }, 190 | }); 191 | let args = args.collect::, _>>()?; 192 | 193 | let pat = v.pat(); 194 | tokens.extend(quote!(#pat => { return write!(f, #format_string #(, #args)*) })); 195 | } 196 | Ok(Some(tokens)) 197 | } 198 | 199 | fn find_error_msg(attrs: &[syn::Attribute]) -> Result, Error> { 200 | let mut error_msg = None; 201 | for attr in attrs { 202 | if let Ok(meta) = attr.parse_meta() { 203 | if meta.path().is_ident("fail") { 204 | if error_msg.is_some() { 205 | return Err(Error::new( 206 | meta.span(), 207 | "Cannot have two display attributes" 208 | )); 209 | } else { 210 | if let syn::Meta::List(list) = meta { 211 | error_msg = Some(list); 212 | } else { 213 | return Err(Error::new( 214 | meta.span(), 215 | "fail attribute must take a list in parentheses" 216 | )); 217 | } 218 | } 219 | } 220 | } 221 | } 222 | Ok(error_msg) 223 | } 224 | 225 | fn is_backtrace(bi: &&synstructure::BindingInfo) -> bool { 226 | match bi.ast().ty { 227 | syn::Type::Path(syn::TypePath { 228 | qself: None, 229 | path: syn::Path { 230 | segments: ref path, .. 231 | }, 232 | }) => path.last().map_or(false, |s| { 233 | s.ident == "Backtrace" && s.arguments.is_empty() 234 | }), 235 | _ => false, 236 | } 237 | } 238 | 239 | fn is_cause(bi: &&synstructure::BindingInfo) -> bool { 240 | let mut found_cause = false; 241 | for attr in &bi.ast().attrs { 242 | if let Ok(meta) = attr.parse_meta() { 243 | if meta.path().is_ident("cause") { 244 | if found_cause { 245 | panic!("Cannot have two `cause` attributes"); 246 | } 247 | found_cause = true; 248 | } 249 | if meta.path().is_ident("fail") { 250 | if let syn::Meta::List(ref list) = meta { 251 | if let Some(ref pair) = list.nested.first() { 252 | if let &&syn::NestedMeta::Meta(syn::Meta::Path(ref path)) = pair { 253 | if path.is_ident("cause") { 254 | if found_cause { 255 | panic!("Cannot have two `cause` attributes"); 256 | } 257 | found_cause = true; 258 | } 259 | } 260 | } 261 | } 262 | } 263 | } 264 | } 265 | found_cause 266 | } 267 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An experimental new error-handling library. Guide-style introduction 2 | //! is available [here](https://boats.gitlab.io/failure/). 3 | //! 4 | //! The primary items exported by this library are: 5 | //! 6 | //! - `Fail`: a new trait for custom error types in Rust. 7 | //! - `Error`: a wrapper around `Fail` types to make it easy to coalesce them 8 | //! at higher levels. 9 | //! 10 | //! As a general rule, library authors should create their own error types and 11 | //! implement `Fail` for them, whereas application authors should primarily 12 | //! deal with the `Error` type. There are exceptions to this rule, though, in 13 | //! both directions, and users should do whatever seems most appropriate to 14 | //! their situation. 15 | //! 16 | //! ## Backtraces 17 | //! 18 | //! Backtraces are disabled by default. To turn backtraces on, enable 19 | //! the `backtrace` Cargo feature and set the `RUST_BACKTRACE` environment 20 | //! variable to a non-zero value (this also enables backtraces for panics). 21 | //! Use the `RUST_FAILURE_BACKTRACE` variable to enable or disable backtraces 22 | //! for `failure` specifically. 23 | #![cfg_attr(not(feature = "std"), no_std)] 24 | #![deny(missing_docs)] 25 | #![deny(warnings)] 26 | #![cfg_attr(feature = "small-error", feature(extern_types, allocator_api))] 27 | 28 | macro_rules! with_std { ($($i:item)*) => ($(#[cfg(feature = "std")]$i)*) } 29 | macro_rules! without_std { ($($i:item)*) => ($(#[cfg(not(feature = "std"))]$i)*) } 30 | 31 | // Re-export libcore using an alias so that the macros can work without 32 | // requiring `extern crate core` downstream. 33 | #[doc(hidden)] 34 | pub extern crate core as _core; 35 | 36 | mod as_fail; 37 | mod backtrace; 38 | #[cfg(feature = "std")] 39 | mod box_std; 40 | mod compat; 41 | mod context; 42 | mod result_ext; 43 | 44 | use core::any::TypeId; 45 | use core::fmt::{Debug, Display}; 46 | 47 | pub use as_fail::AsFail; 48 | pub use backtrace::Backtrace; 49 | pub use compat::Compat; 50 | pub use context::Context; 51 | pub use result_ext::ResultExt; 52 | 53 | #[cfg(feature = "failure_derive")] 54 | #[allow(unused_imports)] 55 | #[macro_use] 56 | extern crate failure_derive; 57 | 58 | #[cfg(feature = "failure_derive")] 59 | #[doc(hidden)] 60 | pub use failure_derive::*; 61 | 62 | with_std! { 63 | extern crate core; 64 | 65 | mod sync_failure; 66 | pub use sync_failure::SyncFailure; 67 | 68 | mod error; 69 | 70 | use std::error::Error as StdError; 71 | 72 | pub use error::Error; 73 | 74 | /// A common result with an `Error`. 75 | pub type Fallible = Result; 76 | 77 | mod macros; 78 | mod error_message; 79 | pub use error_message::err_msg; 80 | } 81 | 82 | /// The `Fail` trait. 83 | /// 84 | /// Implementors of this trait are called 'failures'. 85 | /// 86 | /// All error types should implement `Fail`, which provides a baseline of 87 | /// functionality that they all share. 88 | /// 89 | /// `Fail` has no required methods, but it does require that your type 90 | /// implement several other traits: 91 | /// 92 | /// - `Display`: to print a user-friendly representation of the error. 93 | /// - `Debug`: to print a verbose, developer-focused representation of the 94 | /// error. 95 | /// - `Send + Sync`: Your error type is required to be safe to transfer to and 96 | /// reference from another thread 97 | /// 98 | /// Additionally, all failures must be `'static`. This enables downcasting. 99 | /// 100 | /// `Fail` provides several methods with default implementations. Two of these 101 | /// may be appropriate to override depending on the definition of your 102 | /// particular failure: the `cause` and `backtrace` methods. 103 | /// 104 | /// The `failure_derive` crate provides a way to derive the `Fail` trait for 105 | /// your type. Additionally, all types that already implement 106 | /// `std::error::Error`, and are also `Send`, `Sync`, and `'static`, implement 107 | /// `Fail` by a blanket impl. 108 | pub trait Fail: Display + Debug + Send + Sync + 'static { 109 | /// Returns the "name" of the error. 110 | /// 111 | /// This is typically the type name. Not all errors will implement 112 | /// this. This method is expected to be most useful in situations 113 | /// where errors need to be reported to external instrumentation systems 114 | /// such as crash reporters. 115 | fn name(&self) -> Option<&str> { 116 | None 117 | } 118 | 119 | /// Returns a reference to the underlying cause of this failure, if it 120 | /// is an error that wraps other errors. 121 | /// 122 | /// Returns `None` if this failure does not have another error as its 123 | /// underlying cause. By default, this returns `None`. 124 | /// 125 | /// This should **never** return a reference to `self`, but only return 126 | /// `Some` when it can return a **different** failure. Users may loop 127 | /// over the cause chain, and returning `self` would result in an infinite 128 | /// loop. 129 | fn cause(&self) -> Option<&dyn Fail> { 130 | None 131 | } 132 | 133 | /// Returns a reference to the `Backtrace` carried by this failure, if it 134 | /// carries one. 135 | /// 136 | /// Returns `None` if this failure does not carry a backtrace. By 137 | /// default, this returns `None`. 138 | fn backtrace(&self) -> Option<&Backtrace> { 139 | None 140 | } 141 | 142 | /// Provides context for this failure. 143 | /// 144 | /// This can provide additional information about this error, appropriate 145 | /// to the semantics of the current layer. That is, if you have a 146 | /// lower-level error, such as an IO error, you can provide additional context 147 | /// about what that error means in the context of your function. This 148 | /// gives users of this function more information about what has gone 149 | /// wrong. 150 | /// 151 | /// This takes any type that implements `Display`, as well as 152 | /// `Send`/`Sync`/`'static`. In practice, this means it can take a `String` 153 | /// or a string literal, or another failure, or some other custom context-carrying 154 | /// type. 155 | fn context(self, context: D) -> Context 156 | where 157 | D: Display + Send + Sync + 'static, 158 | Self: Sized, 159 | { 160 | Context::with_err(context, self) 161 | } 162 | 163 | /// Wraps this failure in a compatibility wrapper that implements 164 | /// `std::error::Error`. 165 | /// 166 | /// This allows failures to be compatible with older crates that 167 | /// expect types that implement the `Error` trait from `std::error`. 168 | fn compat(self) -> Compat 169 | where 170 | Self: Sized, 171 | { 172 | Compat { error: self } 173 | } 174 | 175 | #[doc(hidden)] 176 | #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] 177 | fn causes(&self) -> Causes 178 | where 179 | Self: Sized, 180 | { 181 | Causes { fail: Some(self) } 182 | } 183 | 184 | #[doc(hidden)] 185 | #[deprecated( 186 | since = "0.1.2", 187 | note = "please use the 'find_root_cause()' method instead" 188 | )] 189 | fn root_cause(&self) -> &dyn Fail 190 | where 191 | Self: Sized, 192 | { 193 | find_root_cause(self) 194 | } 195 | 196 | #[doc(hidden)] 197 | fn __private_get_type_id__(&self) -> TypeId { 198 | TypeId::of::() 199 | } 200 | } 201 | 202 | impl dyn Fail { 203 | /// Attempts to downcast this failure to a concrete type by reference. 204 | /// 205 | /// If the underlying error is not of type `T`, this will return `None`. 206 | pub fn downcast_ref(&self) -> Option<&T> { 207 | if self.__private_get_type_id__() == TypeId::of::() { 208 | unsafe { Some(&*(self as *const dyn Fail as *const T)) } 209 | } else { 210 | None 211 | } 212 | } 213 | 214 | /// Attempts to downcast this failure to a concrete type by mutable 215 | /// reference. 216 | /// 217 | /// If the underlying error is not of type `T`, this will return `None`. 218 | pub fn downcast_mut(&mut self) -> Option<&mut T> { 219 | if self.__private_get_type_id__() == TypeId::of::() { 220 | unsafe { Some(&mut *(self as *mut dyn Fail as *mut T)) } 221 | } else { 222 | None 223 | } 224 | } 225 | 226 | /// Returns the "root cause" of this `Fail` - the last value in the 227 | /// cause chain which does not return an underlying `cause`. 228 | /// 229 | /// If this type does not have a cause, `self` is returned, because 230 | /// it is its own root cause. 231 | /// 232 | /// This is equivalent to iterating over `iter_causes()` and taking 233 | /// the last item. 234 | pub fn find_root_cause(&self) -> &dyn Fail { 235 | find_root_cause(self) 236 | } 237 | 238 | /// Returns a iterator over the causes of this `Fail` with the cause 239 | /// of this fail as the first item and the `root_cause` as the final item. 240 | /// 241 | /// Use `iter_chain` to also include the fail itself. 242 | pub fn iter_causes(&self) -> Causes { 243 | Causes { fail: self.cause() } 244 | } 245 | 246 | /// Returns a iterator over all fails up the chain from the current 247 | /// as the first item up to the `root_cause` as the final item. 248 | /// 249 | /// This means that the chain also includes the fail itself which 250 | /// means that it does *not* start with `cause`. To skip the outermost 251 | /// fail use `iter_causes` instead. 252 | pub fn iter_chain(&self) -> Causes { 253 | Causes { fail: Some(self) } 254 | } 255 | 256 | /// Deprecated alias to `find_root_cause`. 257 | #[deprecated( 258 | since = "0.1.2", 259 | note = "please use the 'find_root_cause()' method instead" 260 | )] 261 | pub fn root_cause(&self) -> &dyn Fail { 262 | find_root_cause(self) 263 | } 264 | 265 | /// Deprecated alias to `iter_chain`. 266 | #[deprecated(since = "0.1.2", note = "please use the 'iter_chain()' method instead")] 267 | pub fn causes(&self) -> Causes { 268 | Causes { fail: Some(self) } 269 | } 270 | } 271 | 272 | #[cfg(feature = "std")] 273 | impl Fail for E {} 274 | 275 | #[cfg(feature = "std")] 276 | impl Fail for Box { 277 | fn cause(&self) -> Option<&dyn Fail> { 278 | (**self).cause() 279 | } 280 | 281 | fn backtrace(&self) -> Option<&Backtrace> { 282 | (**self).backtrace() 283 | } 284 | } 285 | 286 | /// A iterator over the causes of a `Fail` 287 | pub struct Causes<'f> { 288 | fail: Option<&'f dyn Fail>, 289 | } 290 | 291 | impl<'f> Iterator for Causes<'f> { 292 | type Item = &'f dyn Fail; 293 | fn next(&mut self) -> Option<&'f dyn Fail> { 294 | self.fail.map(|fail| { 295 | self.fail = fail.cause(); 296 | fail 297 | }) 298 | } 299 | } 300 | 301 | fn find_root_cause(mut fail: &dyn Fail) -> &dyn Fail { 302 | while let Some(cause) = fail.cause() { 303 | fail = cause; 304 | } 305 | 306 | fail 307 | } 308 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------