Skip to content
Open
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
8 changes: 8 additions & 0 deletions rmp-serde/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,3 +606,11 @@ pub fn from_read<R, T>(rd: R) -> Result<T, Error>
{
Deserialize::deserialize(&mut Deserializer::new(rd))
}

/// Deserializes a byte slice into the desired type.
pub fn from_slice<'a, T>(input: &'a [u8]) -> Result<T, Error>
where T: serde::Deserialize<'a>
{
let mut de = Deserializer::from_slice(input);
serde::Deserialize::deserialize(&mut de)
}
63 changes: 62 additions & 1 deletion rmp-serde/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@ impl VariantWriter for StructArrayWriter {
}
}

pub 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)
}
}
impl<W: Write> Serializer<W, StructMapWriter> {
/// 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
Expand Down Expand Up @@ -128,6 +157,9 @@ impl<W: Write> Serializer<W, StructArrayWriter> {
pub fn new(wr: W) -> Self {
Serializer::with(wr, StructArrayWriter)
}
pub fn compact(wr: W) -> Self {
Serializer::with(wr, StructArrayWriter)
}
}

impl<W: Write, V> Serializer<W, V> {
Expand Down Expand Up @@ -438,18 +470,32 @@ impl<'a, W: Write, V: VariantWriter> serde::Serializer for &'a mut Serializer<W,
}

/// Serialize the given data structure as MessagePack into the I/O stream.
/// This fyunction uses compact representation - structures as arrays
///
/// Serialization can fail if `T`'s implementation of `Serialize` decides to fail.
#[inline]
pub fn write<W: ?Sized, T: ?Sized>(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<W: ?Sized, T: ?Sized>(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]
Expand All @@ -460,3 +506,18 @@ pub fn to_vec<T: ?Sized>(val: &T) -> Result<Vec<u8>, 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<T>(value: &T) -> Result<Vec<u8>, Error>
where
T: serde::Serialize,
{
let mut buf = Vec::with_capacity(64);
value.serialize(&mut Serializer::new_named(&mut buf))?;
Ok(buf)
}

21 changes: 2 additions & 19 deletions rmp-serde/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<T>(value: &T) -> Result<Vec<u8>, 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<T, decode::Error>
where T: serde::Deserialize<'a>
{
let mut de = Deserializer::from_slice(input);
serde::Deserialize::deserialize(&mut de)
}
33 changes: 33 additions & 0 deletions rmp-serde/tests/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8> = 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);
}
54 changes: 54 additions & 0 deletions rmpv/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions rmpv/tests/decode_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,4 +687,5 @@ fn into_owned() {
]);

assert_eq!(expected, val.to_owned());
assert_eq!(expected.as_ref(), val);
}