sudo-rs 0.2.0-dev.20230627

A memory safe implementation of sudo and su.
Documentation
pub trait CharStream {
    fn advance(&mut self);
    fn peek(&mut self) -> Option<char>;
    fn get_pos(&self) -> (usize, usize);
}

pub struct PeekableWithPos<Iter: Iterator> {
    iter: std::iter::Peekable<Iter>,
    line: usize,
    col: usize,
}

impl<Iter: Iterator<Item = char>> PeekableWithPos<Iter> {
    pub fn new(src: Iter) -> Self {
        PeekableWithPos {
            iter: src.peekable(),
            line: 1,
            col: 1,
        }
    }
}

impl<Iter: Iterator<Item = char>> CharStream for PeekableWithPos<Iter> {
    fn advance(&mut self) {
        match self.iter.next() {
            Some('\n') => {
                self.line += 1;
                self.col = 1;
            }
            Some(_) => self.col += 1,
            _ => {}
        }
    }

    fn peek(&mut self) -> Option<char> {
        self.iter.peek().cloned()
    }

    fn get_pos(&self) -> (usize, usize) {
        (self.line, self.col)
    }
}

#[cfg(test)]
impl<Iter: Iterator<Item = char>> CharStream for std::iter::Peekable<Iter> {
    fn advance(&mut self) {
        self.next();
    }

    fn peek(&mut self) -> Option<char> {
        self.peek().cloned()
    }

    fn get_pos(&self) -> (usize, usize) {
        (0, 0)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_iter() {
        let mut stream = PeekableWithPos::<std::str::Chars>::new("12\n3\n".chars());
        assert_eq!(stream.peek(), Some('1'));
        stream.advance();
        assert_eq!(stream.peek(), Some('2'));
        stream.advance();
        stream.advance();
        assert_eq!(stream.peek(), Some('3'));
        stream.advance();
        assert_eq!(stream.get_pos(), (2, 2));
    }
}