From ee3dee8893f1b987f92198bfeda7a41b7d8f14d3 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 8 Jun 2014 15:17:18 -0700 Subject: [PATCH] Initial version of serialization. --- ser.rs | 574 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ serde.rs | 1 + 2 files changed, 575 insertions(+) create mode 100644 ser.rs diff --git a/ser.rs b/ser.rs new file mode 100644 index 00000000..6a7e8789 --- /dev/null +++ b/ser.rs @@ -0,0 +1,574 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::{HashMap, TreeMap}; +use std::hash::Hash; + +#[deriving(Clone, PartialEq, Show)] +pub enum Token<'a> { + Bool(bool), + Int(int), + I8(i8), + I16(i16), + I32(i32), + I64(i64), + Uint(uint), + U8(u8), + U16(u16), + U32(u32), + U64(u64), + F32(f32), + F64(f64), + Char(char), + Str(&'a str), + Option(bool), + + TupleStart(uint), + StructStart(&'a str, uint), + EnumStart(&'a str, &'a str, uint), + SeqStart(uint), + MapStart(uint), + + End, +} + +////////////////////////////////////////////////////////////////////////////// + +pub trait Serializer { + fn serialize<'a>(&mut self, token: Token<'a>) -> Result<(), E>; + + fn syntax_error(&self) -> Result; +} + +////////////////////////////////////////////////////////////////////////////// + +pub trait Serializable> { + fn serialize(&self, s: &mut S) -> Result<(), E>; +} + +////////////////////////////////////////////////////////////////////////////// + +macro_rules! impl_serializable { + ($ty:ty, $variant:expr) => { + impl<'a, E, S: Serializer> Serializable for $ty { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + s.serialize($variant) + } + } + } +} + +impl_serializable!(bool, Bool(*self)) +impl_serializable!(int, Int(*self)) +impl_serializable!(i8, I8(*self)) +impl_serializable!(i16, I16(*self)) +impl_serializable!(i32, I32(*self)) +impl_serializable!(i64, I64(*self)) +impl_serializable!(uint, Uint(*self)) +impl_serializable!(u8, U8(*self)) +impl_serializable!(u16, U16(*self)) +impl_serializable!(u32, U32(*self)) +impl_serializable!(u64, U64(*self)) +impl_serializable!(f32, F32(*self)) +impl_serializable!(f64, F64(*self)) +impl_serializable!(char, Char(*self)) +impl_serializable!(&'a str, Str(*self)) +impl_serializable!(String, Str(self.as_slice())) + +////////////////////////////////////////////////////////////////////////////// + +impl< + E, + S: Serializer, + T: Serializable +> Serializable for Option { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + match *self { + Some(ref value) => { + try!(s.serialize(Option(true))); + value.serialize(s) + } + None => { + s.serialize(Option(false)) + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl< + E, + S: Serializer, + T: Serializable +> Serializable for Vec { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(SeqStart(self.len()))); + for elt in self.iter() { + try!(elt.serialize(s)); + } + s.serialize(End) + } +} + +////////////////////////////////////////////////////////////////////////////// + +impl< + E, + S: Serializer, + K: Serializable + Eq + Hash, + V: Serializable +> Serializable for HashMap { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(MapStart(self.len()))); + for (key, value) in self.iter() { + try!(key.serialize(s)); + try!(value.serialize(s)); + } + s.serialize(End) + } +} + +impl< + E, + S: Serializer, + K: Serializable + Ord, + V: Serializable +> Serializable for TreeMap { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(MapStart(self.len()))); + for (key, value) in self.iter() { + try!(key.serialize(s)); + try!(value.serialize(s)); + } + s.serialize(End) + } +} + +////////////////////////////////////////////////////////////////////////////// + +macro_rules! peel { + ($name:ident, $($other:ident,)*) => (impl_serialize_tuple!($($other,)*)) +} + +macro_rules! impl_serialize_tuple { + () => { + impl< + E, + S: Serializer + > Serializable for () { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(TupleStart(0))); + s.serialize(End) + } + } + }; + ( $($name:ident,)+ ) => { + impl< + E, + S: Serializer, + $($name:Serializable),* + > Serializable for ($($name,)*) { + #[inline] + #[allow(uppercase_variables)] + fn serialize(&self, s: &mut S) -> Result<(), E> { + // FIXME: how can we count macro args? + let mut len = 0; + $({ let $name = 1; len += $name; })*; + + let ($(ref $name,)*) = *self; + + try!(s.serialize(TupleStart(len))); + $(try!($name.serialize(s));)* + s.serialize(End) + } + } + peel!($($name,)*) + } +} + +impl_serialize_tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } + +////////////////////////////////////////////////////////////////////////////// + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use serialize::Decoder; + + use super::{Token, Int, Uint, Str, Char, Option}; + use super::{TupleStart, StructStart, EnumStart}; + use super::{SeqStart, MapStart, End}; + use super::{Serializer, Serializable}; + + ////////////////////////////////////////////////////////////////////////////// + + #[deriving(Clone, PartialEq, Show, Decodable)] + struct Inner { + a: (), + b: uint, + c: HashMap>, + } + + impl> Serializable for Inner { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(StructStart("Inner", 3))); + try!(s.serialize(Str("a"))); + try!(self.a.serialize(s)); + try!(s.serialize(Str("b"))); + try!(self.b.serialize(s)); + try!(s.serialize(Str("c"))); + try!(self.c.serialize(s)); + s.serialize(End) + } + } + + ////////////////////////////////////////////////////////////////////////////// + + #[deriving(Clone, PartialEq, Show, Decodable)] + struct Outer { + inner: Vec, + } + + impl> Serializable for Outer { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + try!(s.serialize(StructStart("Outer", 1))); + try!(s.serialize(Str("inner"))); + try!(self.inner.serialize(s)); + s.serialize(End) + } + } + + ////////////////////////////////////////////////////////////////////////////// + + #[deriving(Clone, PartialEq, Show, Decodable)] + enum Animal { + Dog, + Frog(String, int) + } + + impl> Serializable for Animal { + #[inline] + fn serialize(&self, s: &mut S) -> Result<(), E> { + match *self { + Dog => { + try!(s.serialize(EnumStart("Animal", "Dog", 0))); + } + Frog(ref x, y) => { + try!(s.serialize(EnumStart("Animal", "Frog", 2))); + try!(x.serialize(s)); + try!(y.serialize(s)); + } + } + s.serialize(End) + } + } + + ////////////////////////////////////////////////////////////////////////////// + + #[deriving(Show)] + enum Error { + EndOfStream, + SyntaxError, + } + + ////////////////////////////////////////////////////////////////////////////// + + struct AssertSerializer { + iter: Iter, + } + + impl<'a, Iter: Iterator>> AssertSerializer { + #[inline] + fn new(iter: Iter) -> AssertSerializer { + AssertSerializer { + iter: iter, + } + } + } + + impl<'a, Iter: Iterator>> Serializer for AssertSerializer { + #[inline] + fn serialize<'b>(&mut self, token: Token<'b>) -> Result<(), Error> { + let t = match self.iter.next() { + Some(t) => t, + None => { fail!(); } + }; + + assert_eq!(t, token); + + Ok(()) + } + + fn syntax_error(&self) -> Result { + Err(SyntaxError) + } + } + + ////////////////////////////////////////////////////////////////////////////// + + #[test] + fn test_tokens_int() { + let tokens = vec!( + Int(5) + ); + let mut serializer = AssertSerializer::new(tokens.move_iter()); + 5i.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_str() { + let tokens = vec!( + Str("a"), + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + "a".serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_null() { + let tokens = vec!( + TupleStart(0), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + ().serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_option_none() { + let tokens = vec!( + Option(false), + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + None::.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_option_some() { + let tokens = vec!( + Option(true), + Int(5), + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + Some(5).serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_tuple() { + let tokens = vec!( + TupleStart(2), + Int(5), + Str("a"), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + (5, "a").serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_tuple_compound() { + let tokens = vec!( + TupleStart(3), + TupleStart(0), + End, + + TupleStart(0), + End, + + TupleStart(2), + Int(5), + Str("a"), + End, + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + ((), (), (5, "a")).serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_struct_empty() { + let tokens = vec!( + StructStart("Outer", 1), + Str("inner"), + SeqStart(0), + End, + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + Outer { inner: vec!() }.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_struct() { + let tokens = vec!( + StructStart("Outer", 1), + Str("inner"), + SeqStart(1), + StructStart("Inner", 3), + Str("a"), + TupleStart(0), + End, + + Str("b"), + Uint(5), + + Str("c"), + MapStart(1), + Str("abc"), + + Option(true), + Char('c'), + End, + End, + End, + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + + let mut map = HashMap::new(); + map.insert("abc".to_string(), Some('c')); + + Outer { + inner: vec!( + Inner { + a: (), + b: 5, + c: map, + }, + ) + }.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_enum() { + let tokens = vec!( + EnumStart("Animal", "Dog", 0), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + Dog.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + + let tokens = vec!( + EnumStart("Animal", "Frog", 2), + Str("Henry"), + Int(349), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + Frog("Henry".to_string(), 349).serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_vec_empty() { + let tokens = vec!( + SeqStart(0), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + let v: Vec = vec!(); + v.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_vec() { + let tokens = vec!( + SeqStart(3), + Int(5), + Int(6), + Int(7), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + (vec!(5, 6, 7)).serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_vec_compound() { + let tokens = vec!( + SeqStart(3), + SeqStart(1), + Int(1), + End, + + SeqStart(2), + Int(2), + Int(3), + End, + + SeqStart(3), + Int(4), + Int(5), + Int(6), + End, + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + (vec!(vec!(1), vec!(2, 3), vec!(4, 5, 6))).serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } + + #[test] + fn test_tokens_hashmap() { + let tokens = vec!( + MapStart(2), + Int(5), + Str("a"), + + Int(6), + Str("b"), + End, + ); + + let mut serializer = AssertSerializer::new(tokens.move_iter()); + + let mut map = HashMap::new(); + map.insert(5, "a".to_string()); + map.insert(6, "b".to_string()); + + map.serialize(&mut serializer).unwrap(); + assert_eq!(serializer.iter.next(), None); + } +} diff --git a/serde.rs b/serde.rs index 433776ac..e079a3f5 100644 --- a/serde.rs +++ b/serde.rs @@ -14,6 +14,7 @@ extern crate debug; extern crate serialize; pub mod de; +pub mod ser; pub mod json; //#[cfg(test)]