chasa 0.5.0

A parser combinator focused on rollback/commit, streaming inputs, and composable method chains.
Documentation
use core::marker::PhantomData;

use crate::input::{Input, Offset, SeqInput};

impl<'a> Input for &'a str {
    type Item = char;
    type Pos = Offset<char>;

    fn index(&self) -> u64 {
        u64::MAX - (self.len() as u64)
    }

    fn pos(&self) -> Self::Pos {
        Offset(self.as_ptr() as usize, PhantomData)
    }

    fn next(&mut self) -> Option<Self::Item> {
        let mut chars = self.chars();
        let c = chars.next();
        *self = chars.as_str();
        c
    }

    fn commit(&mut self) {}
}

impl<'a> SeqInput for &'a str {
    type Seq = &'a str;
    fn seq(start: Self::Checkpoint, end: Self::Checkpoint) -> Self::Seq {
        &start[0..(start.len() - end.len())]
    }
}

impl<'a, T> Input for &'a [T]
where
    T: Clone,
{
    type Item = T;
    type Pos = Offset<T>;

    fn index(&self) -> u64 {
        u64::MAX - (self.len() as u64)
    }

    fn pos(&self) -> Self::Pos {
        Offset(self.as_ptr() as usize, PhantomData)
    }

    fn next(&mut self) -> Option<Self::Item> {
        let first = self.first()?.clone();
        *self = &self[1..];
        Some(first)
    }

    fn commit(&mut self) {}
}

impl<'a, T> SeqInput for &'a [T]
where
    T: Clone,
{
    type Seq = &'a [T];
    fn seq(start: Self::Checkpoint, end: Self::Checkpoint) -> Self::Seq {
        &start[0..(start.len() - end.len())]
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::back::Back;

    #[test]
    fn str_seq_returns_consumed_prefix() {
        let mut input = "ab";
        let start = input.checkpoint();
        input.next();
        let end = input.checkpoint();
        let seq = <&str as SeqInput>::seq(start, end);
        assert_eq!(seq, "a");
    }

    #[test]
    fn slice_seq_returns_consumed_prefix() {
        let mut input: &[u8] = b"ab";
        let start = input.checkpoint();
        input.next();
        let end = input.checkpoint();
        let seq = <&[u8] as SeqInput>::seq(start, end);
        assert_eq!(seq, b"a");
    }
}