Skip to content

Commit 1296037

Browse files
committed
Static dispatch to VariantWriter impl via generics
1 parent 0e69c67 commit 1296037

4 files changed

Lines changed: 145 additions & 35 deletions

File tree

rmp-serde/src/encode.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use serde;
33
use std::fmt;
44
use std::io::Write;
55

6+
use rmp::Marker;
67
use rmp::encode::{
78
write_nil,
89
write_bool,
@@ -58,6 +59,52 @@ impl From<ValueWriteError> for Error {
5859
}
5960
}
6061

62+
pub trait VariantWriter {
63+
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError> where W: Write;
64+
fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError> where W: Write;
65+
}
66+
67+
/// Writes struct as MessagePack array with no field names
68+
pub struct StructArrayWriter;
69+
70+
impl VariantWriter for StructArrayWriter {
71+
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError>
72+
where W: Write
73+
{
74+
write_array_len(wr, len)
75+
}
76+
77+
/// This implementation does not write field names
78+
#[allow(unused_variables)]
79+
fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError>
80+
where W: Write
81+
{
82+
Ok(())
83+
}
84+
}
85+
86+
/// Writes struct as MessagePack map including field names
87+
pub struct StructMapWriter;
88+
89+
impl VariantWriter for StructMapWriter {
90+
fn write_struct_len<W>(&self, wr: &mut W, len: u32) -> Result<Marker, ValueWriteError>
91+
where W: Write
92+
{
93+
write_map_len(wr, len)
94+
}
95+
96+
fn write_field_name<W>(&self, wr: &mut W, _key: &str) -> Result<(), ValueWriteError>
97+
where W: Write
98+
{
99+
write_str(wr, _key)
100+
}
101+
}
102+
103+
/// Creates a new MessagePack encoder with default variant options
104+
pub fn new_default_serializer<'a>(wr: &'a mut Write) -> Serializer<'a, StructArrayWriter> {
105+
Serializer::new(wr, StructArrayWriter)
106+
}
107+
61108
/// Represents MessagePack serialization implementation.
62109
///
63110
/// # Note
@@ -70,20 +117,22 @@ impl From<ValueWriteError> for Error {
70117
/// All instances of `ErrorKind::Interrupted` are handled by this function and the underlying
71118
/// operation is retried.
72119
// TODO: Docs. Examples.
73-
pub struct Serializer<'a> {
120+
pub struct Serializer<'a, W: VariantWriter> {
74121
wr: &'a mut Write,
122+
vw: W,
75123
}
76124

77-
impl<'a> Serializer<'a> {
125+
impl<'a, W: VariantWriter> Serializer<'a, W> {
78126
/// Creates a new MessagePack encoder whose output will be written to the writer specified.
79-
pub fn new(wr: &'a mut Write) -> Serializer<'a> {
127+
pub fn new(wr: &'a mut Write, variant_writer: W) -> Serializer<'a, W> {
80128
Serializer {
81129
wr: wr,
130+
vw: variant_writer,
82131
}
83132
}
84133
}
85134

86-
impl<'a> serde::Serializer for Serializer<'a> {
135+
impl<'a, W: VariantWriter> serde::Serializer for Serializer<'a, W> {
87136
type Error = Error;
88137

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

279-
try!(write_array_len(&mut self.wr, len as u32));
328+
try!(self.vw.write_struct_len(&mut self.wr, len as u32));
280329

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

@@ -286,6 +335,7 @@ impl<'a> serde::Serializer for Serializer<'a> {
286335
fn visit_struct_elt<V>(&mut self, _key: &str, value: V) -> Result<(), Error>
287336
where V: serde::Serialize,
288337
{
338+
try!(self.vw.write_field_name(&mut self.wr, _key));
289339
value.serialize(self)
290340
}
291341

rmp-serde/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ pub mod decode;
55
pub mod encode;
66

77
pub use decode::Deserializer;
8-
pub use encode::Serializer;
8+
pub use encode::{Serializer, new_default_serializer, StructArrayWriter, StructMapWriter};

rmp-serde/tests/deserializer.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,36 @@ fn pass_map() {
340340
assert_eq!(expected, actual);
341341
}
342342

343+
#[cfg(feature = "serde_macros")]
344+
#[test]
345+
fn pass_struct_map() {
346+
#[derive(Debug, PartialEq, Deserialize)]
347+
struct Custom {
348+
et: String,
349+
le: u8,
350+
shit: u8,
351+
}
352+
353+
let buf = [
354+
0x83, // 3 (size)
355+
0xa2, 0x65, 0x74, // "et"
356+
0xa5, 0x76, 0x6f, 0x69, 0x6c, 0x61, // "voila"
357+
0xa2, 0x6c, 0x65, // "le"
358+
0x00, // 0
359+
0xa4, 0x73, 0x68, 0x69, 0x74, // "shit"
360+
0x01, // 1
361+
];
362+
let cur = Cursor::new(&buf[..]);
363+
364+
// it appears no special behavior is needed for deserializing structs encoded as maps
365+
let mut deserializer = Deserializer::new(cur);
366+
let actual: Custom = Deserialize::deserialize(&mut deserializer).unwrap();
367+
let voila = "voila".to_string(); // so the next line looks more funny
368+
let expected = Custom { et: voila, le: 0, shit: 1 };
369+
370+
assert_eq!(expected, actual);
371+
}
372+
343373
#[cfg(feature = "serde_macros")]
344374
#[test]
345375
fn pass_enum() {

0 commit comments

Comments
 (0)