ohmers 0.1.1

A library for retrieving and storing objects in a Redis server
extern crate redis;
extern crate rmp as msgpack;
extern crate rustc_serialize;

use std::ascii::AsciiExt;
use std::collections::{HashMap, HashSet};

#[derive(Debug, Clone, PartialEq)]
enum EncoderStatus {
    Normal,
    Id,
    Reference(String),
}

#[derive(Debug, Clone)]
pub struct Encoder {
    pub id: usize,
    pub id_field: String,
    pub features: HashMap<String, String>,
    pub attributes: Vec<String>,
    pub sets: HashSet<String>,
    pub lists: HashSet<String>,
    pub counters: HashSet<String>,
    status: EncoderStatus,
}

impl Encoder {
    pub fn new() -> Self {
        Encoder {
            id: 0,
            id_field: "".to_string(),
            features: HashMap::new(),
            attributes: vec![],
            counters: HashSet::new(),
            sets: HashSet::new(),
            lists: HashSet::new(),
            status: EncoderStatus::Normal,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum EncoderError {
    NotImplementedYet,
    MissingField,
    UnknownStruct(String),
    RedisError(redis::RedisError),
    MsgPackError,
}

impl From<redis::RedisError> for EncoderError {
    fn from(e: redis::RedisError) -> EncoderError {
        EncoderError::RedisError(e)
    }
}

impl From<msgpack::encode::serialize::Error> for EncoderError {
    fn from(_: msgpack::encode::serialize::Error) -> EncoderError {
        EncoderError::MsgPackError
    }
}

pub type EncodeResult<T> = Result<T, EncoderError>;

macro_rules! emit_fmt {
    ($enc: ident, $e: expr) => {{
        $enc.attributes.push(format!("{}", $e));
        Ok(())
    }}
}

impl rustc_serialize::Encoder for Encoder {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult<()> {
        self.attributes.pop();
        Ok(())
    }

    fn emit_usize(&mut self, v: usize) -> EncodeResult<()> {
        let s = format!("{}", v);
        match self.status {
            EncoderStatus::Normal => self.attributes.push(s),
            EncoderStatus::Id => {
                if s != "0" {
                    self.features.insert(self.id_field.clone(), s);
                }
                self.attributes.pop();
            }
            EncoderStatus::Reference(ref field) => {
                self.attributes.pop();
                self.attributes.push(format!("{}_id", &*field.to_ascii_lowercase()));
                self.attributes.push(s);
            }
        }
        self.status = EncoderStatus::Normal;
        Ok(())
    }

    fn emit_u64(&mut self, v: u64) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_u32(&mut self, v: u32) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_u16(&mut self, v: u16) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_u8(&mut self, v: u8) -> EncodeResult<()> { emit_fmt!(self, v) }

    fn emit_isize(&mut self, v: isize) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_i64(&mut self, v: i64) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_i32(&mut self, v: i32) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_i16(&mut self, v: i16) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_i8(&mut self, v: i8) -> EncodeResult<()> { emit_fmt!(self, v) }

    fn emit_bool(&mut self, v: bool) -> EncodeResult<()> { emit_fmt!(self, if v { 1 } else { 0 }) }

    fn emit_f64(&mut self, v: f64) -> EncodeResult<()> { emit_fmt!(self, v) }
    fn emit_f32(&mut self, v: f32) -> EncodeResult<()> { emit_fmt!(self, v) }

    fn emit_char(&mut self, v: char) -> EncodeResult<()> { emit_fmt!(self, v) }

    fn emit_str(&mut self, v: &str) -> EncodeResult<()> { emit_fmt!(self, v) }

    fn emit_enum<F>(&mut self, _: &str, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_enum_variant<F>(&mut self,
        _: &str,
        _: usize,
        _: usize,
        _: F)
        -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_enum_variant_arg<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_enum_struct_variant<F>(&mut self,
                                   _: &str,
                                   _: usize,
                                   _: usize,
                                   _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_enum_struct_variant_field<F>(&mut self,
                                         _: &str,
                                         _: usize,
                                         _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }


    fn emit_struct<F>(&mut self, name: &str, _: usize, f: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        if self.features.contains_key("name") {
            match name {
                "Reference" => self.status = EncoderStatus::Reference(try!(self.attributes.pop().ok_or(EncoderError::MissingField))),
                "Counter" => { self.counters.insert(try!(self.attributes.pop().ok_or(EncoderError::MissingField))); },
                "Set" => { self.sets.insert(try!(self.attributes.pop().ok_or(EncoderError::MissingField))); },
                "List" => { self.lists.insert(try!(self.attributes.pop().ok_or(EncoderError::MissingField))); },
                "Collection" => { try!(self.attributes.pop().ok_or(EncoderError::MissingField)); },
                _ => return Err(EncoderError::UnknownStruct(name.to_string())),
            }
            f(self)
        } else {
            self.features.insert("name".to_string(), name.to_string());
            f(self)
        }
    }

    fn emit_struct_field<F>(&mut self, name: &str, _: usize, f: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        if self.status == EncoderStatus::Normal && name == self.id_field {
            self.status = EncoderStatus::Id;
        } else {
            self.attributes.push(name.to_string());
        }
        f(self)
    }

    fn emit_tuple<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_tuple_arg<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_tuple_struct<F>(&mut self, _: &str, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }
    fn emit_tuple_struct_arg<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        f(self)
    }

    fn emit_option_none(&mut self) -> EncodeResult<()> {
        self.emit_nil()
    }

    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        f(self)
    }

    fn emit_seq<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_seq_elt<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_map<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_map_elt_key<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }

    fn emit_map_elt_val<F>(&mut self, _: usize, _: F) -> EncodeResult<()> where
        F: FnOnce(&mut Encoder) -> EncodeResult<()>,
    {
        Err(EncoderError::NotImplementedYet)
    }
}

pub fn msgpack_encode<T: rustc_serialize::Encodable>(t: &T) -> Result<Vec<u8>, EncoderError> {
    let mut buf = Vec::new();
    try!(t.encode(&mut msgpack::Encoder::new(&mut buf)));
    Ok(buf)
}