use std::io::BufRead;
use log::warn;
use crate::types::LineType;
#[derive(Debug, PartialEq, Eq)]
pub enum TldrFormat {
Undecided,
V1,
V2,
}
#[derive(Debug)]
pub struct LineIterator<R: BufRead> {
reader: R,
first_line: bool,
current_line: String,
format: TldrFormat,
}
impl<R> LineIterator<R>
where
R: BufRead,
{
pub fn new(reader: R) -> Self {
Self {
reader,
first_line: true,
current_line: String::new(),
format: TldrFormat::Undecided,
}
}
}
impl<R: BufRead> Iterator for LineIterator<R> {
type Item = LineType;
fn next(&mut self) -> Option<LineType> {
self.current_line.clear();
let bytes_read = self.reader.read_line(&mut self.current_line);
match bytes_read {
Ok(0) => None,
Err(e) => {
warn!("Could not read line from reader: {:?}", e);
None
}
Ok(_) => {
if self.first_line {
if self.current_line.starts_with('#') {
self.format = TldrFormat::V1;
} else {
let mut devnull = String::new();
if let Err(e) = self.reader.read_line(&mut devnull) {
warn!("Could not read line from reader: {:?}", e);
return None;
}
self.first_line = false;
self.format = TldrFormat::V2;
return Some(LineType::Title(self.current_line.trim_end().to_string()));
}
}
self.first_line = false;
match self.format {
TldrFormat::V1 => Some(LineType::from_v1(&self.current_line[..])),
TldrFormat::V2 => Some(LineType::from(&self.current_line[..])),
TldrFormat::Undecided => panic!("Could not determine page format version"),
}
}
}
}
}
#[cfg(test)]
mod test {
use super::LineIterator;
use crate::types::LineType;
#[test]
fn test_first_line_old_format() {
let input = "# The Title\n\n";
let mut lines = LineIterator::new(input.as_bytes());
let title = lines.next().unwrap();
assert_eq!(title, LineType::Title("The Title".to_string()));
let empty = lines.next().unwrap();
assert_eq!(empty, LineType::Empty);
}
#[test]
fn test_first_line_new_format() {
let input = "The Title\n=========\n\n";
let mut lines = LineIterator::new(input.as_bytes());
let title = lines.next().unwrap();
assert_eq!(title, LineType::Title("The Title".to_string()));
let empty = lines.next().unwrap();
assert_eq!(empty, LineType::Empty);
}
}