lsonar 0.2.4

Lua 5.3 pattern engine, fully compatible with the original Lua 5.3 engine
Documentation
use crate::{AstNode, Result, engine::find_first_match};

pub struct GMatchIterator {
    pub(super) bytes: Vec<u8>,
    pub(super) pattern_ast: Vec<AstNode>,
    pub(super) current_pos: usize,
    pub(super) is_empty_pattern: bool,
}

impl Iterator for GMatchIterator {
    type Item = Result<Vec<String>>;

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

        if self.is_empty_pattern {
            let result = Some(Ok(vec![String::new()]));

            self.current_pos += 1;

            return result;
        }

        match find_first_match(&self.pattern_ast, &self.bytes, self.current_pos) {
            Ok(Some((match_range, captures))) => {
                if match_range.start == match_range.end {
                    self.current_pos = match_range.end + 1;
                    if self.current_pos > self.bytes.len() {
                        return None;
                    }
                } else {
                    self.current_pos = match_range.end;
                }

                let result: Vec<String> = if captures.iter().any(|c| c.is_some()) {
                    captures
                        .into_iter()
                        .filter_map(|maybe_range| {
                            maybe_range.map(|range| {
                                String::from_utf8_lossy(&self.bytes[range]).into_owned()
                            })
                        })
                        .collect()
                } else {
                    vec![
                        String::from_utf8_lossy(&self.bytes[match_range.start..match_range.end])
                            .into_owned(),
                    ]
                };

                Some(Ok(result))
            }
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}