Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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