use alloc::string::String;
use peek_nth::PeekableNth;
use super::{Line, Lines, State};
pub trait Input {
fn peek(&mut self, state: &State, offset: usize) -> Option<char>;
fn lines<'a>(&'a mut self, state: &'a mut State) -> Lines<'a>;
#[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 skip_line(&mut self, state: &mut State) {
if !self.is_done(state) {
while let Some(ch) = self.read(state) {
if ch == '\n' {
break;
}
}
}
}
#[inline]
fn peek_line(&mut self, state: &State) -> Option<Line> {
if self.is_done(state) {
None
} else {
let mut string = String::new();
let mut index = 0;
let offset = state.index();
while let Some(ch) = self.peek(state, index) {
if ch != '\n' {
index += 1;
string.push(ch);
} else {
break;
}
}
Some((offset, string).into())
}
}
#[inline]
fn read_line(&mut self, state: &mut State) -> Option<Line> {
if self.is_done(state) {
None
} else {
let mut string = String::new();
let offset = state.index();
while let Some(ch) = self.read(state) {
if ch != '\n' {
string.push(ch);
} else {
break;
}
}
Some((offset, string).into())
}
}
#[inline]
fn read_whitespace(&mut self, state: &mut State) -> Option<String> {
if self.is_done(state) {
None
} else {
let mut string = String::new();
while let Some(ch) = self.peek(state, 0) {
if ch.is_whitespace() {
self.read(state);
string.push(ch);
} else {
break;
}
}
if string.is_empty() {
None
} else {
Some(string)
}
}
}
#[inline]
fn skip_whitespaces(&mut self, state: &mut State) {
if !self.is_done(state) {
while let Some(ch) = self.peek(state, 0) {
if ch.is_whitespace() {
self.read(state);
}
}
}
}
#[inline]
fn is_done(&mut self, state: &State) -> bool {
!self.can_peek(state, 0)
}
#[inline]
fn can_peek(&mut self, state: &State, offset: usize) -> bool {
self.peek(state, offset).is_some()
}
}
impl<I> Input for PeekableNth<I>
where
I: Iterator<Item = char>,
{
#[inline]
fn peek(&mut self, state: &State, offset: usize) -> Option<char> {
self.peek_nth(state.index() + offset).map(Clone::clone)
}
#[inline]
fn lines<'a>(&'a mut self, state: &'a mut State) -> Lines<'a> {
Lines::new(self, state)
}
}