98 lines · 2.6 KB · Rust
RawDownload
use bstr::{BStr, BString, ByteSlice};use std::borrow::Cow; mod error {    use bstr::BString;    use quick_error::quick_error;     quick_error! {        #[derive(Debug)]        pub enum Error {            PatternNegation { line_number: usize, line: BString } {                display("Line {} has a negative pattern, for literal characters use \\!: {}", line_number, line)            }        }    }}use crate::ignore;pub use error::Error; pub struct Lines<'a> {    lines: bstr::Lines<'a>,    line_no: usize,} pub struct Iter<'a> {    attrs: bstr::Split<'a>,} impl<'a> Iter<'a> {    pub fn new(attrs: &'a [u8]) -> Self {        Iter {            attrs: attrs.as_bstr().split_str(b" "),        }    }} impl<'a> Iterator for Iter<'a> {    type Item = Result<(&'a BStr, crate::State<'a>), Error>;     fn next(&mut self) -> Option<Self::Item> {        let _attr = self.attrs.next().filter(|a| !a.is_empty())?;        todo!("parse attribute")    }} impl<'a> Lines<'a> {    pub fn new(buf: &'a [u8]) -> Self {        let bom = unicode_bom::Bom::from(buf);        Lines {            lines: buf[bom.len()..].lines(),            line_no: 0,        }    }} impl<'a> Iterator for Lines<'a> {    type Item = Result<(BString, crate::ignore::pattern::Mode, Iter<'a>, usize), Error>;     fn next(&mut self) -> Option<Self::Item> {        for line in self.lines.by_ref() {            self.line_no += 1;            match parse_line(line) {                None => continue,                Some(Ok((pattern, flags, attrs))) => {                    return Some(if flags.contains(ignore::pattern::Mode::NEGATIVE) {                        Err(Error::PatternNegation {                            line: line.into(),                            line_number: self.line_no,                        })                    } else {                        Ok((pattern, flags, attrs, self.line_no))                    })                }                Some(Err(err)) => return Some(Err(err)),            }        }        None    }} fn parse_line(line: &[u8]) -> Option<Result<(BString, crate::ignore::pattern::Mode, Iter<'_>), Error>> {    if line.is_empty() {        return None;    }     let (line, attrs): (Cow<'_, _>, _) = if line.starts_with(b"\"") {        todo!("unquote, need length of consumed bytes to know where attrs start")    } else {        let mut tokens = line.splitn(2, |n| *n == b' ');        (            tokens.next().expect("at least a line").into(),            tokens.next().unwrap_or_default(),        )    };     let (pattern, flags) = super::ignore::parse_line(line.as_ref())?;    Ok((pattern, flags, Iter::new(attrs))).into()}