xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/anyhow-1.0.82/src/kind.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Tagged dispatch mechanism for resolving the behavior of `anyhow!($expr)`.
2 //
3 // When anyhow! is given a single expr argument to turn into anyhow::Error, we
4 // want the resulting Error to pick up the input's implementation of source()
5 // and backtrace() if it has a std::error::Error impl, otherwise require nothing
6 // more than Display and Debug.
7 //
8 // Expressed in terms of specialization, we want something like:
9 //
10 //     trait AnyhowNew {
11 //         fn new(self) -> Error;
12 //     }
13 //
14 //     impl<T> AnyhowNew for T
15 //     where
16 //         T: Display + Debug + Send + Sync + 'static,
17 //     {
18 //         default fn new(self) -> Error {
19 //             /* no std error impl */
20 //         }
21 //     }
22 //
23 //     impl<T> AnyhowNew for T
24 //     where
25 //         T: std::error::Error + Send + Sync + 'static,
26 //     {
27 //         fn new(self) -> Error {
28 //             /* use std error's source() and backtrace() */
29 //         }
30 //     }
31 //
32 // Since specialization is not stable yet, instead we rely on autoref behavior
33 // of method resolution to perform tagged dispatch. Here we have two traits
34 // AdhocKind and TraitKind that both have an anyhow_kind() method. AdhocKind is
35 // implemented whether or not the caller's type has a std error impl, while
36 // TraitKind is implemented only when a std error impl does exist. The ambiguity
37 // is resolved by AdhocKind requiring an extra autoref so that it has lower
38 // precedence.
39 //
40 // The anyhow! macro will set up the call in this form:
41 //
42 //     #[allow(unused_imports)]
43 //     use $crate::__private::{AdhocKind, TraitKind};
44 //     let error = $msg;
45 //     (&error).anyhow_kind().new(error)
46 
47 use crate::Error;
48 use core::fmt::{Debug, Display};
49 
50 #[cfg(feature = "std")]
51 use crate::StdError;
52 #[cfg(feature = "std")]
53 use alloc::boxed::Box;
54 
55 pub struct Adhoc;
56 
57 #[doc(hidden)]
58 pub trait AdhocKind: Sized {
59     #[inline]
anyhow_kind(&self) -> Adhoc60     fn anyhow_kind(&self) -> Adhoc {
61         Adhoc
62     }
63 }
64 
65 impl<T> AdhocKind for &T where T: ?Sized + Display + Debug + Send + Sync + 'static {}
66 
67 impl Adhoc {
68     #[cold]
new<M>(self, message: M) -> Error where M: Display + Debug + Send + Sync + 'static,69     pub fn new<M>(self, message: M) -> Error
70     where
71         M: Display + Debug + Send + Sync + 'static,
72     {
73         Error::from_adhoc(message, backtrace!())
74     }
75 }
76 
77 pub struct Trait;
78 
79 #[doc(hidden)]
80 pub trait TraitKind: Sized {
81     #[inline]
anyhow_kind(&self) -> Trait82     fn anyhow_kind(&self) -> Trait {
83         Trait
84     }
85 }
86 
87 impl<E> TraitKind for E where E: Into<Error> {}
88 
89 impl Trait {
90     #[cold]
new<E>(self, error: E) -> Error where E: Into<Error>,91     pub fn new<E>(self, error: E) -> Error
92     where
93         E: Into<Error>,
94     {
95         error.into()
96     }
97 }
98 
99 #[cfg(feature = "std")]
100 pub struct Boxed;
101 
102 #[cfg(feature = "std")]
103 #[doc(hidden)]
104 pub trait BoxedKind: Sized {
105     #[inline]
anyhow_kind(&self) -> Boxed106     fn anyhow_kind(&self) -> Boxed {
107         Boxed
108     }
109 }
110 
111 #[cfg(feature = "std")]
112 impl BoxedKind for Box<dyn StdError + Send + Sync> {}
113 
114 #[cfg(feature = "std")]
115 impl Boxed {
116     #[cold]
new(self, error: Box<dyn StdError + Send + Sync>) -> Error117     pub fn new(self, error: Box<dyn StdError + Send + Sync>) -> Error {
118         let backtrace = backtrace_if_absent!(&*error);
119         Error::from_boxed(error, backtrace)
120     }
121 }
122