anyerr/lib.rs
1//! A trait object based error type for easy idiomatic error handling in Rust
2//! applications.
3//!
4//! It provides [`Error`], a trait object based error type, and the [`Result`]
5//! alias.
6//!
7//! # Details
8//!
9//! - Use `Result<T, anyerr::Error>`, or equivalently `anyerr::Result<T>`, as
10//! the return type of any fallible function.
11//!
12//! Within the function, use `?` to easily propagate any error that implements
13//! the [`std::error::Error`] trait.
14//!
15//! ```
16//! # pub trait Deserialize {}
17//! #
18//! # mod serde_json {
19//! # use super::Deserialize;
20//! # use std::io;
21//! #
22//! # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
23//! # unimplemented!()
24//! # }
25//! # }
26//! #
27//! # struct ClusterMap;
28//! #
29//! # impl Deserialize for ClusterMap {}
30//! #
31//! use anyerr::Result;
32//!
33//! fn get_cluster_info() -> Result<ClusterMap> {
34//! let config = std::fs::read_to_string("cluster.json")?;
35//! let map: ClusterMap = serde_json::from_str(&config)?;
36//! Ok(map)
37//! }
38//! #
39//! # fn main() {}
40//! ```
41//!
42//! - Attach context to help the person troubleshooting the error understand
43//! where things went wrong. A low-level error like "No such file or
44//! directory" can be annoying to debug without more context about what higher
45//! level step the application was in the middle of.
46//!
47//! ```
48//! # struct It;
49//! #
50//! # impl It {
51//! # fn detach(&self) -> Result<()> {
52//! # unimplemented!()
53//! # }
54//! # }
55//! #
56//! use anyerr::{Context, Result};
57//!
58//! fn main() -> Result<()> {
59//! # return Ok(());
60//! #
61//! # const _: &str = stringify! {
62//! ...
63//! # };
64//! #
65//! # let it = It;
66//! # let path = "./path/to/instrs.json";
67//! #
68//! it.detach().context("Failed to detach the important thing")?;
69//!
70//! let content = std::fs::read(path)
71//! .with_context(|| format!("Failed to read instrs from {}", path))?;
72//! #
73//! # const _: &str = stringify! {
74//! ...
75//! # };
76//! #
77//! # Ok(())
78//! }
79//! ```
80//!
81//! ```console
82//! Error: Failed to read instrs from ./path/to/instrs.json
83//!
84//! Caused by:
85//! No such file or directory (os error 2)
86//! ```
87//!
88//! - Downcasting is supported and can be by value, by shared reference, or by
89//! mutable reference as needed.
90//!
91//! ```
92//! # use anyerr::anyhow;
93//! # use std::fmt::{self, Display};
94//! # use std::task::Poll;
95//! #
96//! # #[derive(Debug)]
97//! # enum DataStoreError {
98//! # Censored(()),
99//! # }
100//! #
101//! # impl Display for DataStoreError {
102//! # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
103//! # unimplemented!()
104//! # }
105//! # }
106//! #
107//! # impl std::error::Error for DataStoreError {}
108//! #
109//! # const REDACTED_CONTENT: () = ();
110//! #
111//! # let error = anyhow!("...");
112//! # let root_cause = &error;
113//! #
114//! # let ret =
115//! // If the error was caused by redaction, then return a
116//! // tombstone instead of the content.
117//! match root_cause.downcast_ref::<DataStoreError>() {
118//! Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
119//! None => Err(error),
120//! }
121//! # ;
122//! ```
123//!
124//! - A backtrace is captured and printed with the error if the underlying
125//! error type does not already provide its own. In order to see backtraces,
126//! they must be enabled through the environment variables described in
127//! [`std::backtrace`]:
128//!
129//! - If you want panics and errors to both have backtraces, set
130//! `RUST_BACKTRACE=1`;
131//! - If you want only errors to have backtraces, set `RUST_LIB_BACKTRACE=1`;
132//! - If you want only panics to have backtraces, set `RUST_BACKTRACE=1` and
133//! `RUST_LIB_BACKTRACE=0`.
134//!
135//! [`std::backtrace`]: https://doc.rust-lang.org/std/backtrace/index.html#environment-variables
136//!
137//! - This crate works with any error type that has an impl of
138//! `std::error::Error`, including ones defined in your crate. It does not
139//! bundle a `derive(Error)` macro, but you can write the impls yourself or
140//! use the standalone `thiserror` crate in this workspace.
141//!
142//! ```
143//! use thiserror::Error;
144//!
145//! #[derive(Error, Debug)]
146//! pub enum FormatError {
147//! #[error("Invalid header (expected {expected:?}, got {found:?})")]
148//! InvalidHeader {
149//! expected: String,
150//! found: String,
151//! },
152//! #[error("Missing attribute: {0}")]
153//! MissingAttribute(String),
154//! }
155//! ```
156//!
157//! - One-off error messages can be constructed using the `anyhow!` macro, which
158//! supports string interpolation and produces an `anyerr::Error`.
159//!
160//! ```
161//! # use anyerr::{anyhow, Result};
162//! #
163//! # fn demo() -> Result<()> {
164//! # let missing = "...";
165//! return Err(anyhow!("Missing attribute: {}", missing));
166//! # Ok(())
167//! # }
168//! ```
169//!
170//! A `bail!` macro is provided as a shorthand for the same early return.
171//!
172//! ```
173//! # use anyerr::{bail, Result};
174//! #
175//! # fn demo() -> Result<()> {
176//! # let missing = "...";
177//! bail!("Missing attribute: {}", missing);
178//! # Ok(())
179//! # }
180//! ```
181//!
182//! # No-std support
183//!
184//! In no_std mode, almost all of the same API is available and works the same
185//! way. Disable the default enabled `std` feature to use it in no_std mode. A
186//! global allocator is required.
187//!
188//! Since the `?`-based error conversions would normally rely on the
189//! `std::error::Error` trait which is only available through std, no_std mode
190//! will require an explicit `.map_err(Error::msg)` when working with a
191//! non-anyerr error type inside a function that returns anyerr's error type.
192
193#![cfg_attr(error_generic_member_access, feature(error_generic_member_access))]
194#![cfg_attr(docsrs, feature(doc_cfg))]
195#![no_std]
196#![deny(dead_code, unused_imports, unused_mut)]
197#![deny(unsafe_op_in_unsafe_fn)]
198#![allow(
199 clippy::doc_markdown,
200 clippy::enum_glob_use,
201 clippy::explicit_auto_deref,
202 clippy::extra_unused_type_parameters,
203 clippy::incompatible_msrv,
204 clippy::let_underscore_untyped,
205 clippy::missing_errors_doc,
206 clippy::missing_panics_doc,
207 clippy::module_name_repetitions,
208 clippy::must_use_candidate,
209 clippy::needless_doctest_main,
210 clippy::new_ret_no_self,
211 clippy::redundant_else,
212 clippy::return_self_not_must_use,
213 clippy::struct_field_names,
214 clippy::unused_self,
215 clippy::used_underscore_binding,
216 clippy::wildcard_imports,
217 clippy::wrong_self_convention
218)]
219
220#[cfg(all(anyhow_nightly_testing, feature = "std", not(error_generic_member_access)))]
221compile_error!("Build script probe failed to compile.");
222
223extern crate alloc;
224
225#[cfg(feature = "std")]
226extern crate std;
227
228#[macro_use]
229mod backtrace;
230mod chain;
231mod context;
232mod ensure;
233mod error;
234mod fmt;
235mod kind;
236mod macros;
237mod ptr;
238mod wrapper;
239
240#[cfg(not(feature = "std"))]
241use core::fmt::Debug;
242use core::fmt::Display;
243#[cfg(feature = "std")]
244use std::error::Error as StdError;
245
246use crate::{error::ErrorImpl, ptr::Own};
247
248#[cfg(not(feature = "std"))]
249trait StdError: Debug + Display {
250 fn source(&self) -> Option<&(dyn StdError + 'static)> {
251 None
252 }
253}
254
255#[doc(no_inline)]
256pub use anyhow as format_err;
257
258/// The `Error` type, a wrapper around a dynamic error type.
259///
260/// `Error` works a lot like `Box<dyn std::error::Error>`, but with these
261/// differences:
262///
263/// - `Error` requires that the error is `Send`, `Sync`, and `'static`.
264/// - `Error` guarantees that a backtrace is available, even if the underlying
265/// error type does not provide one.
266/// - `Error` is represented as a narrow pointer — exactly one word in
267/// size instead of two.
268///
269/// <br>
270///
271/// # Display representations
272///
273/// When you print an error object using "{}" or to_string(), only the outermost
274/// underlying error or context is printed, not any of the lower level causes.
275/// This is exactly as if you had called the Display impl of the error from
276/// which you constructed your anyerr::Error.
277///
278/// ```console
279/// Failed to read instrs from ./path/to/instrs.json
280/// ```
281///
282/// To print causes as well using anyhow's default formatting of causes, use the
283/// alternate selector "{:#}".
284///
285/// ```console
286/// Failed to read instrs from ./path/to/instrs.json: No such file or directory (os error 2)
287/// ```
288///
289/// The Debug format "{:?}" includes your backtrace if one was captured. Note
290/// that this is the representation you get by default if you return an error
291/// from `fn main` instead of printing it explicitly yourself.
292///
293/// ```console
294/// Error: Failed to read instrs from ./path/to/instrs.json
295///
296/// Caused by:
297/// No such file or directory (os error 2)
298/// ```
299///
300/// and if there is a backtrace available:
301///
302/// ```console
303/// Error: Failed to read instrs from ./path/to/instrs.json
304///
305/// Caused by:
306/// No such file or directory (os error 2)
307///
308/// Stack backtrace:
309/// 0: <E as anyerr::context::ext::StdError>::ext_context
310/// at /git/anyhow/src/backtrace.rs:26
311/// 1: core::result::Result<T,E>::map_err
312/// at /git/rustc/src/libcore/result.rs:596
313/// 2: anyerr::context::<impl anyerr::Context<T,E> for core::result::Result<T,E>>::with_context
314/// at /git/anyhow/src/context.rs:58
315/// 3: testing::main
316/// at src/main.rs:5
317/// 4: std::rt::lang_start
318/// at /git/rustc/src/libstd/rt.rs:61
319/// 5: main
320/// 6: __libc_start_main
321/// 7: _start
322/// ```
323///
324/// To see a conventional struct-style Debug representation, use "{:#?}".
325///
326/// ```console
327/// Error {
328/// context: "Failed to read instrs from ./path/to/instrs.json",
329/// source: Os {
330/// code: 2,
331/// kind: NotFound,
332/// message: "No such file or directory",
333/// },
334/// }
335/// ```
336///
337/// If none of the built-in representations are appropriate and you would prefer
338/// to render the error and its cause chain yourself, it can be done something
339/// like this:
340///
341/// ```
342/// use anyerr::{Context, Result};
343///
344/// fn main() {
345/// if let Err(err) = try_main() {
346/// eprintln!("ERROR: {}", err);
347/// err.chain().skip(1).for_each(|cause| eprintln!("because: {}", cause));
348/// std::process::exit(1);
349/// }
350/// }
351///
352/// fn try_main() -> Result<()> {
353/// # const IGNORE: &str = stringify! {
354/// ...
355/// # };
356/// # Ok(())
357/// }
358/// ```
359#[repr(transparent)]
360pub struct Error {
361 inner: Own<ErrorImpl>,
362}
363
364/// Iterator of a chain of source errors.
365///
366/// This type is the iterator returned by [`Error::chain`].
367///
368/// # Example
369///
370/// ```
371/// use anyerr::Error;
372/// use std::io;
373///
374/// pub fn underlying_io_error_kind(error: &Error) -> Option<io::ErrorKind> {
375/// for cause in error.chain() {
376/// if let Some(io_error) = cause.downcast_ref::<io::Error>() {
377/// return Some(io_error.kind());
378/// }
379/// }
380/// None
381/// }
382/// ```
383#[cfg(feature = "std")]
384#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
385#[derive(Clone)]
386pub struct Chain<'a> {
387 state: crate::chain::ChainState<'a>,
388}
389
390/// `Result<T, Error>`
391///
392/// This is a reasonable return type to use throughout your application but also
393/// for `fn main`; if you do, failures will be printed along with any
394/// [context][Context] and a backtrace if one was captured.
395///
396/// `anyerr::Result` may be used with one *or* two type parameters.
397///
398/// ```rust
399/// use anyerr::Result;
400///
401/// # const IGNORE: &str = stringify! {
402/// fn demo1() -> Result<T> {...}
403/// // ^ equivalent to std::result::Result<T, anyerr::Error>
404///
405/// fn demo2() -> Result<T, OtherError> {...}
406/// // ^ equivalent to std::result::Result<T, OtherError>
407/// # };
408/// ```
409///
410/// # Example
411///
412/// ```
413/// # pub trait Deserialize {}
414/// #
415/// # mod serde_json {
416/// # use super::Deserialize;
417/// # use std::io;
418/// #
419/// # pub fn from_str<T: Deserialize>(json: &str) -> io::Result<T> {
420/// # unimplemented!()
421/// # }
422/// # }
423/// #
424/// # #[derive(Debug)]
425/// # struct ClusterMap;
426/// #
427/// # impl Deserialize for ClusterMap {}
428/// #
429/// use anyerr::Result;
430///
431/// fn main() -> Result<()> {
432/// # return Ok(());
433/// let config = std::fs::read_to_string("cluster.json")?;
434/// let map: ClusterMap = serde_json::from_str(&config)?;
435/// println!("cluster info: {:#?}", map);
436/// Ok(())
437/// }
438/// ```
439pub type Result<T, E = Error> = core::result::Result<T, E>;
440
441/// Provides the `context` method for `Result`.
442///
443/// This trait is sealed and cannot be implemented for types outside of
444/// `anyhow`.
445///
446/// <br>
447///
448/// # Example
449///
450/// ```
451/// use anyerr::{Context, Result};
452/// use std::fs;
453/// use std::path::PathBuf;
454///
455/// pub struct ImportantThing {
456/// path: PathBuf,
457/// }
458///
459/// impl ImportantThing {
460/// # const IGNORE: &'static str = stringify! {
461/// pub fn detach(&mut self) -> Result<()> {...}
462/// # };
463/// # fn detach(&mut self) -> Result<()> {
464/// # unimplemented!()
465/// # }
466/// }
467///
468/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
469/// it.detach().context("Failed to detach the important thing")?;
470///
471/// let path = &it.path;
472/// let content = fs::read(path)
473/// .with_context(|| format!("Failed to read instrs from {}", path.display()))?;
474///
475/// Ok(content)
476/// }
477/// ```
478///
479/// When printed, the outermost context would be printed first and the lower
480/// level underlying causes would be enumerated below.
481///
482/// ```console
483/// Error: Failed to read instrs from ./path/to/instrs.json
484///
485/// Caused by:
486/// No such file or directory (os error 2)
487/// ```
488///
489/// Refer to the [Display representations] documentation for other forms in
490/// which this context chain can be rendered.
491///
492/// [Display representations]: Error#display-representations
493///
494/// <br>
495///
496/// # Effect on downcasting
497///
498/// After attaching context of type `C` onto an error of type `E`, the resulting
499/// `anyerr::Error` may be downcast to `C` **or** to `E`.
500///
501/// That is, in codebases that rely on downcasting, Anyhow's context supports
502/// both of the following use cases:
503///
504/// - **Attaching context whose type is insignificant onto errors whose type
505/// is used in downcasts.**
506///
507/// In other error libraries whose context is not designed this way, it can
508/// be risky to introduce context to existing code because new context might
509/// break existing working downcasts. In Anyhow, any downcast that worked
510/// before adding context will continue to work after you add a context, so
511/// you should freely add human-readable context to errors wherever it would
512/// be helpful.
513///
514/// ```
515/// # use anyerr::bail;
516/// # use thiserror::Error;
517/// #
518/// # #[derive(Error, Debug)]
519/// # #[error("???")]
520/// # struct SuspiciousError;
521/// #
522/// # fn helper() -> Result<()> {
523/// # bail!(SuspiciousError);
524/// # }
525/// #
526/// use anyerr::{Context, Result};
527///
528/// fn do_it() -> Result<()> {
529/// helper().context("Failed to complete the work")?;
530/// # const IGNORE: &str = stringify! {
531/// ...
532/// # };
533/// # unreachable!()
534/// }
535///
536/// fn main() {
537/// let err = do_it().unwrap_err();
538/// if let Some(e) = err.downcast_ref::<SuspiciousError>() {
539/// // If helper() returned SuspiciousError, this downcast will
540/// // correctly succeed even with the context in between.
541/// # return;
542/// }
543/// # panic!("expected downcast to succeed");
544/// }
545/// ```
546///
547/// - **Attaching context whose type is used in downcasts onto errors whose
548/// type is insignificant.**
549///
550/// Some codebases prefer to use machine-readable context to categorize
551/// lower level errors in a way that will be actionable to higher levels of
552/// the application.
553///
554/// ```
555/// # use anyerr::bail;
556/// # use thiserror::Error;
557/// #
558/// # #[derive(Error, Debug)]
559/// # #[error("???")]
560/// # struct HelperFailed;
561/// #
562/// # fn helper() -> Result<()> {
563/// # bail!("no such file or directory");
564/// # }
565/// #
566/// use anyerr::{Context, Result};
567///
568/// fn do_it() -> Result<()> {
569/// helper().context(HelperFailed)?;
570/// # const IGNORE: &str = stringify! {
571/// ...
572/// # };
573/// # unreachable!()
574/// }
575///
576/// fn main() {
577/// let err = do_it().unwrap_err();
578/// if let Some(e) = err.downcast_ref::<HelperFailed>() {
579/// // If helper failed, this downcast will succeed because
580/// // HelperFailed is the context that has been attached to
581/// // that error.
582/// # return;
583/// }
584/// # panic!("expected downcast to succeed");
585/// }
586/// ```
587pub trait Context<T, E>: context::private::Sealed {
588 /// Wrap the error value with additional context.
589 fn context<C>(self, context: C) -> Result<T, Error>
590 where
591 C: Display + Send + Sync + 'static;
592
593 /// Wrap the error value with additional context that is evaluated lazily
594 /// only once an error does occur.
595 fn with_context<C, F>(self, f: F) -> Result<T, Error>
596 where
597 C: Display + Send + Sync + 'static,
598 F: FnOnce() -> C;
599}
600
601/// Equivalent to Ok::<_, anyerr::Error>(value).
602///
603/// This simplifies creation of an anyerr::Result in places where type inference
604/// cannot deduce the `E` type of the result — without needing to write
605/// `Ok::<_, anyerr::Error>(value)`.
606///
607/// One might think that `anyerr::Result::Ok(value)` would work in such cases
608/// but it does not.
609///
610/// ```console
611/// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
612/// --> src/main.rs:11:13
613/// |
614/// 11 | let _ = anyerr::Result::Ok(1);
615/// | - ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result`
616/// | |
617/// | consider giving this pattern the explicit type `std::result::Result<i32, E>`, where the type parameter `E` is specified
618/// ```
619#[allow(non_snake_case)]
620pub fn Ok<T>(t: T) -> Result<T> {
621 Result::Ok(t)
622}
623
624// Not public API. Referenced by macro-generated code.
625#[doc(hidden)]
626pub mod __private {
627 use alloc::fmt;
628 #[doc(hidden)]
629 pub use alloc::format;
630 use core::fmt::Arguments;
631 #[doc(hidden)]
632 pub use core::result::Result::Err;
633 #[doc(hidden)]
634 pub use core::{concat, format_args, stringify};
635
636 use self::not::Bool;
637 use crate::Error;
638 #[doc(hidden)]
639 pub use crate::ensure::{BothDebug, NotBothDebug};
640
641 #[doc(hidden)]
642 pub mod kind {
643 #[cfg(feature = "std")]
644 #[doc(hidden)]
645 pub use crate::kind::BoxedKind;
646 #[doc(hidden)]
647 pub use crate::kind::{AdhocKind, TraitKind};
648 }
649
650 #[doc(hidden)]
651 #[inline]
652 #[cold]
653 pub fn format_err(args: Arguments) -> Error {
654 let fmt_arguments_as_str = args.as_str();
655
656 if let Some(message) = fmt_arguments_as_str {
657 // anyhow!("literal"), can downcast to &'static str
658 Error::msg(message)
659 } else {
660 // anyhow!("interpolate {var}"), can downcast to String
661 Error::msg(fmt::format(args))
662 }
663 }
664
665 #[doc(hidden)]
666 #[inline]
667 #[cold]
668 #[must_use]
669 pub fn must_use(error: Error) -> Error {
670 error
671 }
672
673 #[doc(hidden)]
674 #[inline]
675 pub fn not(cond: impl Bool) -> bool {
676 cond.not()
677 }
678
679 mod not {
680 #[doc(hidden)]
681 pub trait Bool {
682 fn not(self) -> bool;
683 }
684
685 impl Bool for bool {
686 #[inline]
687 fn not(self) -> bool {
688 !self
689 }
690 }
691
692 impl Bool for &bool {
693 #[inline]
694 fn not(self) -> bool {
695 !*self
696 }
697 }
698 }
699}