use std::fmt::Debug;
use std::ops::Range;
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
pub struct Span {
lo: u32,
hi: u32,
}
impl Span {
#[must_use]
#[inline]
pub fn new(lo: u32, hi: u32) -> Self {
Span { lo, hi }
}
#[must_use]
#[inline]
pub fn new_shrunk(amount: u32) -> Self {
Span {
lo: amount,
hi: amount,
}
}
#[must_use]
#[inline]
pub fn new_dummy() -> Self {
Self { lo: 0, hi: 0 }
}
#[must_use]
#[inline]
pub fn lo(self) -> u32 {
self.lo
}
#[must_use]
#[inline]
pub fn with_lo(self, lo: u32) -> Self {
Self { lo, ..self }
}
#[must_use]
#[inline]
pub fn hi(self) -> u32 {
self.hi
}
#[must_use]
#[inline]
pub fn with_hi(self, hi: u32) -> Self {
Self { hi, ..self }
}
#[must_use]
#[inline]
pub fn is_dummy(self) -> bool {
self.lo == 0 && self.hi == 0
}
#[must_use]
#[inline]
pub fn shrink_to_lo(self) -> Span {
self.with_hi(self.lo)
}
#[must_use]
#[inline]
pub fn shrink_to_hi(self) -> Span {
self.with_lo(self.hi)
}
#[must_use]
#[inline]
pub fn is_empty(self) -> bool {
self.hi == self.lo
}
#[must_use]
#[inline]
pub fn substitute_dummy(self, other: Span) -> Span {
if self.is_dummy() {
other
} else {
self
}
}
#[must_use]
#[inline]
pub fn contains(self, other: Span) -> bool {
self.lo <= other.lo && other.hi <= self.hi
}
#[must_use]
#[inline]
pub fn overlaps(self, other: Span) -> bool {
self.lo < other.hi && other.lo < self.hi
}
#[must_use]
#[inline]
pub fn to(self, end: Span) -> Span {
Span::new(
std::cmp::min(self.lo, end.lo),
std::cmp::max(self.hi, end.hi),
)
}
#[must_use]
#[inline]
pub fn between(self, end: Span) -> Span {
Span::new(self.hi, end.lo)
}
#[must_use]
#[inline]
pub fn until(self, end: Span) -> Span {
Span::new(self.lo, end.lo)
}
#[must_use]
#[inline]
pub fn add_hi(self, amount: u32) -> Span {
self.with_hi(self.hi + amount)
}
#[must_use]
#[inline]
pub fn sub_hi(self, amount: u32) -> Span {
self.with_hi(self.hi - amount)
}
#[must_use]
#[inline]
pub fn add_lo(self, amount: u32) -> Span {
self.with_lo(self.lo + amount)
}
#[must_use]
#[inline]
pub fn sub_lo(self, amount: u32) -> Span {
self.with_lo(self.lo - amount)
}
#[must_use]
#[inline]
pub fn len(self) -> u32 {
self.hi - self.lo
}
#[must_use]
#[inline]
pub fn into_range(self) -> Range<usize> {
self.into()
}
}
impl Default for Span {
fn default() -> Self {
Self::new_dummy()
}
}
impl From<Span> for Range<usize> {
fn from(span: Span) -> Self {
span.lo as usize..span.hi as usize
}
}
impl From<Span> for Range<u32> {
fn from(span: Span) -> Self {
span.lo..span.hi
}
}
impl From<Range<u32>> for Span {
fn from(range: Range<u32>) -> Self {
Span::new(range.start, range.end)
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Spanned<T>
where
T: Debug,
{
span: Span,
value: T,
}
impl<T> Spanned<T>
where
T: Debug,
{
pub fn new(span: Span, value: T) -> Self {
Self { span, value }
}
pub fn value(&self) -> &T {
&self.value
}
pub fn value_owned(self) -> T {
self.value
}
pub fn span(&self) -> Span {
self.span
}
#[must_use]
pub fn as_ref(&'_ self) -> Spanned<&'_ T> {
Spanned {
span: self.span,
value: &self.value,
}
}
#[must_use]
pub fn map<U: Debug>(self, f: impl FnOnce(T) -> U) -> Spanned<U> {
Spanned {
span: self.span,
value: f(self.value),
}
}
}
impl<T: PartialEq + Debug> PartialEq<T> for Spanned<T> {
fn eq(&self, other: &T) -> bool {
self.value.eq(other)
}
}
impl<T: Debug> From<(u32, T, u32)> for Spanned<T> {
fn from((lo, val, hi): (u32, T, u32)) -> Self {
Spanned::new(Span::new(lo, hi), val)
}
}
impl<T: Debug> From<(T, Range<u32>)> for Spanned<T> {
fn from((val, range): (T, Range<u32>)) -> Self {
Spanned::new(Span::from(range), val)
}
}