plaintalk 0.0.1

A library for parsing and generating PlainTalk
Documentation
pub mod plaintalk {
	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 plaintalk;

	struct TestPlainTalkParserListener;

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

	use plaintalk::PlainTalkParserListener;
	use plaintalk::PlainTalkParser;
	#[test]
	fn it_works() {
		let listener = TestPlainTalkParserListener;
		let mut parser = plaintalk::PlainTalkParser::new(&listener);
		parser.eat_this(b"OMG POP\n");
		parser.eat_this(b"korn");
		parser.eat_this(b"flaeks\n");
	}
}