Skip to content

Commit

Permalink
Merge pull request #39 from 3Hren/pr/encoding-policy
Browse files Browse the repository at this point in the history
Struct encoding policy
  • Loading branch information
3Hren committed Sep 1, 2015
2 parents 0e69c67 + 46b3d5d commit 60d872e
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 5 deletions.
48 changes: 43 additions & 5 deletions rmp-serde/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde;
use std::fmt;
use std::io::Write;

use rmp::Marker;
use rmp::encode::{
write_nil,
write_bool,
Expand Down Expand Up @@ -58,6 +59,30 @@ impl From<ValueWriteError> for Error {
}
}

pub trait VariantWriter {
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError> where W: Write;
fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError> where W: Write;
}

/// Writes struct as MessagePack array with no field names
pub struct StructArrayWriter;

impl VariantWriter for StructArrayWriter {
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError>
where W: Write
{
write_array_len(wr, len)
}

/// This implementation does not write field names
#[allow(unused_variables)]
fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError>
where W: Write
{
Ok(())
}
}

/// Represents MessagePack serialization implementation.
///
/// # Note
Expand All @@ -70,20 +95,32 @@ impl From<ValueWriteError> for Error {
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
/// operation is retried.
// TODO: Docs. Examples.
pub struct Serializer<'a> {
pub struct Serializer<'a, W: VariantWriter> {
wr: &'a mut Write,
vw: W,
}

impl<'a> Serializer<'a> {
impl<'a> Serializer<'a, StructArrayWriter> {
/// Creates a new MessagePack encoder whose output will be written to the writer specified.
pub fn new(wr: &'a mut Write) -> Serializer<'a> {
pub fn new(wr: &'a mut Write) -> Serializer<'a, StructArrayWriter> {
Serializer {
wr: wr,
vw: StructArrayWriter,
}
}
}

impl<'a> serde::Serializer for Serializer<'a> {
impl<'a, W: VariantWriter> Serializer<'a, W> {
/// Creates a new MessagePack encoder whose output will be written to the writer specified.
pub fn with(wr: &'a mut Write, vw: W) -> Serializer<'a, W> {
Serializer {
wr: wr,
vw: vw,
}
}
}

impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {
type Error = Error;

fn visit_unit(&mut self) -> Result<(), Error> {
Expand Down Expand Up @@ -276,7 +313,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
None => panic!("do not know how to serialize a sequence with no length"),
};

try!(write_array_len(&mut self.wr, len as u32));
try!(self.vw.write_struct_len(&mut self.wr, len as u32));

while let Some(()) = try!(visitor.visit(self)) { }

Expand All @@ -286,6 +323,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
fn visit_struct_elt<V>(&mut self, _key: &str, value: V) -> Result<(), Error>
where V: serde::Serialize,
{
try!(self.vw.write_field_name(&mut self.wr, _key));
value.serialize(self)
}

Expand Down
30 changes: 30 additions & 0 deletions rmp-serde/tests/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,36 @@ fn pass_map() {
assert_eq!(expected, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_map() {
#[derive(Debug, PartialEq, Deserialize)]
struct Custom {
et: String,
le: u8,
shit: u8,
}

let buf = [
0x83, // 3 (size)
0xa2, 0x65, 0x74, // "et"
0xa5, 0x76, 0x6f, 0x69, 0x6c, 0x61, // "voila"
0xa2, 0x6c, 0x65, // "le"
0x00, // 0
0xa4, 0x73, 0x68, 0x69, 0x74, // "shit"
0x01, // 1
];
let cur = Cursor::new(&buf[..]);

// it appears no special behavior is needed for deserializing structs encoded as maps
let mut deserializer = Deserializer::new(cur);
let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();
let voila = "voila".to_string(); // so the next line looks more funny
let expected = Custom { et: voila, le: 0, shit: 1 };

assert_eq!(expected, actual);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum() {
Expand Down
49 changes: 49 additions & 0 deletions rmp-serde/tests/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![cfg_attr(feature = "serde_macros", plugin(serde_macros))]

extern crate serde;
extern crate rmp;
extern crate rmp_serde;

use std::io::Cursor;
Expand Down Expand Up @@ -267,6 +268,54 @@ fn pass_map() {
assert_eq!(out, buf);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_struct_map() {
use std::io::Write;
use rmp::Marker;
use rmp::encode::{ValueWriteError, write_map_len, write_str};
use rmp_serde::encode::VariantWriter;

struct StructMapWriter;

impl VariantWriter for StructMapWriter {
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError>
where W: Write
{
write_map_len(wr, len)
}

fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError>
where W: Write
{
write_str(wr, _key)
}
}

#[derive(Debug, PartialEq, Serialize)]
struct Custom<'a> {
et: &'a str,
le: u8,
shit: u8,
}

let mut buf = [0x00; 20];

let val = Custom { et: "voila", le: 0, shit: 1 };
val.serialize(&mut Serializer::with(&mut &mut buf[..], StructMapWriter)).ok().unwrap();

let out = [
0x83, // 3 (size)
0xa2, 0x65, 0x74, // "et"
0xa5, 0x76, 0x6f, 0x69, 0x6c, 0x61, // "voila"
0xa2, 0x6c, 0x65, // "le"
0x00, // 0
0xa4, 0x73, 0x68, 0x69, 0x74, // "shit"
0x01, // 1
];
assert_eq!(out, buf);
}

#[cfg(feature = "serde_macros")]
#[test]
fn pass_enum() {
Expand Down

0 comments on commit 60d872e

Please sign in to comment.