use std::io::{BufRead, Error};
pub struct ByteLines<B>
where
B: BufRead,
{
buffer: Vec<u8>,
reader: B,
}
impl<B> ByteLines<B>
where
B: BufRead,
{
pub fn new(buf: B) -> Self {
Self {
buffer: Vec::new(),
reader: buf,
}
}
pub fn next(&mut self) -> Option<Result<&[u8], Error>> {
self.buffer.clear();
crate::util::handle_line(
self.reader.read_until(b'\n', &mut self.buffer),
&mut self.buffer,
)
}
}
impl<B> IntoIterator for ByteLines<B>
where
B: BufRead,
{
type Item = Result<Vec<u8>, Error>;
type IntoIter = ByteLinesIter<B>;
#[inline]
fn into_iter(self) -> ByteLinesIter<B> {
ByteLinesIter { inner: self }
}
}
pub struct ByteLinesIter<B>
where
B: BufRead,
{
inner: ByteLines<B>,
}
impl<B> Iterator for ByteLinesIter<B>
where
B: BufRead,
{
type Item = Result<Vec<u8>, Error>;
#[inline]
fn next(&mut self) -> Option<Result<Vec<u8>, Error>> {
self.inner.next().map(|r| r.map(|s| s.to_vec()))
}
}
pub trait ByteLinesReader<B>
where
B: BufRead,
{
fn byte_lines(self) -> ByteLines<B>;
}
impl<B> ByteLinesReader<B> for B
where
B: BufRead,
{
#[inline]
fn byte_lines(self) -> ByteLines<Self> {
super::from_std(self)
}
}
#[cfg(test)]
#[allow(clippy::needless_range_loop)]
mod tests {
use super::*;
use std::fs::File;
use std::io::BufReader;
#[test]
fn test_basic_loop() {
let file = File::open("./res/numbers.txt").unwrap();
let mut brdr = BufReader::new(file).byte_lines();
let mut lines = Vec::new();
while let Some(line) = brdr.next() {
let line = line.unwrap().to_vec();
let line = String::from_utf8(line).unwrap();
lines.push(line);
}
for i in 0..9 {
assert_eq!(lines[i], format!("{}", i));
}
}
#[test]
fn test_basic_iterator() {
let file = File::open("./res/numbers.txt").unwrap();
let mut lines = Vec::new();
for line in BufReader::new(file).byte_lines().into_iter() {
let line = line.unwrap();
let line = String::from_utf8(line).unwrap();
lines.push(line);
}
for i in 0..9 {
assert_eq!(lines[i], format!("{}", i));
}
}
#[test]
fn test_empty_line() {
let file = File::open("./res/empty.txt").unwrap();
let mut lines = Vec::new();
for line in BufReader::new(file).byte_lines().into_iter() {
let line = line.unwrap();
let line = String::from_utf8(line).unwrap();
lines.push(line);
}
assert_eq!(lines.len(), 1);
assert_eq!(lines[0], "");
}
}