lexington 0.3.0

A very simple library for lexing / parsing
Documentation
/// An iterator which can be "reset" after an arbitrary number of
/// calls to `next()`.  This is achieved using a
/// buffer which stores items as they are read.
pub trait ResetIterator : Iterator {
    /// Get the current position of this iterator.
    fn offset(&self) -> usize;

    /// Back up the iterator a given number of character positions.
    fn backup(&mut self, n:usize);

    /// Empty the internal lookahead buffer.
    fn reset(&mut self);
}

// ===================================================================
// ResetChars
// ===================================================================

use std::str::Chars;

/// An iterator which can be "reset" after an arbitrary number of
/// calls to `next()`.  This is achieved using a
/// buffer which stores items as they are read.
pub struct ResetChars<'a> {
    /// The underlying iterator from which this iterator is based.
    iter: Chars<'a>,
    /// Stores items which have been read out of the iterator already.
    items: Vec<char>,
    /// Determines character index of first element of `items` in original stream.
    start: usize,
    /// Determines character index within original stream.
    offset: usize,
    /// Determines byte offset within original stream
    byte_offset: usize
}

impl<'a> ResetChars<'a> {
    /// Construct a lookahead iterator from an arbitrary iterator.
    pub fn new(iter:Chars<'a>) -> Self {
        Self{iter, items: Vec::new(), start:0, offset:0, byte_offset:0 }
    }

    /// Get the current position within this iterator.
    pub fn offset(&self) -> usize {
        self.offset
    }

    /// Get the current byte position within original string slice of
    /// this iterator.
    pub fn byte_offset(&self) -> usize {
        self.byte_offset
    }

    /// Back up the iterator a given number of character positions.
    pub fn backup(&mut self, n:usize) {
        assert!(n <= self.items.len());
        self.offset = self.offset - n;
        // Update byteoffset accordingly.
        let m = self.items.len() - n;
        for i in m .. self.items.len() {
            self.byte_offset -= self.items[i].len_utf8();
        }
    }

    /// Empty the internal lookahead buffer.
    pub fn reset(&mut self) {
        // Compute amount to reset.
        let n = self.offset - self.start;
        // Move start ptr along        
        self.start = self.offset;
        // Clean all items
        self.items.drain(0..n);
    }
}

impl<'a> Iterator for ResetChars<'a> {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        // Compute index within items
        let i = self.offset - self.start;        
        // Check whether item available
        if i >= self.items.len() {
            // Pull another item off.
            match self.iter.next() {
                Some(v) => {self.items.push(v);}
                None => {return None;}
            };
        }
        // Determine next character
        let c = self.items[i];
        // Increment position
        self.offset += 1;
        self.byte_offset += c.len_utf8();
        // Done
        Some(c)        
    }
}

impl<'a> ResetIterator for ResetChars<'a> {
    /// Get the current position of this iterator.
    fn offset(&self) -> usize {
        self.offset()
    }

    /// Back up the iterator a given number of positions.
    fn backup(&mut self, n:usize) {
        self.backup(n)
    }

    /// Empty the internal lookahead buffer.
    fn reset(&mut self) {
        self.reset()
    }
}