Skip to main content

anyerr/
context.rs

1use core::{
2    convert::Infallible,
3    fmt::{self, Debug, Display, Write},
4};
5#[cfg(error_generic_member_access)]
6use std::error::Request;
7
8use crate::{Context, Error, StdError, error::ContextError};
9
10mod ext {
11    use super::*;
12
13    pub trait StdError {
14        fn ext_context<C>(self, context: C) -> Error
15        where
16            C: Display + Send + Sync + 'static;
17    }
18
19    #[cfg(feature = "std")]
20    impl<E> StdError for E
21    where
22        E: std::error::Error + Send + Sync + 'static,
23    {
24        fn ext_context<C>(self, context: C) -> Error
25        where
26            C: Display + Send + Sync + 'static,
27        {
28            let backtrace = backtrace_if_absent!(&self);
29            Error::from_context(context, self, backtrace)
30        }
31    }
32
33    impl StdError for Error {
34        fn ext_context<C>(self, context: C) -> Error
35        where
36            C: Display + Send + Sync + 'static,
37        {
38            self.context(context)
39        }
40    }
41}
42
43impl<T, E> Context<T, E> for Result<T, E>
44where
45    E: ext::StdError + Send + Sync + 'static,
46{
47    fn context<C>(self, context: C) -> Result<T, Error>
48    where
49        C: Display + Send + Sync + 'static,
50    {
51        // Not using map_err to save 2 useless frames off the captured backtrace
52        // in ext_context.
53        match self {
54            Ok(ok) => Ok(ok),
55            Err(error) => Err(error.ext_context(context)),
56        }
57    }
58
59    fn with_context<C, F>(self, context: F) -> Result<T, Error>
60    where
61        C: Display + Send + Sync + 'static,
62        F: FnOnce() -> C,
63    {
64        match self {
65            Ok(ok) => Ok(ok),
66            Err(error) => Err(error.ext_context(context())),
67        }
68    }
69}
70
71/// ```
72/// # type T = ();
73/// #
74/// use anyhow::{Context, Result};
75///
76/// fn maybe_get() -> Option<T> {
77///     # const IGNORE: &str = stringify! {
78///     ...
79///     # };
80///     # unimplemented!()
81/// }
82///
83/// fn demo() -> Result<()> {
84///     let t = maybe_get().context("there is no T")?;
85///     # const IGNORE: &str = stringify! {
86///     ...
87///     # };
88///     # unimplemented!()
89/// }
90/// ```
91impl<T> Context<T, Infallible> for Option<T> {
92    fn context<C>(self, context: C) -> Result<T, Error>
93    where
94        C: Display + Send + Sync + 'static,
95    {
96        // Not using ok_or_else to save 2 useless frames off the captured
97        // backtrace.
98        match self {
99            Some(ok) => Ok(ok),
100            None => Err(Error::from_display(context, backtrace!())),
101        }
102    }
103
104    fn with_context<C, F>(self, context: F) -> Result<T, Error>
105    where
106        C: Display + Send + Sync + 'static,
107        F: FnOnce() -> C,
108    {
109        match self {
110            Some(ok) => Ok(ok),
111            None => Err(Error::from_display(context(), backtrace!())),
112        }
113    }
114}
115
116impl<C, E> Debug for ContextError<C, E>
117where
118    C: Display,
119    E: Debug,
120{
121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122        f.debug_struct("Error")
123            .field("context", &Quoted(&self.context))
124            .field("source", &self.error)
125            .finish()
126    }
127}
128
129impl<C, E> Display for ContextError<C, E>
130where
131    C: Display,
132{
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        Display::fmt(&self.context, f)
135    }
136}
137
138impl<C, E> StdError for ContextError<C, E>
139where
140    C: Display,
141    E: StdError + 'static,
142{
143    fn source(&self) -> Option<&(dyn StdError + 'static)> {
144        Some(&self.error)
145    }
146
147    #[cfg(error_generic_member_access)]
148    fn provide<'a>(&'a self, request: &mut Request<'a>) {
149        StdError::provide(&self.error, request);
150    }
151}
152
153impl<C> StdError for ContextError<C, Error>
154where
155    C: Display,
156{
157    fn source(&self) -> Option<&(dyn StdError + 'static)> {
158        Some(unsafe { crate::ErrorImpl::error(self.error.inner.by_ref()) })
159    }
160
161    #[cfg(error_generic_member_access)]
162    fn provide<'a>(&'a self, request: &mut Request<'a>) {
163        Error::provide(&self.error, request);
164    }
165}
166
167struct Quoted<C>(C);
168
169impl<C> Debug for Quoted<C>
170where
171    C: Display,
172{
173    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
174        formatter.write_char('"')?;
175        Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
176        formatter.write_char('"')?;
177        Ok(())
178    }
179}
180
181impl Write for Quoted<&mut fmt::Formatter<'_>> {
182    fn write_str(&mut self, s: &str) -> fmt::Result {
183        Display::fmt(&s.escape_debug(), self.0)
184    }
185}
186
187pub(crate) mod private {
188    use super::*;
189
190    pub trait Sealed {}
191
192    impl<T, E> Sealed for Result<T, E> where E: ext::StdError {}
193    impl<T> Sealed for Option<T> {}
194}