use std::io;
use bstr::BStr;
use bstring::BString;
pub trait BufReadExt: io::BufRead {
fn byte_lines(self) -> ByteLines<Self> where Self: Sized {
ByteLines { buf: self }
}
fn for_byte_line<F>(
mut self,
mut for_each_line: F,
) -> io::Result<()>
where Self: Sized,
F: FnMut(&BStr) -> io::Result<bool>
{
let mut bytes = BString::new();
while self.read_until(b'\n', bytes.as_mut_vec())? > 0 {
trim_line(&mut bytes);
if !for_each_line(&bytes)? {
break;
}
bytes.clear();
}
Ok(())
}
fn for_byte_line_with_terminator<F>(
mut self,
mut for_each_line: F,
) -> io::Result<()>
where Self: Sized,
F: FnMut(&BStr) -> io::Result<bool>
{
let mut bytes = BString::new();
while self.read_until(b'\n', bytes.as_mut_vec())? > 0 {
if !for_each_line(&bytes)? {
break;
}
bytes.clear();
}
Ok(())
}
}
impl<B: io::BufRead> BufReadExt for B {}
#[derive(Debug)]
pub struct ByteLines<B> {
buf: B,
}
impl<B: io::BufRead> Iterator for ByteLines<B> {
type Item = io::Result<BString>;
fn next(&mut self) -> Option<io::Result<BString>> {
let mut bytes = BString::new();
match self.buf.read_until(b'\n', bytes.as_mut_vec()) {
Err(e) => Some(Err(e)),
Ok(0) => None,
Ok(_) => {
trim_line(&mut bytes);
Some(Ok(bytes))
}
}
}
}
fn trim_line(line: &mut BString) {
if line.last() == Some(b'\n') {
line.pop();
if line.last() == Some(b'\r') {
line.pop();
}
}
}