chars_input 0.2.2

chars input
use alloc::boxed::Box;
use alloc::vec::Vec;
use alloc::string::String;

use super::{Lines, State};

pub trait Input {
    fn peek(&mut self, state: &State, offset: usize) -> Option<char>;

    #[inline]
    fn read(&mut self, state: &mut State) -> Option<char> {
        match self.peek(state, 0) {
            Some(ch) => {
                state.read(ch == '\n');
                Some(ch)
            }
            None => None,
        }
    }

    #[inline]
    fn read_offset(&mut self, state: &mut State, offset: usize) -> usize {
        let mut read = 0;

        for _ in 0..offset {
            if self.read(state).is_none() {
                break;
            } else {
                read += 1;
            }
        }

        read
    }

    #[inline]
    fn peek_line(&mut self, state: &State) -> Option<String> {
        if self.is_done(state) {
            None
        } else {
            let mut string = String::new();
            let mut index = 0;

            while let Some(ch) = self.peek(state, index) {
                if ch != '\n' {
                    index += 1;
                    string.push(ch);
                } else {
                    break;
                }
            }

            Some(string)
        }
    }
    #[inline]
    fn read_line(&mut self, state: &mut State) -> Option<String> {
        if self.is_done(state) {
            None
        } else {
            let mut string = String::new();

            while let Some(ch) = self.read(state) {
                if ch != '\n' {
                    string.push(ch);
                } else {
                    break;
                }
            }

            Some(string)
        }
    }

    #[inline]
    fn lines<'a>(&'a mut self, state: &'a mut State) -> Lines<'a, Self>
    where
        Self: Sized,
    {
        Lines::new(self, state)
    }

    #[inline]
    fn is_done(&mut self, state: &State) -> bool {
        self.peek(state, 0).is_none()
    }

    #[inline]
    fn can_read(&mut self, state: &State, offset: usize) -> bool {
        self.peek(state, offset).is_some()
    }
}

macro_rules! peek_slice {
    ($this:ident, $state:ident, $offset:ident) => ({
        let index = $state.index() + $offset;

        if index < $this.len() {
            Some($this[index])
        } else {
            None
        }
    });
}

impl Input for [char] {
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        peek_slice!(self, state, offset)
    }
}
impl<'a> Input for &'a [char] {
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        peek_slice!(self, state, offset)
    }
}
impl<'a> Input for &'a mut [char] {
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        peek_slice!(self, state, offset)
    }
}

impl Input for Vec<char> {
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        peek_slice!(self, state, offset)
    }
}
impl<'a> Input for &'a Vec<char> {
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        peek_slice!(self, state, offset)
    }
}

impl<'a, T> Input for &'a mut T
where
    T: 'a + Input,
{
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        Input::peek(&mut **self, state, offset)
    }
}

impl<T> Input for Box<T>
where
    T: 'static + Input,
{
    #[inline]
    fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
        Input::peek(&mut **self, state, offset)
    }
}

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

    fn trait_object_read_offset(input: &mut Input, state: &mut State, offset: usize) {
        input.read_offset(state, offset);
    }

    fn trait_object_read_lines(input: &mut Input, state: &mut State) -> usize {
        let mut lines = 0;

        while let Some(_) = input.read_line(state) {
            lines += 1;
        }

        lines
    }

    #[test]
    fn test_input() {
        let mut state = State::new();
        let mut input = "abc\ndef".chars().collect::<Vec<char>>();

        trait_object_read_offset(&mut input, &mut state, 4);
        assert_eq!(input.peek(&mut state, 0), Some('d'));
        assert_eq!(input.peek(&mut state, 1), Some('e'));
        assert_eq!(input.peek(&mut state, 2), Some('f'));
        assert_eq!(state.index(), 4);
        assert_eq!(state.row(), 2);
        assert_eq!(state.col(), 1);

        assert_eq!(trait_object_read_lines(&mut input, &mut state), 1);
    }
}