plaintalk/
pushgenerator.rs

1use std::convert;
2use std::io::{self, Write};
3
4#[derive(Debug, Clone)]
5pub enum Error {
6// 	Io(io::Error),
7	Unspecified(&'static str),
8}
9
10impl convert::From<io::Error> for Error {
11	fn from(_err: io::Error) -> Error {
12// 		Error::Io(err)
13		Error::Unspecified("IO error")
14	}
15}
16
17enum PushGeneratorState {
18	Initial,
19	GeneratingMessage,
20	Error(Error),
21}
22
23pub struct PushGenerator<W: Write> {
24	inner: W,
25	state: PushGeneratorState,
26	auto_flush: bool,
27}
28
29impl<W: Write> PushGenerator<W> {
30	pub fn new(inner: W) -> PushGenerator<W> {
31		PushGenerator {
32			inner: inner,
33			state: PushGeneratorState::Initial,
34			auto_flush: true,
35		}
36	}
37
38	pub fn next_message<'x, 'y: 'x+'y>(&'y mut self) -> Result<Message<'x, W>, Error> {
39		match self.state {
40			PushGeneratorState::Initial => {
41				self.state = PushGeneratorState::GeneratingMessage;
42				Ok(Message::new(self))
43			},
44			PushGeneratorState::GeneratingMessage => {
45				Err(Error::Unspecified("Finish message before starting a new one"))
46			},
47			PushGeneratorState::Error(ref err) => Err(err.clone())
48		}
49	}
50
51	pub fn flush(&mut self) -> io::Result<()> {
52		self.inner.flush()
53	}
54
55	fn auto_flush(&self) -> bool {
56		self.auto_flush
57	}
58
59	pub fn write_message(&mut self, msg: &[&[u8]]) -> Result<(), Error> {
60		let mut message = try!{self.next_message()};
61		for &fieldbuf in msg {
62			try!{message.write_field(&fieldbuf)};
63		}
64		Ok(())
65	}
66}
67
68enum MessageState {
69	BeforeFirstField,
70	AfterFirstField,
71	GeneratingField,
72}
73
74pub struct Message<'a, W: 'a + Write> {
75	inner: &'a mut PushGenerator<W>,
76	state: MessageState,
77}
78
79impl<'a, W: Write> Message<'a, W> {
80	fn new(inner: &'a mut PushGenerator<W>) -> Message<'a, W> {
81		Message {
82			inner: inner,
83			state: MessageState::BeforeFirstField,
84		}
85	}
86
87	pub fn next_field<'x, 'y: 'x+'y>(&'y mut self) -> Result<Field<'x, 'a, W>, Error> {
88		match self.state {
89			MessageState::BeforeFirstField => {
90				self.state = MessageState::GeneratingField;
91				Ok(Field::new(self))
92			},
93			MessageState::AfterFirstField => {
94				// TODO Handle failure. Should the generator get into a failed
95				// state? Or are we able to try the same operation again?
96				if let Err(_err) = self.inner.inner.write_all(b" ") { return Err(Error::Unspecified("Nested error")); }
97				self.state = MessageState::GeneratingField;
98				Ok(Field::new(self))
99			},
100			MessageState::GeneratingField =>
101				Err(Error::Unspecified("You must close the previous field before starting a new one"))
102		}
103	}
104
105	pub fn flush(&mut self) -> io::Result<()> {
106		self.inner.inner.flush()
107	}
108
109	pub fn write_field(&mut self, buf: &[u8]) -> Result<(), Error> {
110		let mut field = try!{self.next_field()};
111		try!{field.write(buf)};
112		Ok(())
113	}
114}
115
116impl<'a, W: Write> Drop for Message<'a, W> {
117	fn drop(&mut self) {
118		self.inner.state = match self.inner.inner.write_all(&['\n' as u8]) {
119			Ok(()) => PushGeneratorState::Initial,
120			Err(_err) => PushGeneratorState::Error(Error::Unspecified("Nested error")),
121		};
122		if self.inner.auto_flush() {
123			if let Err(_err) = self.inner.inner.flush() {
124				self.inner.state = PushGeneratorState::Error(Error::Unspecified("Autoflush failed"));
125			}
126		}
127	}
128}
129
130pub struct Field<'a, 'b: 'a + 'b, W: 'b + Write> {
131	inner: &'a mut Message<'b, W>,
132	empty: bool,
133}
134
135impl<'a, 'b, W: Write> Field<'a, 'b, W> {
136	fn new(inner: &'a mut Message<'b, W>) -> Field<'a, 'b, W> {
137		Field {
138			inner: inner,
139			empty: true,
140		}
141	}
142}
143
144impl<'a, 'b, W: Write> Drop for Field<'a, 'b, W> {
145	fn drop(&mut self) {
146		if self.empty {
147			// TODO Handle errors. Should an error put the generator into a failed state?
148			let _ = self.inner.inner.inner.write(b"{0}");
149		}
150		self.inner.state = MessageState::AfterFirstField;
151	}
152}
153
154const CURLY_L: u8 = '{' as u8;
155const SP: u8 = ' ' as u8;
156const CR: u8 = '\r' as u8;
157const LF: u8 = '\n' as u8;
158
159fn should_escape(buf: &[u8]) -> bool {
160	if buf.len() > 100 {
161		true
162	} else {
163		buf.iter().position(|&x| x == CURLY_L || x == SP || x == CR || x == LF).is_some()
164	}
165}
166
167impl<'a, 'b, W: Write> Write for Field<'a, 'b, W> {
168	fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
169		// TODO Handle errors. Should an error put the generator into a failed state?
170
171		let inner_stream = &mut self.inner.inner.inner;
172		if should_escape(buf) {
173			try!{write!(inner_stream, "{{{}}}", buf.len())}
174		}
175		try!{inner_stream.write_all(buf)}
176		self.empty = self.empty && (buf.len() == 0);
177		Ok(buf.len())
178	}
179
180	fn flush(&mut self) -> io::Result<()> {
181		self.inner.inner.inner.flush()
182	}
183}
184
185#[cfg(test)]
186mod test {
187	use std::io::Write;
188	use pushgenerator::*;
189
190	#[test]
191	fn it_works() {
192		let mut buffer = Vec::new();
193
194		{
195			let mut generator = PushGenerator::new(&mut buffer);
196
197			{
198				let mut message = generator.next_message().unwrap();
199
200				{
201					let mut field = message.next_field().unwrap();
202					field.write_all(b"0").unwrap();
203				}
204
205				{
206					let mut field = message.next_field().unwrap();
207					field.write_all(b"lol").unwrap();
208				}
209			}
210		}
211
212		assert_eq!(b"0 lol\n".to_vec(), buffer);
213	}
214
215	#[test]
216	fn it_escapes_control_characters() {
217		let mut buffer = Vec::new();
218
219		{
220			let mut generator = PushGenerator::new(&mut buffer);
221
222			{
223				let mut message = generator.next_message().unwrap();
224
225				{
226					let mut field = message.next_field().unwrap();
227					field.write_all(b" ").unwrap();
228					field.write_all(b"\r").unwrap();
229					field.write_all(b"\n").unwrap();
230					field.write_all(b"{").unwrap();
231				}
232			}
233		}
234
235		assert_eq!(b"{1} {1}\r{1}\n{1}{\n".to_vec(), buffer);
236	}
237
238	#[test]
239	fn it_has_convenience_functions() {
240		let mut buffer = Vec::new();
241
242		{
243			let mut generator = PushGenerator::new(&mut buffer);
244
245			{
246				let mut message = generator.next_message().unwrap();
247				message.write_field(b"apekatt").unwrap();
248				message.write_field(b"katter ape").unwrap();
249			}
250
251			generator.write_message(&[b"0", b"error", b"success"]).unwrap();
252			generator.write_message(&[b"1"]).unwrap();
253		}
254
255		assert_eq!(b"apekatt {10}katter ape\n0 error success\n1\n".to_vec(), buffer);
256	}
257
258	#[test]
259	fn it_generates_escape_sequence_for_empty_fields() {
260		let mut buffer = Vec::new();
261
262		{
263			let mut generator = PushGenerator::new(&mut buffer);
264
265			generator.write_message(&[b"", b""]).unwrap();
266		}
267
268		assert_eq!(b"{0} {0}\n".to_vec(), buffer);
269	}
270}