use std::io::BufRead;
use std::io::{self};
use std::iter;
use thiserror::Error;
use crate::Line;
use crate::alignment::section::Sections;
use crate::line;
const NEW_LINE: char = '\n';
const CARRIAGE_RETURN: char = '\r';
#[derive(Debug, Error)]
pub enum Error {
#[error("i/o error: {0}")]
Io(io::Error),
#[error("line error: {0}")]
Line(line::Error),
}
#[derive(Clone, Debug)]
pub struct Reader<T>(T)
where
T: BufRead;
impl<T> Reader<T>
where
T: BufRead,
{
pub fn new(inner: T) -> Self {
Self::from(inner)
}
pub fn inner(&self) -> &T {
&self.0
}
pub fn inner_mut(&mut self) -> &mut T {
&mut self.0
}
pub fn into_inner(self) -> T {
self.0
}
pub fn read_line_raw(&mut self, buffer: &mut String) -> io::Result<usize> {
read_line(self.inner_mut(), buffer)
}
pub fn read_line(&mut self, buffer: &mut String) -> Result<Option<Line>, Error> {
let read = self.read_line_raw(buffer).map_err(Error::Io)?;
match read {
0 => Ok(None),
_ => {
let line = buffer.parse::<Line>().map_err(Error::Line)?;
Ok(Some(line))
}
}
}
pub fn lines(&mut self) -> impl Iterator<Item = io::Result<Line>> + '_ {
let mut buffer = String::new();
iter::from_fn(move || {
buffer.clear();
match self.read_line_raw(&mut buffer) {
Ok(0) => None,
Ok(_) => Some(
buffer
.parse()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)),
),
Err(e) => Some(Err(e)),
}
})
}
pub fn sections(&mut self) -> Sections<'_, T> {
Sections::new(self)
}
}
impl<T> From<T> for Reader<T>
where
T: BufRead,
{
fn from(inner: T) -> Self {
Self(inner)
}
}
fn read_line<T>(reader: &mut T, buffer: &mut String) -> io::Result<usize>
where
T: BufRead,
{
buffer.clear();
match reader.read_line(buffer) {
Ok(0) => Ok(0),
Ok(n) => {
if buffer.ends_with(NEW_LINE) {
buffer.pop();
if buffer.ends_with(CARRIAGE_RETURN) {
buffer.pop();
}
}
Ok(n)
}
Err(e) => Err(e),
}
}
#[cfg(test)]
mod tests {
use std::io;
use super::*;
#[test]
fn test_read_line() {
let data = b"hello\r\nworld!";
let mut cursor = io::Cursor::new(data);
let mut buffer = String::new();
let len = read_line(&mut cursor, &mut buffer).unwrap();
assert_eq!(buffer, "hello");
assert_eq!(len, 7);
let len = read_line(&mut cursor, &mut buffer).unwrap();
assert_eq!(buffer, "world!");
assert_eq!(len, 6);
}
}