ringels 0.1.0

Simple S-Expression parser
Documentation
use std::ops::{Deref, DerefMut};
#[cfg(feature = "miette")]
use miette::SourceSpan;

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct Span<V, O = usize> {
    pub start: O,
    pub end: O,
    pub value: V,
}

impl<V, O> Span<V, O> {
    pub fn with_value<N>(self, value: N) -> Span<N, O> {
        Span {
            start: self.start,
            end: self.end,
            value,
        }
    }

    pub fn empty(self) -> Span<(), O> {
        self.with_value(())
    }
}

impl<V: ToString, O> Span<V, O> {
    pub fn into_string(self) -> Span<String, O> {
        Span {
            start: self.start,
            end: self.end,
            value: self.value.to_string()
        }
    }
}

pub trait SpanOffset {
    fn absolute_offset(&self) -> usize;
}

impl SpanOffset for usize {
    fn absolute_offset(&self) -> usize {
        *self
    }
}

impl<V, O> Span<V, O> {
    #[inline]
    pub fn new(start: O, end: O, value: V) -> Self {
        Span {
            start,
            end,
            value,
        }
    }

    pub fn unwrap(self) -> V {
        self.value
    }
}

impl<V, O> Deref for Span<V, O> {
    type Target = V;

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

impl<V, O> DerefMut for Span<V, O> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
pub struct LineOffset {
    pub line: usize,
    pub line_offset: usize,
    pub absolute_offset: usize,
}

impl LineOffset {
    pub fn new(line: usize, line_offset: usize, absolute_offset: usize) -> LineOffset {
        LineOffset {
            line,
            line_offset,
            absolute_offset,
        }
    }
}

impl SpanOffset for LineOffset {
    fn absolute_offset(&self) -> usize {
        self.absolute_offset
    }
}

pub type LineSpan<V> = Span<V, LineOffset>;

#[cfg(feature = "miette")]
impl<V, T: SpanOffset> Into<SourceSpan> for &Span<V, T> {
    fn into(self) -> SourceSpan {
        (self.start.absolute_offset(), self.end.absolute_offset() - self.start.absolute_offset()).into()
    }
}

#[cfg(test)]
mod tests {
    use crate::lexer::{LineTracker, Tracker};
    use crate::span::{LineOffset, Span, SpanOffset};

    #[test]
    pub fn simple_test() {
        let mut line_tracker = LineTracker::default();

        line_tracker.start(0);
        line_tracker.process_newline(2);
        assert_eq!(Span::new(LineOffset::new(0, 0, 0), LineOffset::new(1, 1, 4), ()), line_tracker.end(4, ()));
        assert_eq!(1, LineOffset::new(0, 0, 1).absolute_offset());
        assert_eq!(1, 1usize.absolute_offset());
    }
}