solar_interface/diagnostics/
message.rs1use crate::Span;
4use std::{borrow::Cow, ops::Deref};
5
6#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct DiagMsg {
8 inner: Cow<'static, str>,
9}
10
11impl Deref for DiagMsg {
12 type Target = str;
13
14 #[inline]
15 fn deref(&self) -> &Self::Target {
16 &self.inner
17 }
18}
19
20impl From<&'static str> for DiagMsg {
21 fn from(value: &'static str) -> Self {
22 Self { inner: Cow::Borrowed(value) }
23 }
24}
25
26impl From<String> for DiagMsg {
27 fn from(value: String) -> Self {
28 Self { inner: Cow::Owned(value) }
29 }
30}
31
32impl From<Cow<'static, str>> for DiagMsg {
33 fn from(value: Cow<'static, str>) -> Self {
34 Self { inner: value }
35 }
36}
37
38impl DiagMsg {
39 #[inline]
41 pub fn as_str(&self) -> &str {
42 &self.inner
43 }
44
45 pub fn into_inner(self) -> Cow<'static, str> {
46 self.inner
47 }
48}
49
50#[derive(Clone, Debug)]
52pub struct SpanLabel {
53 pub span: Span,
55
56 pub is_primary: bool,
59
60 pub label: Option<DiagMsg>,
62}
63
64#[derive(Clone, Debug, PartialEq, Eq, Hash)]
72pub struct MultiSpan {
73 primary_spans: Vec<Span>,
74 span_labels: Vec<(Span, DiagMsg)>,
75}
76
77impl MultiSpan {
78 #[inline]
79 pub fn new() -> Self {
80 Self { primary_spans: vec![], span_labels: vec![] }
81 }
82
83 pub fn from_span(primary_span: Span) -> Self {
84 Self { primary_spans: vec![primary_span], span_labels: vec![] }
85 }
86
87 pub fn from_spans(mut vec: Vec<Span>) -> Self {
88 vec.sort_unstable();
89 Self { primary_spans: vec, span_labels: vec![] }
90 }
91
92 pub fn push_span_label(&mut self, span: Span, label: impl Into<DiagMsg>) {
93 self.span_labels.push((span, label.into()));
94 }
95
96 pub fn primary_span(&self) -> Option<Span> {
98 self.primary_spans.first().copied()
99 }
100
101 pub fn primary_spans(&self) -> &[Span] {
103 &self.primary_spans
104 }
105
106 pub fn has_primary_spans(&self) -> bool {
108 !self.is_dummy()
109 }
110
111 pub fn is_dummy(&self) -> bool {
113 self.primary_spans.iter().all(|sp| sp.is_dummy())
114 }
115
116 pub fn replace(&mut self, before: Span, after: Span) -> bool {
119 let mut replacements_occurred = false;
120 for primary_span in &mut self.primary_spans {
121 if *primary_span == before {
122 *primary_span = after;
123 replacements_occurred = true;
124 }
125 }
126 for span_label in &mut self.span_labels {
127 if span_label.0 == before {
128 span_label.0 = after;
129 replacements_occurred = true;
130 }
131 }
132 replacements_occurred
133 }
134
135 pub fn pop_span_label(&mut self) -> Option<(Span, DiagMsg)> {
136 self.span_labels.pop()
137 }
138
139 pub fn span_labels(&self) -> Vec<SpanLabel> {
145 let is_primary = |span| self.primary_spans.contains(&span);
146
147 let mut span_labels = self
148 .span_labels
149 .iter()
150 .map(|&(span, ref label)| SpanLabel {
151 span,
152 is_primary: is_primary(span),
153 label: Some(label.clone()),
154 })
155 .collect::<Vec<_>>();
156
157 for &span in &self.primary_spans {
158 if !span_labels.iter().any(|sl| sl.span == span) {
159 span_labels.push(SpanLabel { span, is_primary: true, label: None });
160 }
161 }
162
163 span_labels
164 }
165
166 pub fn has_span_labels(&self) -> bool {
168 self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
169 }
170
171 pub fn clone_ignoring_labels(&self) -> Self {
176 Self { primary_spans: self.primary_spans.clone(), ..Self::new() }
177 }
178}
179
180impl Default for MultiSpan {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186impl From<Span> for MultiSpan {
187 fn from(span: Span) -> Self {
188 Self::from_span(span)
189 }
190}
191
192impl From<Option<Span>> for MultiSpan {
193 fn from(span: Option<Span>) -> Self {
194 if let Some(span) = span { Self::from_span(span) } else { Self::new() }
195 }
196}
197
198impl From<Vec<Span>> for MultiSpan {
199 fn from(spans: Vec<Span>) -> Self {
200 Self::from_spans(spans)
201 }
202}