1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
use crate::error::Result; use regex::Regex; use std::collections::VecDeque; use std::io::BufRead; pub enum Token { Matched(usize, String), Unmatched(String), Undecided(String), } pub struct TokenStream<R: BufRead> { input: R, cache: VecDeque<Token>, regs: Vec<Regex>, } impl<R: BufRead> TokenStream<R> { pub fn new(input: R, regs: Vec<Regex>) -> Self { Self { input, cache: VecDeque::new(), regs, } } fn earliest_match<'a>(&self, input: &'a str) -> Option<(usize, &'a str, &'a str, &'a str)> { let output = self .regs .iter() .enumerate() .filter_map(|(n, re)| re.find(input).map(|m| (m.start(), m.end(), n))) .min(); output .map(|(start, end, color)| (color, &input[..start], &input[start..end], &input[end..])) } fn parse_string(&mut self, s: &str) -> Option<Token> { let output = self.earliest_match(s); if let Some((color, left, mid, right)) = output { if left.is_empty() { self.cache.push_back(Token::Undecided(right.to_string())); Some(Token::Matched(0, mid.to_string())) } else { self.cache.push_back(Token::Matched(color, mid.to_string())); self.cache.push_back(Token::Undecided(right.to_string())); Some(Token::Unmatched(left.to_string())) } } else { Some(Token::Unmatched(s.to_string())) } } } impl<R: BufRead> Iterator for TokenStream<R> { type Item = Token; fn next(&mut self) -> Option<Self::Item> { let s = { match self.cache.pop_front() { t @ Some(Token::Matched(..)) | t @ Some(Token::Unmatched(_)) => return t, Some(Token::Undecided(s)) => s, None => { let mut s: String = String::new(); match self.input.read_line(&mut s) { Err(e) => Err(e).expect("failed to parse"), Ok(0) => return None, Ok(_) => (), } s } } }; self.parse_string(&s) } }