use std::str::Chars;
#[derive(Debug)]
pub struct Line<'a> {
contents: &'a str,
pub start: usize,
pub end: usize
}
impl<'a> Line<'a> {
pub fn new(contents: &'a str, start: usize, end: usize) -> Self {
Line{contents,start,end}
}
pub fn as_str(&self) -> &'a str {
&self.contents[self.start..self.end]
}
pub fn contains(&self,offset: usize) -> bool {
offset >= self.start && offset < self.end
}
}
pub struct LineIter<'a> {
contents: &'a str,
iter: Chars<'a>,
offset: usize
}
impl<'a> LineIter<'a> {
pub fn new(contents: &'a str) -> Self {
let iter = contents.chars();
LineIter{contents,iter,offset:0}
}
}
impl<'a> Iterator for LineIter<'a> {
type Item = Line<'a>;
fn next(&mut self) -> Option<Self::Item> {
let start = self.offset;
let mut cr;
match self.iter.next() {
Some('\n') => {
self.offset = self.offset + 1;
return Some(Line::new(self.contents,start,start));
}
Some(x) => { cr = x == '\r'; }
None => { return None; }
}
self.offset = self.offset + 1;
let mut end = start + 1;
loop {
self.offset = self.offset + 1;
match self.iter.next() {
Some('\n') => {
if cr { end = end - 1; }
break;
}
Some(x) => { cr = x == '\r'; }
None => break,
}
end = end + 1;
}
Some(Line::new(self.contents,start,end))
}
}
pub fn line_offsets<'a>(contents: &'a str) -> LineIter<'a> {
LineIter::new(contents)
}