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");
	}
}