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}