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("error message").bug()?;
24//!
25//! Err(std::io::Error::new(std::io::ErrorKind::Other, "oh no!"))
26//! .bug_with_source()?; // Same behavior as bug() but capture the wrapped std::error::Error as a source
27//!
28//! if 1 > 2 {
29//! Err(Bug::new()
30//! .with_context("Usefull context to help debug."))?;
31//! }
32//!
33//! Err(42).map_err(|e|
34//! ExitError::new(
35//! "Something went wrong because ..",
36//! ExitCode::from(e)
37//! )
38//! )?;
39//!
40//! Ok(())
41//! }
42//!```
43//!
44//! ## Enum and struct
45//!
46//! Domain errors are often represented as enum or struct as they are raised in different places.
47//! To easily enable the conversion to [Error] use the [ExitError](derive::ExitError) derive and implement `From<&MyError> for ExitError`.
48//!
49//! ```rust
50//! use explicit_error_exit::{prelude::*, ExitError, Result, derive::ExitError};
51//! use std::process::ExitCode;
52//!
53//! #[derive(ExitError, Debug)]
54//! enum MyError {
55//! Foo,
56//! }
57//!
58//! impl From<&MyError> for ExitError {
59//! fn from(value: &MyError) -> Self {
60//! match value {
61//! MyError::Foo => ExitError::new(
62//! "Something went wrong because ..",
63//! ExitCode::from(42)
64//! ),
65//! }
66//! }
67//! }
68//!
69//! fn business_logic() -> Result<()> {
70//! Err(MyError::Foo)?;
71//!
72//! Ok(())
73//! }
74//! ```
75//!
76//! Note: The [ExitError](derive::ExitError) derive implements the conversion to [Error], the impl of [Display](std::fmt::Display) and [std::error::Error].
77//!
78//! # Pattern matching
79//!
80//! 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.
81//! 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>`.
82//!
83//! ```rust
84//! use explicit_error_exit::{prelude::*, ExitError, Result, derive::ExitError};
85//! use std::process::ExitCode;
86//!
87//! #[derive(ExitError, Debug)]
88//! enum MyError {
89//! Foo,
90//! Bar
91//! }
92//!
93//! # impl From<&MyError> for ExitError {
94//! # fn from(value: &MyError) -> Self {
95//! # ExitError::new(
96//! # "Something went wrong because ..",
97//! # ExitCode::from(42))
98//! # }
99//! # }
100//! fn business_logic() -> Result<()> {
101//! let err: Result<()> = Err(MyError::Foo)?;
102//!
103//! // Do the map if the source's type of the Error is MyError
104//! err.try_map_on_source(|e| {
105//! match e {
106//! MyError::Foo => ExitError::new(
107//! "Foo",
108//! ExitCode::SUCCESS),
109//! MyError::Bar => ExitError::new(
110//! "Bar",
111//! ExitCode::FAILURE),
112//! }
113//! })?;
114//!
115//! Ok(())
116//! }
117//! ```
118//!
119//! Note: under the hood [try_map_on_source](explicit_error::ResultError::try_map_on_source) perform some downcasting.
120mod domain;
121mod error;
122
123pub use domain::*;
124pub use error::*;
125
126pub type Error = explicit_error::Error<DomainError>;
127pub type Result<T> = std::result::Result<T, Error>;
128
129/// Re-import from [explicit_error] crate.
130pub use explicit_error::Bug;
131
132pub mod prelude {
133 pub use crate::ResultDomainWithContext;
134 pub use explicit_error::prelude::*;
135}
136
137pub mod derive {
138 pub use explicit_error_derive::ExitError;
139}