repubmark/src/input.rs

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