use std::fmt;
use std::io::BufRead;
use std::iter::Iterator;
#[derive(Debug, Clone, Default)]
pub struct Line {
inner: String,
number: usize,
}
impl Line {
pub fn new(line: String, line_number: usize) -> Line {
Line {
inner: line,
number: line_number,
}
}
pub fn as_str(&self) -> &str {
self.inner.as_str()
}
pub fn number(&self) -> usize {
self.number
}
}
impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Line {}: {}", self.number, self.inner)
}
}
pub trait LineRead {
fn next_line(&mut self) -> Option<Line>;
}
#[derive(Debug, Clone, Default)]
pub struct LineReader<B> {
reader: B,
saved: Option<String>,
number: usize,
}
impl<B: BufRead> LineReader<B> {
pub fn new(reader: B) -> LineReader<B> {
LineReader {
reader,
saved: None,
number: 0,
}
}
}
impl<B: BufRead> LineRead for LineReader<B> {
fn next_line(&mut self) -> Option<Line> {
let mut next_line = String::new();
let mut line_number: usize = 0;
if let Some(start) = self.saved.take() {
next_line.push_str(start.as_str());
self.number += 1;
line_number = self.number;
} else {
for line in self.reader.by_ref().lines() {
let line = line.ok()?;
self.number += 1;
if !line.is_empty() {
next_line = line.trim_end().to_string();
line_number = self.number;
break;
}
}
}
for line in self.reader.by_ref().lines() {
let mut line = line.ok()?;
if line.is_empty() {
self.number += 1;
} else if line.starts_with(' ') || line.starts_with('\t') {
line.remove(0);
next_line.push_str(line.trim_end());
self.number += 1;
} else {
self.saved = Some(line.trim().to_string());
break;
}
}
if next_line.is_empty() {
None
} else {
Some(Line::new(next_line, line_number))
}
}
}
impl<B: BufRead> Iterator for LineReader<B> {
type Item = Line;
fn next(&mut self) -> Option<Line> {
self.next_line()
}
}