device-driver-common 2.2.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: u32,
    pub end: u32,
}

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

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

    pub fn len(&self) -> u32 {
        self.end - self.start
    }

    /// 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,
        }
    }

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

    /// Returns true if the two spans have some overlap
    pub fn overlaps(&self, other: Self) -> bool {
        self.start < other.end && other.start < self.end
    }

    /// Returns true if a cursor at the given offset would select the span
    ///
    /// Note that one offset can select multiple non-overlapping (but touching) spans!
    pub fn is_selected_at(&self, offset: u32) -> bool {
        // Normally end is exclusive, but that's not how cursor positions work
        // We want to be able to put the cursor right after a word and have it select the word
        self.start <= offset && offset <= self.end
    }

    /// Take the start of self until the end of other (max is end of self)
    pub fn until_end_of(&self, other: Self) -> Self {
        Self {
            start: self.start,
            end: self.end.min(other.end),
        }
    }

    /// Take the start of self until the start of other (max is end of self)
    pub fn until_start_of(&self, other: Self) -> Self {
        Self {
            start: self.start,
            end: self.end.min(other.start),
        }
    }
}

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

    type Offset = u32;

    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<(u32, u32)> for Span {
    fn from(value: (u32, u32)) -> Self {
        Self {
            start: value.0,
            end: value.1,
        }
    }
}

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

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

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

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

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

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

#[derive(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: Debug> Debug 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 {}