150 lines
4.3 KiB
Rust
150 lines
4.3 KiB
Rust
use crate::models::{Char, Pos};
|
|
|
|
use std::io::BufRead;
|
|
use std::vec::IntoIter;
|
|
|
|
pub type Result = std::result::Result<Char, Error>;
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
IO(std::io::Error),
|
|
InvalidChar(char),
|
|
}
|
|
|
|
pub struct Input<'a> {
|
|
read: &'a mut dyn BufRead,
|
|
fin: bool,
|
|
iter: IntoIter<char>,
|
|
pos: Pos,
|
|
}
|
|
|
|
impl From<std::io::Error> for Error {
|
|
fn from(err: std::io::Error) -> Self {
|
|
Self::IO(err)
|
|
}
|
|
}
|
|
|
|
impl From<char> for Error {
|
|
fn from(chr: char) -> Self {
|
|
Self::InvalidChar(chr)
|
|
}
|
|
}
|
|
|
|
impl<'a> Input<'a> {
|
|
pub fn new(read: &'a mut dyn BufRead) -> Self {
|
|
Self {
|
|
read,
|
|
fin: false,
|
|
iter: std::iter::empty().collect::<Vec<_>>().into_iter(),
|
|
pos: Pos {
|
|
line: 0,
|
|
..Pos::default()
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Iterator for Input<'_> {
|
|
type Item = Result;
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
if self.fin {
|
|
return None;
|
|
}
|
|
|
|
if let Some(chr) = self.iter.next() {
|
|
let chr = Char::new(chr, self.pos);
|
|
self.pos.index += 1;
|
|
self.pos.col += 1;
|
|
return match chr {
|
|
Err(chr) => Some(Err(chr.into())),
|
|
Ok(chr) => Some(Ok(chr)),
|
|
};
|
|
}
|
|
|
|
let mut buffer = String::new();
|
|
|
|
match self.read.read_line(&mut buffer) {
|
|
Ok(0) => None,
|
|
Ok(_) => {
|
|
self.iter = buffer.chars().collect::<Vec<_>>().into_iter();
|
|
self.pos.line += 1;
|
|
self.pos.col = 1;
|
|
self.next()
|
|
}
|
|
Err(err) => {
|
|
self.fin = true;
|
|
Some(Err(err.into()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
fn chr(value: char, index: usize, line: usize, col: usize) -> Char {
|
|
Char::new(value, Pos::new(index, line, col)).unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn empty() {
|
|
let mut bytes = "".as_bytes();
|
|
let mut input = Input::new(&mut bytes);
|
|
assert!(input.next().is_none());
|
|
assert!(input.next().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn some() {
|
|
let mut bytes = "foo".as_bytes();
|
|
let mut input = Input::new(&mut bytes);
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('f', 0, 1, 1));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 1, 1, 2));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 2, 1, 3));
|
|
assert!(input.next().is_none());
|
|
assert!(input.next().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn newline() {
|
|
let mut bytes = "\n".as_bytes();
|
|
let mut input = Input::new(&mut bytes);
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('\n', 0, 1, 1));
|
|
assert!(input.next().is_none());
|
|
assert!(input.next().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn with_newline() {
|
|
let mut bytes = "foo\nbar".as_bytes();
|
|
let mut input = Input::new(&mut bytes);
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('f', 0, 1, 1));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 1, 1, 2));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 2, 1, 3));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('\n', 3, 1, 4));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('b', 4, 2, 1));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('a', 5, 2, 2));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('r', 6, 2, 3));
|
|
assert!(input.next().is_none());
|
|
assert!(input.next().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn ends_with_newline() {
|
|
let mut bytes = "foo\nbar\n".as_bytes();
|
|
let mut input = Input::new(&mut bytes);
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('f', 0, 1, 1));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 1, 1, 2));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('o', 2, 1, 3));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('\n', 3, 1, 4));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('b', 4, 2, 1));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('a', 5, 2, 2));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('r', 6, 2, 3));
|
|
assert_eq!(input.next().unwrap().unwrap(), chr('\n', 7, 2, 4));
|
|
assert!(input.next().is_none());
|
|
assert!(input.next().is_none());
|
|
}
|
|
}
|