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)]
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 #[allow(unused)]
73 pub fn warning<S>(message: S) -> Self
74 where
75 Cow<'static, str>: From<S>,
76 {
77 Self::new(Severity::Warning, message)
78 }
79
80 #[allow(unused)]
81 pub fn advice<S>(message: S) -> Self
82 where
83 Cow<'static, str>: From<S>,
84 {
85 Self::new(Severity::Advice, message)
86 }
87
88 pub fn with_source_file(mut self, file: Option<Arc<SourceFile>>) -> Self {
89 self.file = file;
90 self
91 }
92
93 pub fn with_labeled_span<S>(self, span: SourceSpan, message: S) -> Self
94 where
95 Cow<'static, str>: From<S>,
96 {
97 let range = span.into_range();
98 self.with_label(Label::new((range.start as usize)..(range.end as usize), message))
99 }
100
101 pub fn with_label(mut self, label: Label) -> Self {
102 self.labels.push(label);
103 self
104 }
105
106 #[allow(unused)]
107 pub fn with_labels<I>(mut self, labels: I) -> Self
108 where
109 I: IntoIterator<Item = Label>,
110 {
111 self.labels.extend(labels);
112 self
113 }
114
115 pub fn with_help<S>(mut self, help: S) -> Self
116 where
117 Cow<'static, str>: From<S>,
118 {
119 self.help = Some(help.into());
120 self
121 }
122}
123
124impl Diagnostic for RelatedLabel {
125 fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
126 None
127 }
128 fn severity(&self) -> Option<Severity> {
129 Some(self.severity)
130 }
131 fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
132 self.help.as_deref().map(|help| Box::new(help) as Box<_>)
133 }
134 fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
135 None
136 }
137 fn source_code(&self) -> Option<&dyn SourceCode> {
138 self.file.as_ref().map(|f| f as &dyn SourceCode)
139 }
140 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
141 if self.labels.is_empty() {
142 None
143 } else {
144 Some(Box::new(self.labels.iter().cloned().map(|l| l.into())))
145 }
146 }
147 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
148 None
149 }
150 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
151 None
152 }
153}
154
155#[derive(Debug)]
162pub struct RelatedError(Report);
163
164impl RelatedError {
165 pub fn into_report(self) -> Report {
166 self.0
167 }
168
169 #[inline(always)]
170 pub fn as_diagnostic(&self) -> &dyn Diagnostic {
171 self.0.as_ref()
172 }
173}
174
175impl Diagnostic for RelatedError {
176 fn code<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
177 self.as_diagnostic().code()
178 }
179 fn severity(&self) -> Option<Severity> {
180 self.as_diagnostic().severity()
181 }
182 fn help<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
183 self.as_diagnostic().help()
184 }
185 fn url<'a>(&'a self) -> Option<Box<dyn fmt::Display + 'a>> {
186 self.as_diagnostic().url()
187 }
188 fn source_code(&self) -> Option<&dyn SourceCode> {
189 self.as_diagnostic().source_code()
190 }
191 fn labels(&self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + '_>> {
192 self.as_diagnostic().labels()
193 }
194 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
195 self.as_diagnostic().related()
196 }
197 fn diagnostic_source(&self) -> Option<&dyn Diagnostic> {
198 self.as_diagnostic().diagnostic_source()
199 }
200}
201
202impl fmt::Display for RelatedError {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 fmt::Display::fmt(&self.0, f)
205 }
206}
207
208#[cfg(feature = "std")]
209impl std::error::Error for RelatedError {
210 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
211 AsRef::<dyn std::error::Error>::as_ref(&self.0).source()
212 }
213}
214
215#[cfg(not(feature = "std"))]
216impl miette::StdError for RelatedError {
217 fn source(&self) -> Option<&(dyn miette::StdError + 'static)> {
218 AsRef::<dyn miette::StdError>::as_ref(&self.0).source()
219 }
220}
221
222impl From<Report> for RelatedError {
223 fn from(report: Report) -> Self {
224 Self(report)
225 }
226}
227
228impl RelatedError {
229 pub const fn new(report: Report) -> Self {
230 Self(report)
231 }
232
233 pub fn wrap<E>(error: E) -> Self
234 where
235 E: Diagnostic + Send + Sync + 'static,
236 {
237 Self(Report::new_boxed(Box::new(error)))
238 }
239}