/// A span is made up of /// - the start location /// - the end location /// - the file id #[derive(Eq, PartialEq, Clone, Copy, serde::Serialize, serde::Deserialize)] pub struct Span(pub usize, pub usize, pub usize); impl Span { pub const DUMMY: Span = Span(usize::MAX, usize::MAX, usize::MAX); pub fn point(loc: usize, file_id: usize) -> Self { Span(loc, loc, file_id) } /// Get the span that includes this and the other span completely. /// Will panic if the spans are from different file_ids. pub fn to(mut self, other: Span) -> Self { assert!(other.2 == self.2); self.1 = other.1; self } pub fn ending_at(mut self, end: usize) -> Self { self.1 = end; self } /// Turn this span into a span only highlighting the point it starts at, setting the length to 0. pub fn point_span(mut self) -> Self { self.1 = self.0; self } /// Turn this span into a span only highlighting the point it ends at, setting the length to 0. pub fn point_span_at_end(mut self) -> Self { self.0 = self.1; self } pub fn shifted(mut self, n: isize) -> Self { self.0 = isize::max(0, self.0 as isize + n) as usize; self.1 = isize::max(0, self.0 as isize + n) as usize; self } pub fn new_relative(mut self, other_start: usize, other_end: usize) -> Self { self.0 += other_start; self.1 += other_end; self } pub fn is_dummy(&self) -> bool { *self == Self::DUMMY } } impl std::fmt::Display for Span { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.is_dummy() { write!(f, "DUMMY") } else { write!(f, "{}..{}", self.0, self.1) } } } impl std::fmt::Debug for Span { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) } } pub trait Spanned { fn span(&self) -> Span; }