// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. use miette::SourceSpan; use std::{ fmt::{self, Display, Formatter}, ops::{Add, Index, Sub}, }; /// A region between two offsets in an array. Spans are the half-open interval `[lo, hi)`. #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct Span { /// The smallest offset contained in the span. pub lo: u32, /// The next offset after the largest offset contained in the span. pub hi: u32, } impl Span { /// Returns true if the position is within the span. Meaning it is in the /// right open interval `[self.lo, self.hi)`. #[must_use] pub fn contains(&self, offset: u32) -> bool { (self.lo..self.hi).contains(&offset) } /// Returns true if the position is in the closed interval `[self.lo, self.hi]`. #[must_use] pub fn touches(&self, offset: u32) -> bool { (self.lo..=self.hi).contains(&offset) } /// Intersect `other` with `self` and returns a new `Span` or `None` /// if the spans have no overlap. #[must_use] pub fn intersection(&self, other: &Self) -> Option { let lo = self.lo.max(other.lo); let hi = self.hi.min(other.hi); if lo <= hi { Some(Self { lo, hi }) } else { None } } } impl Add for Span { type Output = Self; fn add(self, rhs: u32) -> Self::Output { Self { lo: self.lo + rhs, hi: self.hi + rhs, } } } impl Sub for Span { type Output = Self; fn sub(self, rhs: u32) -> Self::Output { Self { lo: self.lo - rhs, hi: self.hi - rhs, } } } impl Display for Span { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "[{}-{}]", self.lo, self.hi)?; Ok(()) } } impl Index for str { type Output = str; fn index(&self, index: Span) -> &Self::Output { &self[(index.lo as usize)..(index.hi as usize)] } } impl Index<&Span> for str { type Output = str; fn index(&self, index: &Span) -> &Self::Output { &self[(index.lo as usize)..(index.hi as usize)] } } impl Index for String { type Output = str; fn index(&self, index: Span) -> &Self::Output { &self[(index.lo as usize)..(index.hi as usize)] } } impl From for SourceSpan { fn from(value: Span) -> Self { Self::from((value.lo as usize)..(value.hi as usize)) } } pub trait WithSpan { #[must_use] fn with_span(self, span: Span) -> Self; } impl WithSpan for Box where T: WithSpan, { fn with_span(mut self, span: Span) -> Self { *self = (*self).with_span(span); self } }