miette/eyreish/
context.rs

1use super::error::{ContextError, ErrorImpl};
2use super::{Report, WrapErr};
3use core::fmt::{self, Debug, Display, Write};
4
5use std::error::Error as StdError;
6
7use crate::{Diagnostic, LabeledSpan};
8
9mod ext {
10    use super::*;
11
12    pub trait Diag {
13        #[cfg_attr(track_caller, track_caller)]
14        fn ext_report<D>(self, msg: D) -> Report
15        where
16            D: Display + Send + Sync + 'static;
17    }
18
19    impl<E> Diag for E
20    where
21        E: Diagnostic + Send + Sync + 'static,
22    {
23        fn ext_report<D>(self, msg: D) -> Report
24        where
25            D: Display + Send + Sync + 'static,
26        {
27            Report::from_msg(msg, self)
28        }
29    }
30
31    impl Diag for Report {
32        fn ext_report<D>(self, msg: D) -> Report
33        where
34            D: Display + Send + Sync + 'static,
35        {
36            self.wrap_err(msg)
37        }
38    }
39}
40
41impl<T> WrapErr<T, std::convert::Infallible> for Option<T> {
42    fn wrap_err<D>(self, msg: D) -> Result<T, Report>
43    where
44        D: Display + Send + Sync + 'static,
45    {
46        match self {
47            Some(t) => Ok(t),
48            None => Err(Report::from(crate::eyreish::wrapper::DisplayError(msg))),
49        }
50    }
51
52    fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
53    where
54        D: Display + Send + Sync + 'static,
55        F: FnOnce() -> D,
56    {
57        match self {
58            Some(t) => Ok(t),
59            None => Err(Report::from(crate::eyreish::wrapper::DisplayError(msg()))),
60        }
61    }
62
63    fn context<D>(self, msg: D) -> Result<T, Report>
64    where
65        D: Display + Send + Sync + 'static,
66    {
67        self.wrap_err(msg)
68    }
69
70    fn with_context<D, F>(self, msg: F) -> Result<T, Report>
71    where
72        D: Display + Send + Sync + 'static,
73        F: FnOnce() -> D,
74    {
75        self.wrap_err_with(msg)
76    }
77}
78
79impl<T, E> WrapErr<T, E> for Result<T, E>
80where
81    E: ext::Diag + Send + Sync + 'static,
82{
83    fn wrap_err<D>(self, msg: D) -> Result<T, Report>
84    where
85        D: Display + Send + Sync + 'static,
86    {
87        match self {
88            Ok(t) => Ok(t),
89            Err(e) => Err(e.ext_report(msg)),
90        }
91    }
92
93    fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
94    where
95        D: Display + Send + Sync + 'static,
96        F: FnOnce() -> D,
97    {
98        match self {
99            Ok(t) => Ok(t),
100            Err(e) => Err(e.ext_report(msg())),
101        }
102    }
103
104    fn context<D>(self, msg: D) -> Result<T, Report>
105    where
106        D: Display + Send + Sync + 'static,
107    {
108        self.wrap_err(msg)
109    }
110
111    fn with_context<D, F>(self, msg: F) -> Result<T, Report>
112    where
113        D: Display + Send + Sync + 'static,
114        F: FnOnce() -> D,
115    {
116        self.wrap_err_with(msg)
117    }
118}
119
120impl<D, E> Debug for ContextError<D, E>
121where
122    D: Display,
123    E: Debug,
124{
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        f.debug_struct("Error")
127            .field("msg", &Quoted(&self.msg))
128            .field("source", &self.error)
129            .finish()
130    }
131}
132
133impl<D, E> Display for ContextError<D, E>
134where
135    D: Display,
136{
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        Display::fmt(&self.msg, f)
139    }
140}
141
142impl<D, E> StdError for ContextError<D, E>
143where
144    D: Display,
145    E: StdError + 'static,
146{
147    fn source(&self) -> Option<&(dyn StdError + 'static)> {
148        Some(&self.error)
149    }
150}
151
152impl<D> StdError for ContextError<D, Report>
153where
154    D: Display,
155{
156    fn source(&self) -> Option<&(dyn StdError + 'static)> {
157        unsafe { Some(ErrorImpl::error(self.error.inner.by_ref())) }
158    }
159}
160
161impl<D, E> Diagnostic for ContextError<D, E>
162where
163    D: Display,
164    E: Diagnostic + 'static,
165{
166    fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
167        self.error.code()
168    }
169
170    fn severity(&self) -> Option<crate::Severity> {
171        self.error.severity()
172    }
173
174    fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
175        self.error.help()
176    }
177
178    fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
179        self.error.url()
180    }
181
182    fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
183        self.error.labels()
184    }
185
186    fn source_code(&self) -> Option<&dyn crate::SourceCode> {
187        self.error.source_code()
188    }
189
190    fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
191        self.error.related()
192    }
193}
194
195impl<D> Diagnostic for ContextError<D, Report>
196where
197    D: Display,
198{
199    fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
200        unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).code() }
201    }
202
203    fn severity(&self) -> Option<crate::Severity> {
204        unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).severity() }
205    }
206
207    fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
208        unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).help() }
209    }
210
211    fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
212        unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).url() }
213    }
214
215    fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
216        unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).labels() }
217    }
218
219    fn source_code(&self) -> Option<&dyn crate::SourceCode> {
220        self.error.source_code()
221    }
222
223    fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
224        self.error.related()
225    }
226}
227
228struct Quoted<D>(D);
229
230impl<D> Debug for Quoted<D>
231where
232    D: Display,
233{
234    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
235        formatter.write_char('"')?;
236        Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
237        formatter.write_char('"')?;
238        Ok(())
239    }
240}
241
242impl Write for Quoted<&mut fmt::Formatter<'_>> {
243    fn write_str(&mut self, s: &str) -> fmt::Result {
244        Display::fmt(&s.escape_debug(), self.0)
245    }
246}
247
248pub(crate) mod private {
249    use super::*;
250
251    pub trait Sealed {}
252
253    impl<T, E> Sealed for Result<T, E> where E: ext::Diag {}
254    impl<T> Sealed for Option<T> {}
255}