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 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
pub trait PlainTalkParserListener { fn start_message(&self); fn end_message(&self); fn start_field(&self); fn field_data(&self, &[u8]); fn end_field(&self); } pub struct PlainTalkParser<'a> { pub listener: &'a PlainTalkParserListener, state: for<'b> fn(&mut PlainTalkParser<'a>, &'b [u8]) -> &'b [u8] } impl<'a> PlainTalkParser<'a> { pub fn new(listener: &'a PlainTalkParserListener) -> PlainTalkParser<'a> { PlainTalkParser { listener: listener, state: PlainTalkParser::expect_message } } pub fn eat_this(&mut self, s: &[u8]) { println!("eat_this {:?}", s); let mut rest = s; while rest.len() != 0 { rest = (self.state)(self, rest); } } fn expect_message<'b>(&mut self, s: &'b [u8]) -> &'b [u8] { self.listener.start_message(); self.state = PlainTalkParser::expect_field; s } fn expect_field<'b>(&mut self, s: &'b [u8]) -> &'b [u8] { self.listener.start_field(); self.state = PlainTalkParser::expect_field_data_or_end_of_field; s } fn expect_field_data_or_end_of_field<'b>(&mut self, s: &'b [u8]) -> &'b [u8] { match s.iter().position(|&x| x == b' ' || x == b'\n' || x == b'\r') { Some(0) => { match s[0] { b' ' => { self.listener.end_field(); self.listener.start_field(); }, b'\n' => { self.listener.end_field(); self.listener.end_message(); self.state = PlainTalkParser::expect_message; }, b'\r' => { self.listener.end_field(); self.listener.end_message(); self.state = PlainTalkParser::expect_line_feed; }, _ => panic!("A specific match should be found based on the search above") } &s[1..] }, Some(n) => { self.listener.field_data(&s[0..n]); &s[n..] }, None => { self.listener.field_data(s); &[] } } } fn expect_line_feed<'b>(&mut self, _s: &'b [u8]) -> &'b [u8] { panic!(); } } #[cfg(test)] mod test { use pushparser::*; struct TestPlainTalkParserListener; impl PlainTalkParserListener for TestPlainTalkParserListener { fn start_message(&self) { println!("start_message"); } fn end_message(&self) { println!("end_message"); } fn start_field(&self) { println!("start_field"); } fn field_data(&self, data:&[u8]) { println!("field_data {:?}", data); } fn end_field(&self) { println!("end_field"); } } #[test] fn it_works() { let listener = TestPlainTalkParserListener; let mut parser = PlainTalkParser::new(&listener); parser.eat_this(b"OMG POP\n"); parser.eat_this(b"korn"); parser.eat_this(b"flaeks\n"); } }