miden_utils_diagnostics/
related.rs1use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec};
2use core::fmt;
3
4use miden_debug_types::{SourceFile, SourceSpan};
5
6use super::{Diagnostic, Label, LabeledSpan, Report, Severity, SourceCode};
7
8#[derive(Debug, Clone)]
18pub struct RelatedLabel {
19 pub severity: Severity,
21 pub message: Cow<'static, str>,
23 pub labels: Vec<Label>,
25 pub help: Option<Cow<'static, str>>,
27 pub file: Option<Arc<SourceFile>>,
29}
30
31impl fmt::Display for RelatedLabel {
32 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
33 f.write_str(self.message.as_ref())
34 }
35}
36
37#[cfg(feature = "std")]
38impl std::error::Error for RelatedLabel {
39 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40 None
41 }
42}
43
44#[cfg(not(feature = "std"))]
45impl miette::StdError for RelatedLabel {
46 fn source(&self) -> Option<&(dyn miette::StdError + 'static)> {
47 None
48 }
49}
50
51impl RelatedLabel {
52 pub fn new<S>(severity: Severity, message: S) -> Self
53 where
54 Cow<'static, str>: From<S>,
55 {
56 Self {
57 severity,
58 message: Cow::from(message),
59 help: None,
60 labels: vec![],
61 file: None,
62 }
63 }
64
65 pub fn error<S>(message: S) -> Self
66 where
67 Cow<'static, str>: From<S>,
68 {
69 Self::new(Severity::Error, message)
70 }
71
72 pub fn warning<S>(message: S) -> Self
73 where
74 Cow<'static, str>: From<S>,
75 {
76 Self::new(Severity::Warning, message)
77 }
78
79 pub fn advice<S>(message: S) -> Self
80 where
81 Cow<'static, str>: From<S>,
82 {
83 Self::new(Severity::Advice, message)
84 }
85
86 pub fn with_source_file(mut self, file: Option<Arc<SourceFile>>) -> Self {
87 self.file = file;
88 self
89 }
90
91 pub fn with_labeled_span<S>(self, span: SourceSpan, message: S) -> Self
92 where
93 Cow<'static, str>: From<S>,
94 {
95 let range = span.into_range();
96 self.with_label(Label::new((range.start as usize)..(range.end as usize), message))
97 }
98
99 pub fn with_label(mut self, label: Label) -> Self {
100 self.labels.push(label);
101 self
102 }
103
104 pub fn with_labels<I>(mut self, labels: I) -> Self
105 where
106 I: IntoIterator<Item = Label>,
107 {
108 self.labels.extend(labels);
109 self
110 }
111
112 pub fn with_help<S>(mut self, help: S) -> Self
113 where
114 Cow<'static, str>: From<S>,
115 {
116 self.help = Some(help.into());
117 self
118 }
119}
120
121impl Diagnostic for RelatedLabel {
122 fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
123 None
124 }
125 fn severity(&self) -> Option<Severity> {
126 Some(self.severity)
127 }
128 fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
129 self.help.as_deref().map(|help| Box::new(help) as Box<_>)
130 }
131 fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
132 None
133 }
134 fn source_code(&self) -> Option<&dyn SourceCode> {
135 self.file.as_ref().map(|f| f as &dyn SourceCode)
136 }
137 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
138 if self.labels.is_empty() {
139 None
140 } else {
141 Some(Box::new(self.labels.iter().cloned().map(|l| l.into())))
142 }
143 }
144 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
145 None
146 }
147 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
148 None
149 }
150}
151
152#[derive(Debug)]
159pub struct RelatedError(Report);
160
161impl RelatedError {
162 pub fn into_report(self) -> Report {
163 self.0
164 }
165
166 #[inline(always)]
167 pub fn as_diagnostic(&self) -> &dyn Diagnostic {
168 self.0.as_ref()
169 }
170}
171
172impl Diagnostic for RelatedError {
173 fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
174 self.as_diagnostic().code()
175 }
176 fn severity(&self) -> Option<Severity> {
177 self.as_diagnostic().severity()
178 }
179 fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
180 self.as_diagnostic().help()
181 }
182 fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
183 self.as_diagnostic().url()
184 }
185 fn source_code(&self) -> Option<&dyn SourceCode> {
186 self.as_diagnostic().source_code()
187 }
188 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
189 self.as_diagnostic().labels()
190 }
191 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
192 self.as_diagnostic().related()
193 }
194 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
195 self.as_diagnostic().diagnostic_source()
196 }
197}
198
199impl fmt::Display for RelatedError {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 fmt::Display::fmt(&self.0, f)
202 }
203}
204
205#[cfg(feature = "std")]
206impl std::error::Error for RelatedError {
207 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
208 AsRef::<dyn std::error::Error>::as_ref(&self.0).source()
209 }
210}
211
212#[cfg(not(feature = "std"))]
213impl miette::StdError for RelatedError {
214 fn source(&self) -> Option<&(dyn miette::StdError + 'static)> {
215 AsRef::<dyn miette::StdError>::as_ref(&self.0).source()
216 }
217}
218
219impl From<Report> for RelatedError {
220 fn from(report: Report) -> Self {
221 Self(report)
222 }
223}
224
225impl RelatedError {
226 pub const fn new(report: Report) -> Self {
227 Self(report)
228 }
229
230 pub fn wrap<E>(error: E) -> Self
231 where
232 E: Diagnostic + Send + Sync + 'static,
233 {
234 Self(Report::new_boxed(Box::new(error)))
235 }
236}