use std::mem::replace; use std::collections::HashMap; use super::{Object, Props}; use super::tokenizer::{Tokenizer, Token}; pub struct Parser { tokenizer: Tokenizer, object_name: Option, current_key: Option, current_prop: Option, props: Props, content: HashMap, } impl Parser { pub fn new() -> Self { Parser { tokenizer: Tokenizer::new(), object_name: None, current_key: None, current_prop: None, props: vec![], content: HashMap::new(), } } pub fn feed(&mut self, input: &'_ [u8], mut f: F) where F: FnMut(Object), { let current_key = &mut self.current_key; let current_prop = &mut self.current_prop; let props = &mut self.props; let object_name = &mut self.object_name; let content = &mut self.content; self.tokenizer.feed(input, |token| { match token { Token::Key(key) => *current_key = Some(key), Token::PropName(name) => *current_prop = Some(name), Token::PropValue(value) => { current_prop.take().map(|name| { props.push((name, value)); }); } Token::Value(value) => { fn compare(s1: &Option, s2: &str) -> bool { s1.as_ref().map(|s1| s1 == s2).unwrap_or(s2.len() == 0) } if compare(current_key, "BEGIN") { *object_name = Some(value); content.clear(); } else if compare(current_key, "END") { let object_name = replace(object_name, None); let content = replace(content, HashMap::new()); object_name.map(|name| f(Object { name, content })); } else { let props = replace(props, vec![]); let key = replace(current_key, None); key.map(|key| content.insert(key, (props, value))); } } } }); } } #[cfg(test)] mod test { use super::*; #[test] fn parse_event() { let mut p = Parser::new(); let mut obj = None; p.feed(b"BEGIN:VEVENT SUMMARY:Test event DTSTART:19700101 END:VEVENT ", |o| { assert!(obj.is_none()); obj = Some(o); }); assert_eq!(obj, Some(Object { name: "VEVENT".to_owned(), content: [("SUMMARY", "Test event"), ("DTSTART", "19700101")] .iter() .cloned() .map(|(k, v)| (k.to_owned(), (vec![], v.to_owned()))) .collect(), })); } }