n0_error/lib.rs
1//! A library for ergonomic errors with call-site location data
2//!
3//! This crate provides a [`StackError`] trait and [`stack_error`] proc macro to
4//! ergonomically work with enum or struct errors.
5//!
6//! * All errors that use the macro will implement the [`StackError`] trait,
7//! which exposes call-site metadata indicating where the error occurred. Its
8//! [`source`](StackError::source) method returns an [`ErrorRef`], which is an
9//! enum over either a reference to a [`std::error::Error`] or another
10//! [`StackError`]. This allows retrieving error locations for the full error
11//! chain, as long as all errors are stack errors.
12//!
13//! * The proc macro can add a `meta` field to structs or enum variants. This
14//! field is the source for the call-site location accessed through the
15//! `StackError` trait. There is a simple declarative macro [`e!`](e) that
16//! provides an ergonomic way to construct errors with a `meta` field without
17//! having to spell it out everywhere.
18//!
19//! * This crate also provides an [`AnyError`] type, which is similar to
20//! [`anyhow`](https://docs.rs/anyhow/latest/anyhow/). If constructed from an
21//! error that implements `StackError`, the call-site location is preserved.
22//! The `AnyError` type is generally recommended for applications or tests,
23//! whereas libraries should use concrete errors with the macro.
24//!
25//! * There are result extensions to convert `StackError`s or `std::error::Error`s
26//! to `AnyError` while providing additional context.
27//!
28//! * While all errors using the derive macro from this crate have a `From`
29//! implementation for `AnyError`, regular std errors do not. Unfortunately, a
30//! blanket `From` implementation for all std errors would prevent a
31//! specialized implementation for stack errors, causing loss of location
32//! metadata upon conversion to `AnyError`. Therefore, you need to use the
33//! [`std_context`](StdResultExt::std_context) or
34//! [`anyerr`](StdResultExt::anyerr) methods to convert results with std errors
35//! to [`AnyError`]. You should not use these methods on stack errors; instead,
36//! use [`context`](StackResultExt::context) or simply forward with `?`.
37//!
38//! The call-site metadata in the `meta` field is collected only if the
39//! environment variable `RUST_BACKTRACE=1` or `RUST_ERROR_LOCATION=1` is set.
40//! Otherwise, it is not collected, as doing so has a small performance overhead.
41//!
42//! Both [`AnyError`] and all errors that use the
43//! [derive macro](derive@StackError) feature the following outputs:
44//!
45//! * Display impl (`{error}`) prints only the message of the outermost error
46//! `failed to process input`
47//! * Alternate display impl (`{error:#}`) prints the message for each error in the chain, in a single line
48//! `failed to process input: invalid input: wanted 23 but got 13`
49//! * Debug impl (`{error:?}`) prints the message and each source, on separate lines.
50//! ```text
51//! failed to process input
52//! Caused by:
53//! invalid input
54//! wanted 23 but got 13
55//! ```
56//!
57//! If `RUST_BACKTRACE` or `RUST_ERROR_LOCATION` is set, this will also print the call site of each error.
58//! ```text
59//! failed to process input (examples/basic.rs:61:17)
60//! Caused by:
61//! invalid input (examples/basic.rs:36:5)
62//! wanted 23 but got 13 (examples/basic.rs:48:13)
63//! ```
64//! * Alternate debug impl `{error:#?}`: An output similar to how the `#[derive(Debug)]` output looks.
65//!
66//! ### Feature flags
67//!
68//! * `anyhow` (off by default): Enables `From<anyhow::Error> for AnyError`
69//!
70//! ## Example
71//!
72//! ```rust
73#![doc = include_str!("../examples/basic.rs")]
74//! ```
75#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
76
77pub use n0_error_macros::{StackError, stack_error};
78
79mod any;
80mod error;
81mod ext;
82mod macros;
83mod meta;
84#[cfg(test)]
85mod tests;
86
87pub use self::{any::*, error::*, ext::*, macros::*, meta::*};
88
89/// `Result` type alias where the error type defaults to [`AnyError`].
90pub type Result<T = (), E = AnyError> = std::result::Result<T, E>;
91
92/// Returns a result with the error type set to [`AnyError`].
93///
94/// Equivalent to `Ok::<_, AnyError>(value)`.
95#[allow(non_snake_case)]
96pub fn Ok<T>(value: T) -> Result<T, AnyError> {
97 std::result::Result::Ok(value)
98}
99
100/// Ensures we can use the macros within this crate as well.
101extern crate self as n0_error;
102
103/// Ensure the code in the README compiles
104#[cfg(doctest)]
105#[doc = include_str!("../README.md")]
106mod readme_doctest {}