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);
}
}