Lines
95.65 %
Functions
84.21 %
Branches
100 %
use std::io::BufRead;
use std::io::BufReader;
use std::io::Read;
use streaming_iterator::StreamingIterator;
/// A lending iterator over the lines of a type implementing Read.
pub struct LineIterator<T: Read> {
reader: BufReader<T>,
buffer: String,
end: bool,
}
impl<T: Read> LineIterator<T> {
pub fn new(reader: T) -> LineIterator<T> {
LineIterator {
reader: BufReader::new(reader),
buffer: String::new(),
end: false,
impl<T: Read> StreamingIterator for LineIterator<T> {
type Item = String;
fn advance(&mut self) {
self.buffer.clear();
match self.reader.read_line(&mut self.buffer) {
Ok(n) if n > 0 => {
if self.buffer.ends_with('\n') {
self.buffer.pop();
if self.buffer.ends_with('\r') {
Ok(_) => self.end = true,
Err(_) => self.end = true,
fn get(&self) -> Option<&Self::Item> {
if self.end {
None
} else {
Some(&self.buffer)
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_line_iterator_basic() {
let data = "line1\nline2\nline3";
let cursor = Cursor::new(data);
let mut line_iterator = LineIterator::new(cursor);
let mut lines = Vec::new();
while let Some(line) = line_iterator.next() {
lines.push(line.clone());
assert_eq!(lines, vec!["line1", "line2", "line3"]);
fn test_line_iterator_empty() {
let data = "";
assert!(lines.is_empty());
fn test_line_iterator_single_line() {
let data = "single line";
assert_eq!(lines, vec!["single line"]);
fn test_line_iterator_with_carriage_return() {
let data = "line1\r\nline2\r\nline3";