use std::io::{self, Write};
#[derive(Debug, Clone)]
pub enum Error {
Unspecified(&'static str),
}
enum PushGeneratorState {
Initial,
GeneratingMessage,
Error(Error),
}
pub struct PushGenerator<'a> {
target: &'a mut Write,
state: PushGeneratorState,
}
impl<'a> PushGenerator<'a> {
pub fn new<'x>(target: &'x mut Write) -> PushGenerator<'x> {
PushGenerator {
target: target,
state: PushGeneratorState::Initial,
}
}
pub fn next_message<'x, 'y: 'x+'y>(&'y mut self) -> Result<Message<'x, 'a>, Error> {
match self.state {
PushGeneratorState::Initial => {
self.state = PushGeneratorState::GeneratingMessage;
Ok(Message::new(self))
},
PushGeneratorState::GeneratingMessage => {
Err(Error::Unspecified("Finish message before starting a new one"))
},
PushGeneratorState::Error(ref err) => Err(err.clone())
}
}
}
enum MessageState {
BeforeFirstField,
AfterFirstField,
GeneratingField,
}
pub struct Message<'a, 'b: 'a+'b> {
target: &'a mut PushGenerator<'b>,
state: MessageState,
}
impl<'a, 'b> Message<'a, 'b> {
fn new<'x, 'y: 'x+'y>(target: &'x mut PushGenerator<'y>) -> Message<'x, 'y> {
Message {
target: target,
state: MessageState::BeforeFirstField,
}
}
pub fn next_field<'x, 'y: 'x+'y>(&'y mut self) -> Result<Field<'x, 'a, 'b>, Error> {
match self.state {
MessageState::BeforeFirstField => {
self.state = MessageState::GeneratingField;
Ok(Field::new(self))
},
MessageState::AfterFirstField => {
if let Err(_err) = self.target.target.write_all(&[' ' as u8]) { return Err(Error::Unspecified("Nested error")); }
self.state = MessageState::GeneratingField;
Ok(Field::new(self))
},
MessageState::GeneratingField =>
Err(Error::Unspecified("You must close the previous field before starting a new one"))
}
}
}
impl<'a, 'b> Drop for Message<'a, 'b> {
fn drop(&mut self) {
self.target.state = match self.target.target.write_all(&['\n' as u8]) {
Ok(()) => PushGeneratorState::Initial,
Err(_err) => PushGeneratorState::Error(Error::Unspecified("Nested error")),
}
}
}
pub struct Field<'a, 'b: 'a + 'b, 'c: 'b + 'c> {
target: &'a mut Message<'b, 'c>,
}
impl<'a, 'b, 'c> Field<'a, 'b, 'c> {
fn new<'x, 'y, 'z>(target: &'x mut Message<'y, 'z>) -> Field<'x, 'y, 'z> {
Field {
target: target,
}
}
}
impl<'a, 'b, 'c> Drop for Field<'a, 'b, 'c> {
fn drop(&mut self) {
self.target.state = MessageState::AfterFirstField;
}
}
impl<'a, 'b, 'c> Write for Field<'a, 'b, 'c> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.target.target.target.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.target.target.target.flush()
}
}
#[cfg(test)]
mod test {
use std::io::Write;
use pushgenerator::*;
#[test]
fn it_works() {
let mut buffer = Vec::<u8>::new();
{
let mut generator = PushGenerator::new(&mut buffer);
{
let mut message = generator.next_message().unwrap();
{
let mut field = message.next_field().unwrap();
field.write_all(b"0").unwrap();
}
{
let mut field = message.next_field().unwrap();
field.write_all(b"lol").unwrap();
}
}
}
assert_eq!(String::from("0 lol\n").into_bytes(), buffer);
}
}