1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! We provide support for:
//!
//! - User-friendly `io::Error` wrappers with pathnames,
//! - Formatting errors for display to the user (with the entire cause chain!),
//!   and
//! - Handy helper utilities like `quick_main!`.
//!
//! Basically, the goal is to make `failure` as ergonomic as possible, so that
//! everybody can stop re-inventing common bits of supporting code.
//!
//! ## User-friendly `io::Error` wrappers
//!
//! By default, Rust's I/O errors do not include any information about the
//! operation that failed. This means that you'll often see errors like:
//!
//! ```txt
//! No such file or directory (os error 2)
//! ```
//!
//! But it's much nicer for users if we print something like:
//!
//! ```txt
//! Error: error reading the file no-such-file.txt
//!   caused by: No such file or directory (os error 2)
//! ```
//!
//! To do this, we can use `io_read_context` and related functions:
//!
//! ```
//! # extern crate common_failures;
//! # fn main() {}
//! use common_failures::prelude::*;
//! use std::fs::File;
//! use std::path::Path;
//!
//! fn open_example(path: &Path) -> Result<File> {
//!     Ok(File::open(path).io_read_context(path)?)
//! }
//! ```
//!
//! ## Formatting errors for display to the user
//!
//! We also provide a support for formatting errors as strings, including
//! the entire chain of "causes" of the error:
//!
//! ```no_run
//! # extern crate common_failures;
//! # extern crate failure;
//! # fn main() {
//! use common_failures::prelude::*;
//!
//! # let err: Error = failure::err_msg("Example error");
//! format!("{}", err.display_causes_and_backtrace());
//! # }
//! ```
//!
//! ## The `quick_main!` macro
//!
//! ```
//! # fn main() {} // Dummy `main` to disable doctest wrapper.
//! #[macro_use]
//! extern crate common_failures;
//! #[macro_use]
//! extern crate failure;
//!
//! // This imports `Result`, `Error`, `failure::ResultExt`, and possibly
//! // other useful extension traits, to get you a minimal useful API.
//! use common_failures::prelude::*;
//!
//! // Uncomment this to define a `main` function that calls `run`, and prints
//! // any errors that it returns to standard error.
//! //quick_main!(run);
//!
//! fn run() -> Result<()> {
//!     if true {
//!         Ok(())
//!     } else {
//!         Err(format_err!("an error occurred"))
//!     }
//! }
//! ```

#![warn(missing_docs)]

// We would love to re-export the macros from this crate, but that's not
// feasible on standard Rust. If we _could_ export the macros, it would also
// be desirable to `pub extern crate` it, so that it's easier to keep in sync
// with this crate.
#[macro_use]
extern crate failure;

use std::result;

/// Import this module to get a useful error-handling API.
pub mod prelude {
    pub use {Error, Result};
    pub use io::{IoContextExt, IoContextErrorExt};
    pub use display::DisplayCausesAndBacktraceExt;
    pub use failure::ResultExt;
}

pub mod display;
pub mod io;

/// Re-export `failure::Error` for convenience.
pub type Error = failure::Error;

/// A short alias for `Result<T, failure::Error>`.
pub type Result<T> = result::Result<T, Error>;

/// Generate a `main` function which calls the specified function. If the
/// function returns `Result::Err(_)`, then `main` will print the error and exit
/// with a non-zero status code.
#[macro_export]
macro_rules! quick_main {
    ($wrapped:ident) => (
        fn main() {
            if let Err(err) = $wrapped() {
                use $crate::display::DisplayCausesAndBacktraceExt;
                use ::std::io::Write;
                let stderr = ::std::io::stderr();
                write!(
                    &mut stderr.lock(),
                    "{}",
                    err.display_causes_and_backtrace(),
                ).expect("Error occurred while trying to display error");
                ::std::process::exit(1);
            }
        }
    )
}