miden_diagnostics/
span.rs1use std::cmp;
2use std::convert::{AsMut, AsRef};
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::ops::{Deref, DerefMut, Range};
6
7use codespan::{ByteIndex, ByteOffset};
8
9use super::{SourceId, SourceIndex};
10
11#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct SourceSpan {
31 pub(crate) source_id: SourceId,
32 pub(crate) start: ByteIndex,
33 pub(crate) end: ByteIndex,
34}
35impl fmt::Debug for SourceSpan {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 write!(
38 f,
39 "{}..{}@{}",
40 self.start.to_usize(),
41 self.end.to_usize(),
42 self.source_id.get()
43 )
44 }
45}
46impl Default for SourceSpan {
47 #[inline(always)]
48 fn default() -> Self {
49 Self::UNKNOWN
50 }
51}
52impl SourceSpan {
53 pub const UNKNOWN: Self = Self {
55 source_id: SourceId::UNKNOWN,
56 start: ByteIndex(0),
57 end: ByteIndex(0),
58 };
59
60 #[inline]
64 pub fn new(start: SourceIndex, end: SourceIndex) -> Self {
65 let source_id = start.source_id();
66 assert_eq!(
67 source_id,
68 end.source_id(),
69 "source spans cannot start and end in different files!"
70 );
71 let start = start.index();
72 let end = end.index();
73
74 Self {
75 source_id,
76 start,
77 end,
78 }
79 }
80
81 #[inline(always)]
83 pub fn is_unknown(self) -> bool {
84 self == Self::UNKNOWN
85 }
86
87 #[inline(always)]
89 pub fn source_id(&self) -> SourceId {
90 self.source_id
91 }
92
93 #[inline(always)]
95 pub fn start(&self) -> SourceIndex {
96 SourceIndex::new(self.source_id, self.start)
97 }
98
99 #[inline(always)]
101 pub fn start_index(&self) -> ByteIndex {
102 self.start
103 }
104
105 pub fn shrink_front(mut self, offset: ByteOffset) -> Self {
107 self.start += offset;
108 self
109 }
110
111 #[inline(always)]
113 pub fn end(&self) -> SourceIndex {
114 SourceIndex::new(self.source_id, self.end)
115 }
116
117 #[inline(always)]
119 pub fn end_index(&self) -> ByteIndex {
120 self.end
121 }
122
123 pub fn merge(self, other: SourceSpan) -> Option<SourceSpan> {
129 if self.is_unknown() || other.is_unknown() {
130 return None;
131 }
132 let source_id = self.source_id();
133 if source_id != other.source_id() {
134 return None;
135 }
136 let start = cmp::min(self.start_index(), other.start_index());
137 let end = cmp::max(self.end_index(), other.end_index());
138 Some(SourceSpan::new(
139 SourceIndex::new(source_id, start),
140 SourceIndex::new(source_id, end),
141 ))
142 }
143}
144impl From<SourceSpan> for codespan::Span {
145 #[inline]
146 fn from(span: SourceSpan) -> Self {
147 Self::new(span.start, span.end)
148 }
149}
150impl From<SourceSpan> for ByteIndex {
151 #[inline]
152 fn from(span: SourceSpan) -> Self {
153 span.start_index()
154 }
155}
156impl From<SourceSpan> for Range<usize> {
157 fn from(span: SourceSpan) -> Range<usize> {
158 span.start.into()..span.end.into()
159 }
160}
161impl From<SourceSpan> for Range<SourceIndex> {
162 fn from(span: SourceSpan) -> Range<SourceIndex> {
163 let start = SourceIndex::new(span.source_id, span.start);
164 let end = SourceIndex::new(span.source_id, span.end);
165 start..end
166 }
167}
168
169pub trait Spanned {
171 fn span(&self) -> SourceSpan;
172}
173impl Spanned for SourceSpan {
174 #[inline(always)]
175 fn span(&self) -> SourceSpan {
176 *self
177 }
178}
179impl<T: Spanned> Spanned for Box<T> {
180 #[inline]
181 fn span(&self) -> SourceSpan {
182 self.as_ref().span()
183 }
184}
185
186pub struct Span<T: ?Sized> {
193 span: SourceSpan,
194 pub item: T,
196}
197impl<T: ?Sized> Spanned for Span<T> {
198 #[inline]
199 fn span(&self) -> SourceSpan {
200 self.span
201 }
202}
203impl<T> Span<T> {
204 pub const fn new(span: SourceSpan, item: T) -> Self {
206 Self { span, item }
207 }
208}
209impl<T: ?Sized> AsRef<T> for Span<T> {
210 #[inline(always)]
211 fn as_ref(&self) -> &T {
212 &self.item
213 }
214}
215impl<T: ?Sized> AsMut<T> for Span<T> {
216 #[inline(always)]
217 fn as_mut(&mut self) -> &mut T {
218 &mut self.item
219 }
220}
221impl<T: ?Sized> Deref for Span<T> {
222 type Target = T;
223
224 #[inline(always)]
225 fn deref(&self) -> &Self::Target {
226 &self.item
227 }
228}
229impl<T: ?Sized> DerefMut for Span<T> {
230 #[inline(always)]
231 fn deref_mut(&mut self) -> &mut Self::Target {
232 &mut self.item
233 }
234}
235impl<T: Clone> Clone for Span<T> {
236 fn clone(&self) -> Self {
237 Self {
238 span: self.span,
239 item: self.item.clone(),
240 }
241 }
242}
243impl<T: Copy> Copy for Span<T> {}
244unsafe impl<T: Send> Send for Span<T> {}
245unsafe impl<T: Sync> Sync for Span<T> {}
246impl<T, U> PartialEq<Span<U>> for Span<T>
247where
248 T: PartialEq<U>,
249 U: PartialEq<T>,
250{
251 fn eq(&self, other: &Span<U>) -> bool {
252 self.item.eq(&other.item)
253 }
254}
255impl<T: Eq> Eq for Span<T> {}
256impl<T, U> PartialOrd<Span<U>> for Span<T>
257where
258 T: PartialOrd<U>,
259 U: PartialOrd<T>,
260{
261 fn partial_cmp(&self, other: &Span<U>) -> Option<std::cmp::Ordering> {
262 self.item.partial_cmp(&other.item)
263 }
264}
265impl<T: Ord> Ord for Span<T> {
266 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
267 self.item.cmp(&other.item)
268 }
269}
270impl<T: Hash> Hash for Span<T> {
271 fn hash<H: Hasher>(&self, state: &mut H) {
272 self.item.hash(state)
273 }
274}
275impl<T: fmt::Debug> fmt::Debug for Span<T> {
276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 write!(f, "Spanned({:?}, {:?})", &self.span, &self.item)
278 }
279}
280impl<T: fmt::Display> fmt::Display for Span<T> {
281 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282 write!(f, "{}", &self.item)
283 }
284}