Documentation
use std::io::{self, Read};

pub struct LineIter<R: Read> {
  reader: R,
  buffer: Vec<u8>,
  position: usize,
  last_line_returned: bool,
}

impl<R: Read> LineIter<R> {
  pub fn new(reader: R) -> Self {
    LineIter {
      reader,
      buffer: Vec::new(),
      position: 0,
      last_line_returned: false,
    }
  }
}

impl<R: Read> Iterator for LineIter<R> {
  type Item = io::Result<String>;

  fn next(&mut self) -> Option<Self::Item> {
    if self.last_line_returned {
      return None;
    }

    let mut line = Vec::new();
    loop {
      if self.position >= self.buffer.len() {
        self.buffer.clear();
        self.position = 0;
        let mut temp_buf = [0; 1024];
        match self.reader.read(&mut temp_buf) {
          Ok(0) => break,
          Ok(n) => self.buffer.extend_from_slice(&temp_buf[..n]),
          Err(e) => return Some(Err(e)),
        }
      }

      while self.position < self.buffer.len() {
        let byte = self.buffer[self.position];
        self.position += 1;

        if byte == b'\n' {
          return Some(Ok(String::from_utf8_lossy(&line).to_string()));
        } else if byte == b'\r' {
          if self.position < self.buffer.len() && self.buffer[self.position] == b'\n' {
            self.position += 1;
          }
          return Some(Ok(String::from_utf8_lossy(&line).to_string()));
        } else {
          line.push(byte);
        }
      }
    }

    if !line.is_empty() {
      self.last_line_returned = true;
      return Some(Ok(String::from_utf8_lossy(&line).to_string()));
    }

    None
  }
}