pretty_error_debug/lib.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! # pretty-error-debug
4//!
5//! [](https://github.com/Kijewski/pretty-error-debug/actions/workflows/ci.yml)
6//! [](https://crates.io/crates/pretty-error-debug)
7//! 
8//! [](/LICENSE-MIT "License: MIT OR Apache-2.0")
9//!
10//! Display a the chain of an error. Most useful as [`Result<(), E>`](std::result::Result) for your `fn main()`,
11//! and in conjunction with [`thiserror`](https://crates.io/crates/thiserror).
12//!
13//! This crate simply <del>plagiarized</del> <ins>extracted</ins> all the relevant formatting code from
14//! [`anyhow`](https://crates.io/crates/anyhow).
15//!
16//! ## Example message
17//!
18//! ```text
19//! Error: Got a 'middle' error
20//!
21//! Caused by:
22//! 1: A nested error occured
23//! 2: 'inner' failed
24//! 3: Caught an error: Not implemented, yet.
25//! ```
26//!
27//! ## With `thiserror`
28//!
29//! ```rust,ignore
30//! #[derive(pretty_error_debug::Debug, thiserror::Error)]
31//! pub enum MyError {
32//! #[error("Error variant 1 happened")]
33//! Variant1(#[from] Error1),
34//! #[error("Error variant 2 happened")]
35//! Variant2(#[from] Error2),
36//! }
37//!
38//! fn main() -> Result<(), MyError> {
39//! # /*
40//! ...
41//! # */ Ok(())
42//! }
43//! ```
44//!
45//! ## With `thiserror`, but without a new type
46//!
47//! ```rust,ignore
48//! #[derive(Debug, thiserror::Error)]
49//! pub enum MyError {
50//! #[error("Error variant 1 happened")]
51//! Variant1(#[from] Error1),
52//! #[error("Error variant 2 happened")]
53//! Variant2(#[from] Error2),
54//! }
55//!
56//! fn main() -> Result<(), pretty_error_debug::Wrapper<MyError>> {
57//! # /*
58//! ...
59//! # */ Ok(())
60//! }
61//! ```
62//!
63//! ## Without `thiserror`
64//!
65//! ```rust
66//! use std::error::Error;
67//! use std::fmt::{self, Write};
68//! #
69//! # #[derive(Debug)] pub struct Error1;
70//! # impl Error for Error1 {}
71//! # impl fmt::Display for Error1 {
72//! # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73//! # write!(f, "Error1")
74//! # }
75//! # }
76//! #
77//! # #[derive(Debug)] pub struct Error2;
78//! # impl Error for Error2 {}
79//! # impl fmt::Display for Error2 {
80//! # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81//! # write!(f, "Error2")
82//! # }
83//! # }
84//!
85//! #[derive(pretty_error_debug::Debug)]
86//! pub enum MyError {
87//! Variant1(Error1),
88//! Variant2(Error2),
89//! }
90//!
91//! impl fmt::Display for MyError {
92//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93//! match self {
94//! MyError::Variant1(_) => write!(f, "Error variant 1 happened"),
95//! MyError::Variant2(_) => write!(f, "Error variant 2 happened"),
96//! }
97//! }
98//! }
99//!
100//! impl Error for MyError {
101//! fn source(&self) -> Option<&(dyn 'static + Error)> {
102//! match self {
103//! MyError::Variant1(source) => Some(source),
104//! MyError::Variant2(source) => Some(source),
105//! }
106//! }
107//! }
108//!
109//! fn main() -> Result<(), MyError> {
110//! # /*
111//! ...
112//! # */ Ok(())
113//! }
114//! ```
115//!
116
117#![no_std]
118#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
119
120#[rustversion::before(1.81.0)]
121extern crate std;
122#[rustversion::since(1.81.0)]
123use core as std;
124
125mod implementation;
126#[cfg(test)]
127mod test;
128
129#[cfg(feature = "derive")]
130#[doc(hidden)]
131pub use core;
132use core::fmt;
133use std::error::Error;
134
135#[cfg(feature = "derive")]
136pub use pretty_error_debug_derive::PrettyDebug as Debug;
137
138pub use self::implementation::pretty_error_debug;
139
140/// Wrap an [`Error`] to display its error chain in debug messages ([`format!("{:?}")`][fmt::Debug]).
141///
142/// ## Example
143///
144/// ```rust
145/// use some_external_mod::{SomeError, some_test};
146///
147/// fn main() -> Result<(), pretty_error_debug::Wrapper<SomeError>> {
148/// some_test()?;
149/// Ok(())
150/// }
151///
152/// mod some_external_mod {
153/// #[derive(Debug)]
154/// pub struct SomeError;
155///
156/// impl std::error::Error for SomeError {}
157///
158/// impl std::fmt::Display for SomeError {
159/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160/// f.write_str("Something went wrong")
161/// }
162/// }
163///
164/// pub fn some_test() -> Result<(), SomeError> {
165/// # /*
166/// Err(SomeError)
167/// # */ Ok(())
168/// }
169/// }
170/// ```
171#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
172#[repr(transparent)]
173pub struct Wrapper<E: Error + ?Sized + 'static>(pub E);
174
175impl<E: Error + ?Sized + 'static> Wrapper<E> {
176 /// Return the wrapped argument.
177 #[inline]
178 pub const fn new(err: E) -> Self
179 where
180 E: Sized,
181 {
182 Self(err)
183 }
184}
185
186impl<E: Error + 'static> From<E> for Wrapper<E> {
187 #[inline]
188 fn from(value: E) -> Self {
189 Self(value)
190 }
191}
192
193impl<E: Error + 'static> Error for Wrapper<E> {
194 #[inline]
195 fn source(&self) -> Option<&(dyn Error + 'static)> {
196 Some(&self.0)
197 }
198}
199
200impl<E: Error + 'static> fmt::Display for Wrapper<E> {
201 #[inline]
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 fmt::Display::fmt(&self.0, f)
204 }
205}
206
207impl<E: Error + 'static> fmt::Debug for Wrapper<E> {
208 #[inline]
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 pretty_error_debug(&self.0, f)
211 }
212}
213
214/// Wrap a reference to an [`Error`] to display its error chain with [`format!("{}")`][fmt::Display].
215#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
216#[repr(transparent)]
217pub struct Display<'a, E: Error + ?Sized>(pub &'a E);
218
219impl<'a, E: Error + ?Sized> Display<'a, E> {
220 /// Return the wrapped reference.
221 #[inline]
222 pub const fn new(err: &'a E) -> Self {
223 Self(err)
224 }
225}
226
227impl<'a, E: Error> From<&'a E> for Display<'a, E> {
228 #[inline]
229 fn from(value: &'a E) -> Self {
230 Self(value)
231 }
232}
233
234impl<E: Error + ?Sized> fmt::Debug for Display<'_, E> {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 f.debug_tuple("Display").field(&self.0).finish()
237 }
238}
239
240impl<E: Error + ?Sized> fmt::Display for Display<'_, E> {
241 #[inline]
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 pretty_error_debug(&self.0, f)
244 }
245}