diff --git a/rmp-serde/src/decode.rs b/rmp-serde/src/decode.rs index 0b1da7ce..048653b9 100644 --- a/rmp-serde/src/decode.rs +++ b/rmp-serde/src/decode.rs @@ -606,3 +606,11 @@ pub fn from_read(rd: R) -> Result { Deserialize::deserialize(&mut Deserializer::new(rd)) } + +/// Deserializes a byte slice into the desired type. +pub fn from_slice<'a, T>(input: &'a [u8]) -> Result + where T: serde::Deserialize<'a> +{ + let mut de = Deserializer::from_slice(input); + serde::Deserialize::deserialize(&mut de) +} diff --git a/rmp-serde/src/encode.rs b/rmp-serde/src/encode.rs index de842478..b0e76e59 100644 --- a/rmp-serde/src/encode.rs +++ b/rmp-serde/src/encode.rs @@ -92,6 +92,35 @@ impl VariantWriter for StructArrayWriter { } } +pub struct StructMapWriter; + +impl VariantWriter for StructMapWriter { + fn write_struct_len(&self, wr: &mut W, len: u32) -> Result + where + W: Write, + { + write_map_len(wr, len) + } + + fn write_field_name(&self, wr: &mut W, key: &str) -> Result<(), ValueWriteError> + where + W: Write, + { + write_str(wr, key) + } +} +impl Serializer { + /// Constructs a new `MessagePack` serializer whose output will be written to the writer + /// specified. + /// + /// # Note + /// + /// This is the default constructor, which returns a serializer that will serialize structs + /// using large named representation. + pub fn new_named(wr: W) -> Self { + Serializer::with(wr, StructMapWriter) + } +} /// Represents MessagePack serialization implementation. /// /// # Note @@ -128,6 +157,9 @@ impl Serializer { pub fn new(wr: W) -> Self { Serializer::with(wr, StructArrayWriter) } + pub fn compact(wr: W) -> Self { + Serializer::with(wr, StructArrayWriter) + } } impl Serializer { @@ -438,6 +470,7 @@ impl<'a, W: Write, V: VariantWriter> serde::Serializer for &'a mut Serializer(wr: &mut W, val: &T) -> Result<(), Error> where W: Write, T: Serialize { - val.serialize(&mut Serializer::new(wr)) + val.serialize(&mut Serializer::compact(wr)) } +/// Serialize the given data structure as MessagePack into the I/O stream. +/// This function serializes structures as maps +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to fail. +#[inline] +pub fn write_named(wr: &mut W, val: &T) -> Result<(), Error> +where + W: Write, + T: Serialize, +{ + val.serialize(&mut Serializer::new_named(wr)) +} /// Serialize the given data structure as a MessagePack byte vector. +/// This method uses compact representation, structs are serialized as arrays /// /// Serialization can fail if `T`'s implementation of `Serialize` decides to fail. #[inline] @@ -460,3 +506,18 @@ pub fn to_vec(val: &T) -> Result, Error> write(&mut buf, val)?; Ok(buf) } + +/// Serializes data structure into byte vector as a map +/// Resulting MessagePack message will contain field names +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to fail. +#[inline] +pub fn to_vec_named(value: &T) -> Result, Error> +where + T: serde::Serialize, +{ + let mut buf = Vec::with_capacity(64); + value.serialize(&mut Serializer::new_named(&mut buf))?; + Ok(buf) +} + diff --git a/rmp-serde/src/lib.rs b/rmp-serde/src/lib.rs index eea83021..537c2154 100644 --- a/rmp-serde/src/lib.rs +++ b/rmp-serde/src/lib.rs @@ -68,8 +68,8 @@ use std::str::{self, Utf8Error}; use serde::de::{self, Deserialize}; -pub use decode::Deserializer; -pub use encode::Serializer; +pub use decode::{Deserializer, from_slice, from_read}; +pub use encode::{Serializer, to_vec, to_vec_named}; pub mod decode; pub mod encode; @@ -268,20 +268,3 @@ impl<'de> Deserialize<'de> for RawRef<'de> { de.deserialize_any(RawRefVisitor) } } - -/// Serializes a value to a byte vector. -pub fn to_vec(value: &T) -> Result, encode::Error> - where T: serde::Serialize -{ - let mut buf = Vec::with_capacity(64); - value.serialize(&mut Serializer::new(&mut buf))?; - Ok(buf) -} - -/// Deserializes a byte slice into the desired type. -pub fn from_slice<'a, T>(input: &'a [u8]) -> Result - where T: serde::Deserialize<'a> -{ - let mut de = Deserializer::from_slice(input); - serde::Deserialize::deserialize(&mut de) -} diff --git a/rmp-serde/tests/round.rs b/rmp-serde/tests/round.rs index 76911525..a5c80588 100644 --- a/rmp-serde/tests/round.rs +++ b/rmp-serde/tests/round.rs @@ -86,3 +86,36 @@ fn round_enum_with_nested_struct() { assert_eq!(expected, Deserialize::deserialize(&mut de).unwrap()); } + +// Checks whether deserialization and serialization can both work with structs as maps +#[test] +fn round_struct_as_map() { + use rmps::to_vec_named; + use rmps::decode::from_slice; + + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + struct Dog1 { + name: String, + age: u16, + } + #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)] + struct Dog2 { + age: u16, + name: String, + } + + let dog1 = Dog1 { + name: "Frankie".into(), + age: 42, + }; + + let serialized: Vec = to_vec_named(&dog1).unwrap(); + let deserialized: Dog2 = from_slice(&serialized).unwrap(); + + let check = Dog1 { + age: deserialized.age, + name: deserialized.name, + }; + + assert_eq!(dog1, check); +} diff --git a/rmpv/src/lib.rs b/rmpv/src/lib.rs index 87995c78..4ab999ea 100644 --- a/rmpv/src/lib.rs +++ b/rmpv/src/lib.rs @@ -249,6 +249,13 @@ impl Utf8String { Err(err) => err.0, } } + + pub fn as_ref(&self) -> Utf8StringRef { + match self.s { + Ok(ref s) => Utf8StringRef { s: Ok(s.as_str()) }, + Err((ref buf, err)) => Utf8StringRef { s: Err((&buf[..], err)) }, + } + } } impl Display for Utf8String { @@ -410,6 +417,53 @@ pub enum Value { } impl Value { + /// Converts the current owned Value to a ValueRef. + /// + /// # Panics + /// + /// Panics in unable to allocate memory to keep all internal structures and buffers. + /// + /// # Examples + /// ``` + /// use rmpv::{Value, ValueRef}; + /// + /// let val = Value::Array(vec![ + /// Value::Nil, + /// Value::from(42), + /// Value::Array(vec![ + /// Value::String("le message".into()) + /// ]) + /// ]); + /// + /// let expected = ValueRef::Array(vec![ + /// ValueRef::Nil, + /// ValueRef::from(42), + /// ValueRef::Array(vec![ + /// ValueRef::from("le message"), + /// ]) + /// ]); + /// + /// assert_eq!(expected, val.as_ref()); + /// ``` + pub fn as_ref(&self) -> ValueRef { + match self { + &Value::Nil => ValueRef::Nil, + &Value::Boolean(val) => ValueRef::Boolean(val), + &Value::Integer(val) => ValueRef::Integer(val), + &Value::F32(val) => ValueRef::F32(val), + &Value::F64(val) => ValueRef::F64(val), + &Value::String(ref val) => ValueRef::String(val.as_ref()), + &Value::Binary(ref val) => ValueRef::Binary(val.as_slice()), + &Value::Array(ref val) => { + ValueRef::Array(val.iter().map(|v| v.as_ref()).collect()) + } + &Value::Map(ref val) => { + ValueRef::Map(val.iter().map(|&(ref k, ref v)| (k.as_ref(), v.as_ref())).collect()) + } + &Value::Ext(ty, ref buf) => ValueRef::Ext(ty, buf.as_slice()), + } + } + /// Returns true if the `Value` is a Null. Returns false otherwise. /// /// # Examples diff --git a/rmpv/tests/decode_ref.rs b/rmpv/tests/decode_ref.rs index 4c580df0..0bd6f3d8 100644 --- a/rmpv/tests/decode_ref.rs +++ b/rmpv/tests/decode_ref.rs @@ -687,4 +687,5 @@ fn into_owned() { ]); assert_eq!(expected, val.to_owned()); + assert_eq!(expected.as_ref(), val); }