device-driver-common 2.0.0

Internal compiler crate for the device-driver toolkit
Documentation
use std::{
    fmt::{Debug, Display},
    ops::Range,
};

#[derive(Clone, Eq, PartialEq, Copy, Default, Hash)]
pub struct Span {
    pub start: usize,
    pub end: usize,
}

impl Span {
    pub const fn empty() -> Self {
        Self { start: 0, end: 0 }
    }

    pub fn is_empty(&self) -> bool {
        self.start == 0 && self.end == 0
    }

    /// Return self if not empty, or the other span if self is empty
    #[must_use]
    pub fn or(&self, other: Self) -> Self {
        if self.is_empty() { other } else { *self }
    }

    /// Get the combined span that encompasses both spans.
    /// The order does not matter.
    #[must_use]
    pub fn to(&self, other: Self) -> Self {
        Self {
            start: self.start.min(other.start),
            end: self.end.max(other.end),
        }
    }

    /// Take the current span, but skip the start until the `skip` span has been passed
    #[must_use]
    pub fn skip(&self, skip: Self) -> Self {
        assert!(skip.end >= self.start);
        assert!(skip.end <= self.end);
        Self {
            start: skip.end,
            end: self.end,
        }
    }

    /// Take the current span, but skip the first part and start from the given start span
    #[must_use]
    pub fn start_from(&self, start: Self) -> Self {
        assert!(start.start >= self.start);
        assert!(start.start <= self.end);
        Self {
            start: start.start,
            end: self.end,
        }
    }

    /// Discard the span and keep a zero-length span at the end value
    #[must_use]
    pub fn collapse_to_end(&self) -> Span {
        Span {
            start: self.end,
            end: self.end,
        }
    }
}

impl chumsky::span::Span for Span {
    type Context = ();

    type Offset = usize;

    fn new(_context: Self::Context, range: Range<Self::Offset>) -> Self {
        range.into()
    }

    fn context(&self) -> Self::Context {}

    fn start(&self) -> Self::Offset {
        self.start
    }

    fn end(&self) -> Self::Offset {
        self.end
    }
}

impl Display for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}..{}", self.start, self.end)
    }
}
impl Debug for Span {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self)
    }
}

impl From<(usize, usize)> for Span {
    fn from(value: (usize, usize)) -> Self {
        Self {
            start: value.0,
            end: value.1,
        }
    }
}

impl From<Range<usize>> for Span {
    fn from(value: Range<usize>) -> Self {
        Self {
            start: value.start,
            end: value.end,
        }
    }
}

impl From<Span> for Range<usize> {
    fn from(value: Span) -> Self {
        value.start..value.end
    }
}

impl<'a> From<&'a Span> for Range<usize> {
    fn from(value: &'a Span) -> Self {
        value.start..value.end
    }
}

#[derive(Debug, Clone, Eq, Copy)]
pub struct Spanned<T> {
    pub span: Span,
    pub value: T,
}

impl<T: PartialEq> PartialEq for Spanned<T> {
    fn eq(&self, other: &Self) -> bool {
        // Only compare value. The span is transparent
        self.value == other.value
    }
}

impl<T: PartialEq> PartialEq<T> for Spanned<T> {
    fn eq(&self, other: &T) -> bool {
        // Only compare value. The span is transparent
        &self.value == other
    }
}

impl<T: std::hash::Hash> std::hash::Hash for Spanned<T> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.value.hash(state);
        // Only hash value. The span is transparent
    }
}

impl<T: Default> Default for Spanned<T> {
    fn default() -> Self {
        Self {
            span: (0, 0).into(),
            value: Default::default(),
        }
    }
}

impl<T: Display> Display for Spanned<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.value.fmt(f)
    }
}

impl<T> std::ops::Deref for Spanned<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> std::ops::DerefMut for Spanned<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

impl<T> Spanned<T> {
    pub fn new(span: Span, value: T) -> Self {
        Self { span, value }
    }
}

impl<T, S: Into<Span>> From<(T, S)> for Spanned<T> {
    fn from((value, span): (T, S)) -> Self {
        Self {
            span: span.into(),
            value,
        }
    }
}

impl<T: PartialOrd> PartialOrd<T> for Spanned<T> {
    fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
        self.value.partial_cmp(other)
    }
}

pub trait SpanExt {
    fn with_span(self, span: impl Into<Span>) -> Spanned<Self>
    where
        Self: Sized,
    {
        Spanned::new(span.into(), self)
    }

    /// Same as [`Self::with_span`], but can avoid name collisions
    fn spanned(self, span: impl Into<Span>) -> Spanned<Self>
    where
        Self: Sized,
    {
        self.with_span(span)
    }

    fn with_dummy_span(self) -> Spanned<Self>
    where
        Self: Sized,
    {
        self.with_span((0, 0))
    }

    fn into_with_dummy_span<T>(self) -> Spanned<T>
    where
        Self: Into<T>,
    {
        self.into().with_dummy_span()
    }
}
impl<T> SpanExt for T {}