1 use super::error::{ContextError, ErrorImpl};
2 use super::{Report, WrapErr};
3 use core::fmt::{self, Debug, Display, Write};
4 
5 use std::error::Error as StdError;
6 
7 use crate::{Diagnostic, LabeledSpan};
8 
9 mod ext {
10     use super::*;
11 
12     pub trait Diag {
13         #[cfg_attr(track_caller, track_caller)]
ext_report<D>(self, msg: D) -> Report where D: Display + Send + Sync + 'static14         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     {
ext_report<D>(self, msg: D) -> Report where D: Display + Send + Sync + 'static,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 {
ext_report<D>(self, msg: D) -> Report where D: Display + Send + Sync + 'static,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 
41 impl<T, E> WrapErr<T, E> for Result<T, E>
42 where
43     E: ext::Diag + Send + Sync + 'static,
44 {
wrap_err<D>(self, msg: D) -> Result<T, Report> where D: Display + Send + Sync + 'static,45     fn wrap_err<D>(self, msg: D) -> Result<T, Report>
46     where
47         D: Display + Send + Sync + 'static,
48     {
49         match self {
50             Ok(t) => Ok(t),
51             Err(e) => Err(e.ext_report(msg)),
52         }
53     }
54 
wrap_err_with<D, F>(self, msg: F) -> Result<T, Report> where D: Display + Send + Sync + 'static, F: FnOnce() -> D,55     fn wrap_err_with<D, F>(self, msg: F) -> Result<T, Report>
56     where
57         D: Display + Send + Sync + 'static,
58         F: FnOnce() -> D,
59     {
60         match self {
61             Ok(t) => Ok(t),
62             Err(e) => Err(e.ext_report(msg())),
63         }
64     }
65 
context<D>(self, msg: D) -> Result<T, Report> where D: Display + Send + Sync + 'static,66     fn context<D>(self, msg: D) -> Result<T, Report>
67     where
68         D: Display + Send + Sync + 'static,
69     {
70         self.wrap_err(msg)
71     }
72 
with_context<D, F>(self, msg: F) -> Result<T, Report> where D: Display + Send + Sync + 'static, F: FnOnce() -> D,73     fn with_context<D, F>(self, msg: F) -> Result<T, Report>
74     where
75         D: Display + Send + Sync + 'static,
76         F: FnOnce() -> D,
77     {
78         self.wrap_err_with(msg)
79     }
80 }
81 
82 impl<D, E> Debug for ContextError<D, E>
83 where
84     D: Display,
85     E: Debug,
86 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result87     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88         f.debug_struct("Error")
89             .field("msg", &Quoted(&self.msg))
90             .field("source", &self.error)
91             .finish()
92     }
93 }
94 
95 impl<D, E> Display for ContextError<D, E>
96 where
97     D: Display,
98 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result99     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100         Display::fmt(&self.msg, f)
101     }
102 }
103 
104 impl<D, E> StdError for ContextError<D, E>
105 where
106     D: Display,
107     E: StdError + 'static,
108 {
source(&self) -> Option<&(dyn StdError + 'static)>109     fn source(&self) -> Option<&(dyn StdError + 'static)> {
110         Some(&self.error)
111     }
112 }
113 
114 impl<D> StdError for ContextError<D, Report>
115 where
116     D: Display,
117 {
source(&self) -> Option<&(dyn StdError + 'static)>118     fn source(&self) -> Option<&(dyn StdError + 'static)> {
119         unsafe { Some(ErrorImpl::error(self.error.inner.by_ref())) }
120     }
121 }
122 
123 impl<D, E> Diagnostic for ContextError<D, E>
124 where
125     D: Display,
126     E: Diagnostic + 'static,
127 {
code<'a>(&'a self) -> Option<Box<dyn Display + 'a>>128     fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
129         self.error.code()
130     }
131 
severity(&self) -> Option<crate::Severity>132     fn severity(&self) -> Option<crate::Severity> {
133         self.error.severity()
134     }
135 
help<'a>(&'a self) -> Option<Box<dyn Display + 'a>>136     fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
137         self.error.help()
138     }
139 
url<'a>(&'a self) -> Option<Box<dyn Display + 'a>>140     fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
141         self.error.url()
142     }
143 
labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>>144     fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
145         self.error.labels()
146     }
147 
source_code(&self) -> Option<&dyn crate::SourceCode>148     fn source_code(&self) -> Option<&dyn crate::SourceCode> {
149         self.error.source_code()
150     }
151 
related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>>152     fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
153         self.error.related()
154     }
155 }
156 
157 impl<D> Diagnostic for ContextError<D, Report>
158 where
159     D: Display,
160 {
code<'a>(&'a self) -> Option<Box<dyn Display + 'a>>161     fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
162         unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).code() }
163     }
164 
severity(&self) -> Option<crate::Severity>165     fn severity(&self) -> Option<crate::Severity> {
166         unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).severity() }
167     }
168 
help<'a>(&'a self) -> Option<Box<dyn Display + 'a>>169     fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
170         unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).help() }
171     }
172 
url<'a>(&'a self) -> Option<Box<dyn Display + 'a>>173     fn url<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
174         unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).url() }
175     }
176 
labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>>177     fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
178         unsafe { ErrorImpl::diagnostic(self.error.inner.by_ref()).labels() }
179     }
180 
source_code(&self) -> Option<&dyn crate::SourceCode>181     fn source_code(&self) -> Option<&dyn crate::SourceCode> {
182         self.error.source_code()
183     }
184 
related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>>185     fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
186         self.error.related()
187     }
188 }
189 
190 struct Quoted<D>(D);
191 
192 impl<D> Debug for Quoted<D>
193 where
194     D: Display,
195 {
fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result196     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
197         formatter.write_char('"')?;
198         Quoted(&mut *formatter).write_fmt(format_args!("{}", self.0))?;
199         formatter.write_char('"')?;
200         Ok(())
201     }
202 }
203 
204 impl Write for Quoted<&mut fmt::Formatter<'_>> {
write_str(&mut self, s: &str) -> fmt::Result205     fn write_str(&mut self, s: &str) -> fmt::Result {
206         Display::fmt(&s.escape_debug(), self.0)
207     }
208 }
209 
210 pub(crate) mod private {
211     use super::*;
212 
213     pub trait Sealed {}
214 
215     impl<T, E> Sealed for Result<T, E> where E: ext::Diag {}
216     impl<T> Sealed for Option<T> {}
217 }
218