From b206032ff15ca01317e5117f6b88ead99e47b9e0 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 1 Jul 2015 15:21:26 -0700 Subject: [PATCH] Initial support for serde serialization --- src/lib.rs | 11 + src/writer_serde.rs | 675 ++++++++++++++++++++++++++++++++++++++++++++ tests/test.rs | 4 +- tests/test_serde.rs | 337 ++++++++++++++++++++++ 4 files changed, 1025 insertions(+), 2 deletions(-) create mode 100644 src/writer_serde.rs create mode 100644 tests/test_serde.rs diff --git a/src/lib.rs b/src/lib.rs index a9a1a6f..bcea473 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ extern crate rustc_serialize; extern crate byteorder; +extern crate serde; use rustc_serialize::{Encodable, Decodable}; @@ -39,12 +40,22 @@ pub use refbox::{RefBox, StrBox, SliceBox}; pub use writer::{EncoderWriter, EncodingResult, EncodingError}; pub use reader::{DecoderReader, DecodingResult, DecodingError}; use writer::SizeChecker; +pub use writer_serde::{ + Serializer, + SerializeResult, + SerializeError, + to_writer, + to_vec, + serialized_size, + serialized_size_bounded, +}; use std::io::{Write, Read}; mod writer; mod reader; mod refbox; +mod writer_serde; /// A limit on the amount of bytes that can be read or written. /// diff --git a/src/writer_serde.rs b/src/writer_serde.rs new file mode 100644 index 0000000..7ece01c --- /dev/null +++ b/src/writer_serde.rs @@ -0,0 +1,675 @@ +use std::error::Error; +use std::fmt; +use std::io::Error as IoError; +use std::io::ErrorKind as IoErrorKind; +use std::io::Write; +use std::u32; +use std::u64; + +use serde; + +use byteorder::{BigEndian, WriteBytesExt}; +use byteorder::Error as ByteOrderError; + +use super::SizeLimit; + +pub type SerializeResult = Result; + + +/// An error that can be produced during encoding. +#[derive(Debug)] +pub enum SerializeError { + /// An error originating from the underlying `Writer`. + IoError(IoError), + /// An object could not be encoded with the given size limit. + /// + /// This error is returned before any bytes are written to the + /// output `Writer`. + SizeLimit +} + +/// An Serializer that encodes values directly into a Writer. +/// +/// This struct should not be used often. +/// For most cases, prefer the `encode_into` function. +pub struct Serializer<'a, W: 'a> { + writer: &'a mut W, +} + +fn wrap_io(err: ByteOrderError) -> SerializeError { + match err { + ByteOrderError::Io(ioe) => SerializeError::IoError(ioe), + ByteOrderError::UnexpectedEOF => SerializeError::IoError( + IoError::new(IoErrorKind::Other, + "ByteOrder could not write to the buffer")) + } +} + +impl fmt::Display for SerializeError { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match *self { + SerializeError::IoError(ref err) => write!(f, "IoError: {}", err), + SerializeError::SizeLimit => write!(f, "SizeLimit") + } + } +} + +impl Error for SerializeError { + fn description(&self) -> &str { + match *self { + SerializeError::IoError(ref err) => Error::description(err), + SerializeError::SizeLimit => "the size limit for decoding has been reached" + } + } + + fn cause(&self) -> Option<&Error> { + match *self { + SerializeError::IoError(ref err) => err.cause(), + SerializeError::SizeLimit => None + } + } +} + +impl<'a, W: Write> Serializer<'a, W> { + pub fn new(w: &'a mut W) -> Serializer<'a, W> { + Serializer { + writer: w, + } + } + + fn add_enum_tag(&mut self, tag: usize) -> SerializeResult<()> { + if tag > u32::MAX as usize { + panic!("Variant tag doesn't fit in a u32") + } + + serde::Serializer::visit_u32(self, tag as u32) + } +} + +impl<'a, W: Write> serde::Serializer for Serializer<'a, W> { + type Error = SerializeError; + + fn visit_unit(&mut self) -> SerializeResult<()> { Ok(()) } + + fn visit_bool(&mut self, v: bool) -> SerializeResult<()> { + self.writer.write_u8(if v {1} else {0}).map_err(wrap_io) + } + + fn visit_u8(&mut self, v: u8) -> SerializeResult<()> { + self.writer.write_u8(v).map_err(wrap_io) + } + + fn visit_u16(&mut self, v: u16) -> SerializeResult<()> { + self.writer.write_u16::(v).map_err(wrap_io) + } + + fn visit_u32(&mut self, v: u32) -> SerializeResult<()> { + self.writer.write_u32::(v).map_err(wrap_io) + } + + fn visit_u64(&mut self, v: u64) -> SerializeResult<()> { + self.writer.write_u64::(v).map_err(wrap_io) + } + + fn visit_i8(&mut self, v: i8) -> SerializeResult<()> { + self.writer.write_i8(v).map_err(wrap_io) + } + + fn visit_i16(&mut self, v: i16) -> SerializeResult<()> { + self.writer.write_i16::(v).map_err(wrap_io) + } + + fn visit_i32(&mut self, v: i32) -> SerializeResult<()> { + self.writer.write_i32::(v).map_err(wrap_io) + } + + fn visit_i64(&mut self, v: i64) -> SerializeResult<()> { + self.writer.write_i64::(v).map_err(wrap_io) + } + + fn visit_f32(&mut self, v: f32) -> SerializeResult<()> { + self.writer.write_f32::(v).map_err(wrap_io) + } + + fn visit_f64(&mut self, v: f64) -> SerializeResult<()> { + self.writer.write_f64::(v).map_err(wrap_io) + } + + fn visit_str(&mut self, v: &str) -> SerializeResult<()> { + try!(self.visit_usize(v.len())); + self.writer.write_all(v.as_bytes()).map_err(SerializeError::IoError) + } + + fn visit_none(&mut self) -> SerializeResult<()> { + self.writer.write_u8(0).map_err(wrap_io) + } + + fn visit_some(&mut self, v: T) -> SerializeResult<()> + where T: serde::Serialize, + { + try!(self.writer.write_u8(1).map_err(wrap_io)); + v.serialize(self) + } + + fn visit_seq(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + let len = match visitor.len() { + Some(len) => len, + None => panic!("do not know how to serialize a sequence with no length"), + }; + + try!(self.visit_usize(len)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_tuple(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_named_seq(&mut self, _name: &str, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_seq_elt(&mut self, value: V) -> SerializeResult<()> + where V: serde::Serialize, + { + value.serialize(self) + } + + fn visit_map(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + let len = match visitor.len() { + Some(len) => len, + None => panic!("do not know how to serialize a map with no length"), + }; + + try!(self.visit_usize(len)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_map_elt(&mut self, key: K, value: V) -> SerializeResult<()> + where K: serde::Serialize, + V: serde::Serialize, + { + try!(key.serialize(self)); + value.serialize(self) + } + + fn visit_named_map(&mut self, _name: &str, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_named_map_elt(&mut self, _key: K, value: V) -> SerializeResult<()> + where K: serde::Serialize, + V: serde::Serialize, + { + value.serialize(self) + } + + fn visit_enum_unit(&mut self, + _name: &str, + variant_index: usize, + _variant: &str) -> SerializeResult<()> { + self.add_enum_tag(variant_index) + } + + fn visit_enum_seq(&mut self, + _name: &str, + variant_index: usize, + _variant: &str, + mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + try!(self.add_enum_tag(variant_index)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_enum_map(&mut self, + _name: &str, + variant_index: usize, + _variant: &str, + mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + try!(self.add_enum_tag(variant_index)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } +} + +struct SizeChecker { + size_limit: u64, + written: u64 +} + +impl SizeChecker { + fn new(limit: u64) -> SizeChecker { + SizeChecker { + size_limit: limit, + written: 0 + } + } + + fn add_raw(&mut self, size: usize) -> SerializeResult<()> { + self.written += size as u64; + if self.written <= self.size_limit { + Ok(()) + } else { + Err(SerializeError::SizeLimit) + } + } + + fn add_value(&mut self, t: T) -> SerializeResult<()> { + use std::mem::size_of_val; + self.add_raw(size_of_val(&t)) + } + + fn add_enum_tag(&mut self, tag: usize) -> SerializeResult<()> { + if tag > u32::MAX as usize { + panic!("Variant tag doesn't fit in a u32") + } + + self.add_value(tag as u32) + } +} + +impl serde::Serializer for SizeChecker { + type Error = SerializeError; + + fn visit_unit(&mut self) -> SerializeResult<()> { Ok(()) } + + fn visit_bool(&mut self, _: bool) -> SerializeResult<()> { + self.add_value(0 as u8) + } + + fn visit_u8(&mut self, v: u8) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_u16(&mut self, v: u16) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_u32(&mut self, v: u32) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_u64(&mut self, v: u64) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_i8(&mut self, v: i8) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_i16(&mut self, v: i16) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_i32(&mut self, v: i32) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_i64(&mut self, v: i64) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_f32(&mut self, v: f32) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_f64(&mut self, v: f64) -> SerializeResult<()> { + self.add_value(v) + } + + fn visit_str(&mut self, v: &str) -> SerializeResult<()> { + try!(self.add_value(0 as u64)); + self.add_raw(v.len()) + } + + fn visit_none(&mut self) -> SerializeResult<()> { + self.add_value(0 as u8) + } + + fn visit_some(&mut self, v: T) -> SerializeResult<()> + where T: serde::Serialize, + { + try!(self.add_value(1 as u8)); + v.serialize(self) + } + + fn visit_seq(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + let len = match visitor.len() { + Some(len) => len, + None => panic!("do not know how to serialize a sequence with no length"), + }; + + try!(self.visit_usize(len)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_tuple(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_named_seq(&mut self, _name: &str, visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + self.visit_tuple(visitor) + } + + fn visit_seq_elt(&mut self, value: V) -> SerializeResult<()> + where V: serde::Serialize, + { + value.serialize(self) + } + + fn visit_map(&mut self, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + let len = match visitor.len() { + Some(len) => len, + None => panic!("do not know how to serialize a map with no length"), + }; + + try!(self.visit_usize(len)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_map_elt(&mut self, key: K, value: V) -> SerializeResult<()> + where K: serde::Serialize, + V: serde::Serialize, + { + try!(key.serialize(self)); + value.serialize(self) + } + + fn visit_named_map(&mut self, _name: &str, mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_named_map_elt(&mut self, _key: K, value: V) -> SerializeResult<()> + where K: serde::Serialize, + V: serde::Serialize, + { + value.serialize(self) + } + + fn visit_enum_unit(&mut self, + _name: &str, + variant_index: usize, + _variant: &str) -> SerializeResult<()> { + self.add_enum_tag(variant_index) + } + + fn visit_enum_seq(&mut self, + _name: &str, + variant_index: usize, + _variant: &str, + mut visitor: V) -> SerializeResult<()> + where V: serde::ser::SeqVisitor, + { + try!(self.add_enum_tag(variant_index)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + fn visit_enum_map(&mut self, + _name: &str, + variant_index: usize, + _variant: &str, + mut visitor: V) -> SerializeResult<()> + where V: serde::ser::MapVisitor, + { + try!(self.add_enum_tag(variant_index)); + + while let Some(()) = try!(visitor.visit(self)) { } + + Ok(()) + } + + + + + /* + type Error = SerializeError; + + fn emit_nil(&mut self) -> SerializeResult<()> { Ok(()) } + fn emit_usize(&mut self, v: usize) -> SerializeResult<()> { + self.add_value(v as u64) + } + fn emit_u64(&mut self, v: u64) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_u32(&mut self, v: u32) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_u16(&mut self, v: u16) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_u8(&mut self, v: u8) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_isize(&mut self, v: isize) -> SerializeResult<()> { + self.add_value(v as i64) + } + fn emit_i64(&mut self, v: i64) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_i32(&mut self, v: i32) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_i16(&mut self, v: i16) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_i8(&mut self, v: i8) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_bool(&mut self, _: bool) -> SerializeResult<()> { + self.add_value(0 as u8) + } + fn emit_f64(&mut self, v: f64) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_f32(&mut self, v: f32) -> SerializeResult<()> { + self.add_value(v) + } + fn emit_char(&mut self, v: char) -> SerializeResult<()> { + self.add_raw(v.len_utf8()) + } + fn emit_str(&mut self, v: &str) -> SerializeResult<()> { + try!(self.add_value(0 as u64)); + self.add_raw(v.len()) + } + fn emit_enum(&mut self, __: &str, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_enum_variant(&mut self, _: &str, + v_id: usize, + _: usize, + f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + try!(self.add_value(v_id as u32)); + f(self) + } + fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_enum_struct_variant(&mut self, _: &str, + _: usize, + _: usize, + f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_enum_struct_variant_field(&mut self, + _: &str, + _: usize, + f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_struct(&mut self, _: &str, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_struct_field(&mut self, _: &str, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_tuple(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_tuple_arg(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + self.emit_tuple(len, f) + } + fn emit_tuple_struct_arg(&mut self, f_idx: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + self.emit_tuple_arg(f_idx, f) + } + fn emit_option(&mut self, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_option_none(&mut self) -> SerializeResult<()> { + self.add_value(0 as u8) + } + fn emit_option_some(&mut self, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + try!(self.add_value(1 as u8)); + f(self) + } + fn emit_seq(&mut self, len: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + try!(self.emit_usize(len)); + f(self) + } + fn emit_seq_elt(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_map(&mut self, len: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + try!(self.emit_usize(len)); + f(self) + } + fn emit_map_elt_key(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + fn emit_map_elt_val(&mut self, _: usize, f: F) -> SerializeResult<()> where + F: FnOnce(&mut SizeChecker) -> SerializeResult<()> { + f(self) + } + */ +} + +pub fn to_writer(writer: &mut W, + value: &T, + size_limit: SizeLimit) -> SerializeResult<()> + where W: Write, + T: serde::Serialize, +{ + match size_limit { + SizeLimit::Infinite => { } + SizeLimit::Bounded(x) => { + let mut size_checker = SizeChecker::new(x); + try!(value.serialize(&mut size_checker)) + } + } + + let mut serializer = Serializer::new(writer); + serde::Serialize::serialize(value, &mut serializer) +} + +pub fn to_vec(value: &T, size_limit: SizeLimit) -> SerializeResult> + where T: serde::Serialize, +{ + // Since we are putting values directly into a vector, we can do size + // computation out here and pre-allocate a buffer of *exactly* + // the right size. + let mut writer = match size_limit { + SizeLimit::Bounded(size_limit) => { + let actual_size = match serialized_size_bounded(value, size_limit) { + Some(actual_size) => actual_size, + None => { return Err(SerializeError::SizeLimit); } + }; + Vec::with_capacity(actual_size as usize) + } + SizeLimit::Infinite => Vec::new() + }; + + try!(to_writer(&mut writer, value, SizeLimit::Infinite)); + Ok(writer) +} + +/// Returns the size that an object would be if serialized using bincode. +/// +/// This is used internally as part of the check for encode_into, but it can +/// be useful for preallocating buffers if thats your style. +pub fn serialized_size(value: &T) -> u64 { + let mut size_checker = SizeChecker::new(u64::MAX); + value.serialize(&mut size_checker).ok(); + size_checker.written +} + +/// Given a maximum size limit, check how large an object would be if it +/// were to be serialized. +/// +/// If it can be serialized in `max` or fewer bytes, that number will be returned +/// inside `Some`. If it goes over bounds, then None is returned. +pub fn serialized_size_bounded(value: &T, max: u64) -> Option { + let mut size_checker = SizeChecker::new(max); + value.serialize(&mut size_checker).ok().map(|_| size_checker.written) +} diff --git a/tests/test.rs b/tests/test.rs index 77326cb..f3f8580 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -40,8 +40,8 @@ fn the_same(element: V) let size = encoded_size(&element); let encoded = encode(&element, Infinite).unwrap(); let decoded = decode(&encoded[..]).unwrap(); - assert!(element == decoded); - assert!(size == encoded.len() as u64); + assert_eq!(element, decoded); + assert_eq!(size, encoded.len() as u64); assert!(ref_box_correct(&element)) } diff --git a/tests/test_serde.rs b/tests/test_serde.rs new file mode 100644 index 0000000..4888908 --- /dev/null +++ b/tests/test_serde.rs @@ -0,0 +1,337 @@ +#![feature(plugin, custom_derive)] +#![plugin(serde_macros)] + +extern crate bincode; +extern crate rustc_serialize; +extern crate serde; + +use std::fmt::Debug; +use std::collections::HashMap; +use std::ops::Deref; + +use rustc_serialize::{Encoder, Decoder, Encodable, Decodable}; + +use bincode::{ + encode, + decode, + decode_from, + encoded_size, + DecodingError, + DecodingResult, + RefBox, + StrBox, + SliceBox, +}; + +use bincode::SizeLimit::{Infinite, Bounded}; + +fn the_same(element: V) + where V: Encodable+Decodable+serde::Serialize+PartialEq+Debug+'static +{ + + // Make sure that the bahavior isize correct when wrapping with a RefBox. + fn ref_box_correct(v: &V) -> bool + where V: Encodable+Decodable+PartialEq+Debug+'static + { + let rf = RefBox::new(v); + + let encoded = encode(&rf, Infinite).unwrap(); + let decoded: RefBox<'static, V> = decode(&encoded[..]).unwrap(); + + decoded.take().deref() == v + } + + let size = encoded_size(&element); + let encoded = encode(&element, Infinite).unwrap(); + let decoded = decode(&encoded[..]).unwrap(); + assert_eq!(element, decoded); + assert_eq!(size, encoded.len() as u64); + assert!(ref_box_correct(&element)); + + let size = bincode::serialized_size(&element); + let serialized = bincode::to_vec(&element, Infinite).unwrap(); + assert_eq!(encoded, serialized); + assert_eq!(size, serialized.len() as u64); +} + +#[test] +fn test_numbers() { + // unsigned positive + the_same(5u8); + the_same(5u16); + the_same(5u32); + the_same(5u64); + // signed positive + the_same(5i8); + the_same(5i16); + the_same(5i32); + the_same(5i64); + // signed negative + the_same(-5i8); + the_same(-5i16); + the_same(-5i32); + the_same(-5i64); + // floating + the_same(-100f32); + the_same(0f32); + the_same(5f32); + the_same(-100f64); + the_same(5f64); +} + +#[test] +fn test_string() { + the_same("".to_string()); + the_same("a".to_string()); +} + +#[test] +fn test_tuple() { + the_same((1isize,)); + the_same((1isize,2isize,3isize)); + the_same((1isize,"foo".to_string(),())); +} + +#[test] +fn test_basic_struct() { + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + struct Easy { + x: isize, + s: String, + y: usize + } + the_same(Easy{x: -4, s: "foo".to_string(), y: 10}); +} + +#[test] +fn test_nested_struct() { + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + struct Easy { + x: isize, + s: String, + y: usize + } + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + struct Nest { + f: Easy, + b: usize, + s: Easy + } + + the_same(Nest { + f: Easy {x: -1, s: "foo".to_string(), y: 20}, + b: 100, + s: Easy {x: -100, s: "bar".to_string(), y: 20} + }); +} + +#[test] +fn test_struct_tuple() { + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + struct TubStr(usize, String, f32); + + the_same(TubStr(5, "hello".to_string(), 3.2)); +} + +#[test] +fn option() { + the_same(Some(5usize)); + the_same(Some("foo bar".to_string())); + the_same(None::); +} + +#[test] +fn enm() { + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + enum TestEnum { + NoArg, + OneArg(usize), + AnotherNoArg + } + the_same(TestEnum::NoArg); + the_same(TestEnum::OneArg(4)); + the_same(TestEnum::AnotherNoArg); +} + + +#[test] +fn struct_enum() { + #[derive(RustcEncodable, RustcDecodable, Serialize, PartialEq, Debug)] + enum TestEnum { + NoArg, + OneArg(usize), + AnotherNoArg, + StructLike{x: usize, y: f32} + } + the_same(TestEnum::NoArg); + the_same(TestEnum::OneArg(4)); + the_same(TestEnum::AnotherNoArg); + the_same(TestEnum::StructLike{x: 4, y: 3.14159}); + the_same(vec![TestEnum::NoArg, TestEnum::OneArg(5), TestEnum::AnotherNoArg, + TestEnum::StructLike{x: 4, y:1.4}]); +} + +#[test] +fn many() { + let v: Vec = vec![]; + the_same(v); + the_same(vec![1u64]); + the_same(vec![1u64,2,3,4,5,6]); +} + +#[test] +fn map() { + let mut m = HashMap::new(); + m.insert(4u64, "foo".to_string()); + m.insert(0u64, "bar".to_string()); + the_same(m); +} + +#[test] +fn boole() { + the_same(true); + the_same(false); +} + +#[test] +fn unicode() { + the_same("å".to_string()); + the_same("aåååååååa".to_string()); +} + + +#[test] +fn decoding_errors() { + fn isize_invalid_encoding(res: DecodingResult) { + match res { + Ok(_) => panic!("Expecting error"), + Err(DecodingError::IoError(_)) => panic!("Expecting InvalidEncoding"), + Err(DecodingError::SizeLimit) => panic!("Expecting InvalidEncoding"), + Err(DecodingError::InvalidEncoding(_)) => {}, + } + } + + isize_invalid_encoding(decode::(&vec![0xA][..])); + isize_invalid_encoding(decode::(&vec![0, 0, 0, 0, 0, 0, 0, 1, 0xFF][..])); + // Out-of-bounds variant + #[derive(RustcEncodable, RustcDecodable, Serialize)] + enum Test { + One, + Two, + }; + isize_invalid_encoding(decode::(&vec![0, 0, 0, 5][..])); + isize_invalid_encoding(decode::>(&vec![5, 0][..])); +} + +#[test] +fn too_big_decode() { + let encoded = vec![0,0,0,3]; + let mut encoded_ref = &encoded[..]; + let decoded: Result = decode_from(&mut encoded_ref, Bounded(3)); + assert!(decoded.is_err()); + + let encoded = vec![0,0,0,3]; + let mut encoded_ref = &encoded[..]; + let decoded: Result = decode_from(&mut encoded_ref, Bounded(4)); + assert!(decoded.is_ok()); +} + +#[test] +fn too_big_char_decode() { + let encoded = vec![0x41]; + let mut encoded_ref = &encoded[..]; + let decoded: Result = decode_from(&mut encoded_ref, Bounded(1)); + assert!(decoded.is_ok()); + assert_eq!(decoded.unwrap(), 'A'); +} + +#[test] +fn too_big_encode() { + assert!(encode(&0u32, Bounded(3)).is_err()); + assert!(encode(&0u32, Bounded(4)).is_ok()); + + assert!(encode(&"abcde", Bounded(8 + 4)).is_err()); + assert!(encode(&"abcde", Bounded(8 + 5)).is_ok()); +} + +#[test] +fn test_encoded_size() { + assert!(encoded_size(&0u8) == 1); + assert!(encoded_size(&0u16) == 2); + assert!(encoded_size(&0u32) == 4); + assert!(encoded_size(&0u64) == 8); + + // length isize stored as u64 + assert!(encoded_size(&"") == 8); + assert!(encoded_size(&"a") == 8 + 1); + + assert!(encoded_size(&vec![0u32, 1u32, 2u32]) == 8 + 3 * (4)) +} + +#[test] +fn encode_box() { + the_same(Box::new(5)); +} + +#[test] +fn test_refbox() { + let large_object = vec![1u32,2,3,4,5,6]; + let mut large_map = HashMap::new(); + large_map.insert(1, 2); + + + #[derive(RustcEncodable, RustcDecodable, Debug)] + enum Message<'a> { + M1(RefBox<'a, Vec>), + M2(RefBox<'a, HashMap>) + } + + // Test 1 + { + let encoded = encode(&Message::M1(RefBox::new(&large_object)), Infinite).unwrap(); + let decoded: Message<'static> = decode(&encoded[..]).unwrap(); + + match decoded { + Message::M1(b) => assert!(b.take().deref() == &large_object), + _ => assert!(false) + } + } + + // Test 2 + { + let encoded = encode(&Message::M2(RefBox::new(&large_map)), Infinite).unwrap(); + let decoded: Message<'static> = decode(&encoded[..]).unwrap(); + + match decoded { + Message::M2(b) => assert!(b.take().deref() == &large_map), + _ => assert!(false) + } + } +} + +#[test] +fn test_strbox() { + let strx: &'static str = "hello world"; + let encoded = encode(&StrBox::new(strx), Infinite).unwrap(); + let decoded: StrBox<'static> = decode(&encoded[..]).unwrap(); + let stringx: String = decoded.take(); + assert!(strx == &stringx[..]); +} + +#[test] +fn test_slicebox() { + let slice = [1u32, 2, 3 ,4, 5]; + let encoded = encode(&SliceBox::new(&slice), Infinite).unwrap(); + let decoded: SliceBox<'static, u32> = decode(&encoded[..]).unwrap(); + { + let sb: &[u32] = &decoded; + assert!(slice == sb); + } + let vecx: Vec = decoded.take(); + assert!(slice == &vecx[..]); +} + +#[test] +fn test_multi_strings() { + assert!(encode(&("foo", "bar", "baz"), Infinite).is_ok()); +}