1 use crate::io; 2 3 pub struct LineColIterator<I> { 4 iter: I, 5 6 /// Index of the current line. Characters in the first line of the input 7 /// (before the first newline character) are in line 1. 8 line: usize, 9 10 /// Index of the current column. The first character in the input and any 11 /// characters immediately following a newline character are in column 1. 12 /// The column is 0 immediately after a newline character has been read. 13 col: usize, 14 15 /// Byte offset of the start of the current line. This is the sum of lenghts 16 /// of all previous lines. Keeping track of things this way allows efficient 17 /// computation of the current line, column, and byte offset while only 18 /// updating one of the counters in `next()` in the common case. 19 start_of_line: usize, 20 } 21 22 impl<I> LineColIterator<I> 23 where 24 I: Iterator<Item = io::Result<u8>>, 25 { new(iter: I) -> LineColIterator<I>26 pub fn new(iter: I) -> LineColIterator<I> { 27 LineColIterator { 28 iter, 29 line: 1, 30 col: 0, 31 start_of_line: 0, 32 } 33 } 34 line(&self) -> usize35 pub fn line(&self) -> usize { 36 self.line 37 } 38 col(&self) -> usize39 pub fn col(&self) -> usize { 40 self.col 41 } 42 byte_offset(&self) -> usize43 pub fn byte_offset(&self) -> usize { 44 self.start_of_line + self.col 45 } 46 } 47 48 impl<I> Iterator for LineColIterator<I> 49 where 50 I: Iterator<Item = io::Result<u8>>, 51 { 52 type Item = io::Result<u8>; 53 next(&mut self) -> Option<io::Result<u8>>54 fn next(&mut self) -> Option<io::Result<u8>> { 55 match self.iter.next() { 56 None => None, 57 Some(Ok(b'\n')) => { 58 self.start_of_line += self.col + 1; 59 self.line += 1; 60 self.col = 0; 61 Some(Ok(b'\n')) 62 } 63 Some(Ok(c)) => { 64 self.col += 1; 65 Some(Ok(c)) 66 } 67 Some(Err(e)) => Some(Err(e)), 68 } 69 } 70 } 71