explicit_error_exit/lib.rs
1//! Built on top of [`explicit-error`](https://crates.io/crates/explicit-error), it provides idiomatic tools to manage errors that ends a process/program.
2//! Based on the [explicit-error](explicit_error) crate, its chore tenet is to favor explicitness by inlining the error output while remaining concise.
3//!
4//! The key features are:
5//! - Explicitly mark any error wrapped in a [Result] as a [Bug], a backtrace is captured.
6//! - Inline transformation of any errors wrapped in a [Result] into an [Error].
7//! - A derive macro [ExitError](derive::ExitError) to easily declare how enum or struct errors transform into an [Error].
8//! - Add context to errors to help debug.
9//!
10//! # A tour of explicit-error-bin
11//!
12//! The cornerstone of the library is the [Error] type. Use `Result<T, explicit_error_http::Error>`, or equivalently `explicit_error_bin::Result<T>`, as the return type of any faillible function returning errors that can end the program.
13//!
14//! ## Inline
15//!
16//! In the body of the function you can explicitly turn errors as exit errors using [ExitError] or marking them as [Bug].
17//! ```rust
18//! use explicit_error_exit::{prelude::*, ExitError, Result, Bug};
19//! use std::process::ExitCode;
20//! // Import the prelude to enable functions on std::result::Result
21//!
22//! fn business_logic() -> Result<()> {
23//! Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"))
24//! .bug()?;
25//!
26//! // Same behavior as bug() but the error is not captured as a source because it does not implement `[std::error::Error]`
27//! Err("error message").bug_no_source()?;
28//!
29//! if 1 > 2 {
30//! Err(Bug::new()
31//! .with_context("Usefull context to help debug."))?;
32//! }
33//!
34//! Err(42).map_err(|e|
35//! ExitError::new(
36//! "Something went wrong because ..",
37//! ExitCode::from(e)
38//! )
39//! )?;
40//!
41//! Ok(())
42//! }
43//!```
44//!
45//! ## Enum and struct
46//!
47//! Domain errors are often represented as enum or struct as they are raised in different places.
48//! To easily enable the conversion to [Error] use the [ExitError](derive::ExitError) derive and implement `From<&MyError> for ExitError`.
49//!
50//! ```rust
51//! use explicit_error_exit::{prelude::*, ExitError, Result, derive::ExitError};
52//! use std::process::ExitCode;
53//!
54//! #[derive(ExitError, Debug)]
55//! enum MyError {
56//! Foo,
57//! }
58//!
59//! impl From<&MyError> for ExitError {
60//! fn from(value: &MyError) -> Self {
61//! match value {
62//! MyError::Foo => ExitError::new(
63//! "Something went wrong because ..",
64//! ExitCode::from(42)
65//! ),
66//! }
67//! }
68//! }
69//!
70//! fn business_logic() -> Result<()> {
71//! Err(MyError::Foo)?;
72//!
73//! Ok(())
74//! }
75//! ```
76//!
77//! Note: The [ExitError](derive::ExitError) derive implements the conversion to [Error], the impl of [Display](std::fmt::Display) and [std::error::Error].
78//!
79//! # Pattern matching
80//!
81//! One of the drawbacks of using one and only one return type for different domain functions is that callers loose the ability to pattern match on the returned error.
82//! A solution is provided using [try_map_on_source](explicit_error::ResultError::try_map_on_source) on any `Result<T, Error>`, or equivalently `explicit_error_exit::Result<T>`.
83//!
84//! ```rust
85//! use explicit_error_exit::{prelude::*, ExitError, Result, derive::ExitError};
86//! use std::process::ExitCode;
87//!
88//! #[derive(ExitError, Debug)]
89//! enum MyError {
90//! Foo,
91//! Bar
92//! }
93//!
94//! # impl From<&MyError> for ExitError {
95//! # fn from(value: &MyError) -> Self {
96//! # ExitError::new(
97//! # "Something went wrong because ..",
98//! # ExitCode::from(42))
99//! # }
100//! # }
101//! fn business_logic() -> Result<()> {
102//! let err: Result<()> = Err(MyError::Foo)?;
103//!
104//! // Do the map if the source's type of the Error is MyError
105//! err.try_map_on_source(|e| {
106//! match e {
107//! MyError::Foo => ExitError::new(
108//! "Foo",
109//! ExitCode::SUCCESS),
110//! MyError::Bar => ExitError::new(
111//! "Bar",
112//! ExitCode::FAILURE),
113//! }
114//! })?;
115//!
116//! Ok(())
117//! }
118//! ```
119//!
120//! Note: under the hood [try_map_on_source](explicit_error::ResultError::try_map_on_source) perform some downcasting.
121mod domain;
122mod error;
123
124pub use domain::*;
125pub use error::*;
126
127pub type Error = explicit_error::Error<DomainError>;
128pub type Result<T> = std::result::Result<T, Error>;
129
130/// Re-import from [explicit_error] crate.
131pub use explicit_error::Bug;
132
133pub mod prelude {
134 pub use crate::ResultDomainWithContext;
135 pub use explicit_error::prelude::*;
136}
137
138pub mod derive {
139 pub use explicit_error_derive::ExitError;
140}