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
100 changes: 100 additions & 0 deletions rmpv-tests/tests/de_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,106 @@ fn pass_enum_from_value() {
deserialize_from(ValueRef::Array(vec![ValueRef::from(3), ValueRef::Array(vec![ValueRef::from("John"), ValueRef::from(42)])])).unwrap());
}

#[test]
fn pass_map_encoded_enum_variants_from_value_ref() {
#[derive(Debug, PartialEq, Deserialize)]
enum Enum<'a> {
Unit,
EmptyTuple(),
EmptyStruct {},
Newtype(Vec<u32>),
Tuple(&'a str, u32),
Struct { name: &'a str, age: u32 },
}

let unit = ValueRef::Map(vec![(ValueRef::from("Unit"), ValueRef::Nil)]);
assert_eq!(Enum::Unit, deserialize_from(unit).unwrap());
for payload in [ValueRef::Array(vec![]), ValueRef::Map(vec![])] {
let value = ValueRef::Map(vec![(ValueRef::from("EmptyStruct"), payload)]);
assert_eq!(Enum::EmptyStruct {}, deserialize_from(value).unwrap());
}
let value = ValueRef::Map(vec![(ValueRef::from("EmptyTuple"), ValueRef::Array(vec![]))]);
assert_eq!(Enum::EmptyTuple(), deserialize_from(value).unwrap());
for values in [vec![], vec![1], vec![1, 2]] {
let expected = values.clone();
let value = ValueRef::Map(vec![
(ValueRef::from("Newtype"), ValueRef::Array(values.into_iter().map(ValueRef::from).collect())),
]);
let decoded: Enum<'_> = deserialize_from(value).unwrap();
match decoded {
Enum::Newtype(actual) => assert_eq!(expected, actual),
_ => panic!("unexpected enum variant"),
}
}
let value = ValueRef::Map(vec![
(ValueRef::from("Tuple"), ValueRef::Array(vec![ValueRef::from("John"), ValueRef::from(42)])),
]);
assert_eq!(Enum::Tuple("John", 42), deserialize_from(value).unwrap());

let value = ValueRef::Map(vec![
(ValueRef::from("Struct"), ValueRef::Map(vec![
(ValueRef::from("name"), ValueRef::from("John")),
(ValueRef::from("age"), ValueRef::from(42)),
])),
]);
let decoded: Enum<'_> = deserialize_from(value).unwrap();
assert_eq!(Enum::Struct { name: "John", age: 42 }, decoded);

for (index, value) in [
ValueRef::Map(vec![]),
ValueRef::Map(vec![(ValueRef::from("Unit"), ValueRef::Nil), (ValueRef::from("Unit"), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::Array(vec![]), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::from("Unknown"), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::from("Tuple"), ValueRef::from(1))]),
].into_iter().enumerate() {
assert!(deserialize_from::<Enum<'_>, _>(value).is_err(), "case {index}");
}
}

#[test]
fn pass_borrowed_map_enum_from_reference() {
#[derive(Debug, PartialEq, Deserialize)]
enum Enum<'a> {
Unit,
EmptyTuple(),
EmptyStruct {},
Newtype(&'a str),
Tuple(&'a str, u32),
Struct { name: &'a str, age: u32 },
}

let value = ValueRef::Map(vec![(ValueRef::from("Unit"), ValueRef::Nil)]);
assert_eq!(Enum::Unit, serde::Deserialize::deserialize(&value).unwrap());
for payload in [ValueRef::Array(vec![]), ValueRef::Map(vec![])] {
let value = ValueRef::Map(vec![(ValueRef::from("EmptyStruct"), payload)]);
let decoded: Enum<'_> = serde::Deserialize::deserialize(&value).unwrap();
assert_eq!(Enum::EmptyStruct {}, decoded);
}
let value = ValueRef::Map(vec![(ValueRef::from("EmptyTuple"), ValueRef::Array(vec![]))]);
assert_eq!(Enum::EmptyTuple(), serde::Deserialize::deserialize(&value).unwrap());
let value = ValueRef::Map(vec![(ValueRef::from("Newtype"), ValueRef::from("borrowed"))]);
let decoded: Enum<'_> = serde::Deserialize::deserialize(&value).unwrap();
assert_eq!(Enum::Newtype("borrowed"), decoded);
let value = ValueRef::Map(vec![(ValueRef::from("Tuple"), ValueRef::Array(vec![ValueRef::from("John"), ValueRef::from(42)]))]);
assert_eq!(Enum::Tuple("John", 42), serde::Deserialize::deserialize(&value).unwrap());
let value = ValueRef::Map(vec![(ValueRef::from("Struct"), ValueRef::Map(vec![
(ValueRef::from("name"), ValueRef::from("John")),
(ValueRef::from("age"), ValueRef::from(42)),
]))]);
assert_eq!(Enum::Struct { name: "John", age: 42 }, serde::Deserialize::deserialize(&value).unwrap());

for (index, value) in [
ValueRef::Map(vec![]),
ValueRef::Map(vec![(ValueRef::from("Unit"), ValueRef::Nil), (ValueRef::from("Unit"), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::Array(vec![]), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::from("Unknown"), ValueRef::Nil)]),
ValueRef::Map(vec![(ValueRef::from("Tuple"), ValueRef::from(1))]),
].into_iter().enumerate() {
let decoded: Result<Enum<'_>, _> = serde::Deserialize::deserialize(&value);
assert!(decoded.is_err(), "case {index}");
}
}

#[test]
fn pass_from_slice() {
let buf = [0x93, 0xa4, 0x4a, 0x6f, 0x68, 0x6e, 0xa5, 0x53, 0x6d, 0x69, 0x74, 0x68, 0x2a];
Expand Down
93 changes: 92 additions & 1 deletion rmpv-tests/tests/decode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use serde_bytes::ByteBuf;
use std::collections::BTreeMap;

Expand Down Expand Up @@ -263,6 +263,97 @@ fn pass_enum_from_value() {
from_value(Value::Array(vec![Value::from(3), Value::Array(vec![Value::from("John"), Value::from(42)])])).unwrap());
}

#[test]
fn pass_externally_tagged_enum_map_from_value() {
for result in [Ok(1), Err(2)] {
let encoded = rmp_serde::to_vec_named(&result).unwrap();
assert_eq!(
encoded,
if result.is_ok() {
vec![0x81, 0xa2, b'O', b'k', 0x01]
} else {
vec![0x81, 0xa3, b'E', b'r', b'r', 0x02]
}
);
let value: Value = rmp_serde::from_slice(&encoded).unwrap();
let decoded: Result<u32, u32> = from_value(value).unwrap();
assert_eq!(result, decoded);
}
}

#[test]
fn pass_map_encoded_enum_variants_from_value() {
#[derive(Debug, PartialEq, Deserialize)]
enum Enum {
Unit,
EmptyTuple(),
EmptyStruct {},
Newtype(Vec<u32>),
Tuple(String, u32),
Struct { name: String, age: u32 },
}

assert_eq!(Enum::Unit, from_value(Value::Map(vec![(Value::from("Unit"), Value::Nil)])).unwrap());
assert_eq!(Enum::EmptyTuple(), from_value(Value::Map(vec![(Value::from("EmptyTuple"), Value::Array(vec![]))])).unwrap());
assert_eq!(Enum::EmptyStruct {}, from_value(Value::Map(vec![(Value::from("EmptyStruct"), Value::Array(vec![]))])).unwrap());
assert_eq!(Enum::EmptyStruct {}, from_value(Value::Map(vec![(
Value::from("EmptyStruct"),
Value::Map(vec![]),
)])).unwrap());
for values in [vec![], vec![1], vec![1, 2]] {
assert_eq!(Enum::Newtype(values.clone()), from_value(Value::Map(vec![
(Value::from("Newtype"), Value::Array(values.into_iter().map(Value::from).collect())),
])).unwrap());
}
assert_eq!(Enum::Tuple("John".into(), 42), from_value(Value::Map(vec![
(Value::from("Tuple"), Value::Array(vec![Value::from("John"), Value::from(42)])),
])).unwrap());
assert_eq!(Enum::Struct { name: "John".into(), age: 42 }, from_value(Value::Map(vec![
(Value::from("Struct"), Value::Map(vec![
(Value::from("name"), Value::from("John")),
(Value::from("age"), Value::from(42)),
])),
])).unwrap());
}

#[test]
fn reject_malformed_enum_maps_from_value() {
#[derive(Debug, PartialEq, Deserialize)]
enum Enum {
Unit,
}

for value in [
Value::Map(vec![]),
Value::Map(vec![(Value::from("Unit"), Value::Nil), (Value::from("Unit"), Value::Nil)]),
Value::Map(vec![(Value::from("Unknown"), Value::Nil)]),
Value::Map(vec![(Value::from("Unit"), Value::from(1))]),
] {
assert!(from_value::<Enum>(value).is_err());
}
}

#[test]
fn pass_serializer_generated_empty_enum_variants_from_value() {
#[derive(Debug, PartialEq, Serialize, Deserialize)]
enum Enum {
Tuple(),
Struct {},
}

for expected in [Enum::Tuple(), Enum::Struct {}] {
let encoded = rmp_serde::to_vec_named(&expected).unwrap();
let fixture = match &expected {
Enum::Tuple() => vec![0x81, 0xa5, b'T', b'u', b'p', b'l', b'e', 0x90],
Enum::Struct {} => vec![0x81, 0xa6, b'S', b't', b'r', b'u', b'c', b't', 0x80],
};
assert_eq!(encoded, fixture);
let value: Value = rmp_serde::from_slice(&encoded).unwrap();
let decoded: Enum = from_value(value).unwrap();
assert_eq!(expected, decoded);
}
}

#[test]
fn pass_tuple_struct_from_ext() {
#[derive(Debug, PartialEq)]
Expand Down
105 changes: 103 additions & 2 deletions rmpv/src/ext/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,16 @@ impl<'de> Deserializer<'de> for Value {
fn deserialize_enum<V>(self, _name: &str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>
{
ValueBase::deserialize_enum(self, visitor)
match self {
Self::Map(mut values) if values.len() == 1 => {
match values.pop() {
Some((key, value)) => visitor.visit_enum(MapEnumDeserializer::new(key, value)),
None => Err(de::Error::invalid_length(0, &"map with one element")),
}
},
Self::Map(values) => Err(de::Error::invalid_length(values.len(), &"map with one element")),
value => ValueBase::deserialize_enum(value, visitor),
}
}

#[inline]
Expand Down Expand Up @@ -456,7 +465,16 @@ impl<'de> Deserializer<'de> for ValueRef<'de> {
fn deserialize_enum<V>(self, _name: &str, _variants: &'static [&'static str], visitor: V) -> Result<V::Value, Self::Error>
where V: Visitor<'de>
{
ValueBase::deserialize_enum(self, visitor)
match self {
ValueRef::Map(mut values) if values.len() == 1 => {
match values.pop() {
Some((key, value)) => visitor.visit_enum(MapEnumDeserializer::new(key, value)),
None => Err(de::Error::invalid_length(0, &"map with one element")),
}
},
ValueRef::Map(values) => Err(de::Error::invalid_length(values.len(), &"map with one element")),
value => ValueBase::deserialize_enum(value, visitor),
}
}

#[inline]
Expand Down Expand Up @@ -570,6 +588,11 @@ impl<'de> Deserializer<'de> for &'de ValueRef<'de> {

visitor.visit_enum(EnumRefDeserializer::new(id, iter.next()))
},
ValueRef::Map(v) if v.len() == 1 => {
let (key, value) = &v[0];
visitor.visit_enum(MapEnumDeserializer::new(key, value))
},
ValueRef::Map(v) => Err(de::Error::invalid_length(v.len(), &"map with one element")),
other => Err(de::Error::invalid_type(other.unexpected(), &"array, map or int")),
}
}
Expand Down Expand Up @@ -838,6 +861,84 @@ impl<'de, U: ValueBase<'de> + ValueExt> de::EnumAccess<'de> for EnumDeserializer
}
}

struct MapEnumDeserializer<K, V> {
key: K,
value: V,
}

impl<K, V> MapEnumDeserializer<K, V> {
const fn new(key: K, value: V) -> Self {
Self { key, value }
}
}

impl<'de, K, V> de::EnumAccess<'de> for MapEnumDeserializer<K, V>
where
K: Deserializer<'de, Error = Error>,
V: Deserializer<'de, Error = Error>,
{
type Error = Error;
type Variant = MapVariantDeserializer<V>;

fn variant_seed<S>(self, seed: S) -> Result<(S::Value, Self::Variant), Self::Error>
where
S: de::DeserializeSeed<'de>,
{
seed.deserialize(self.key)
.map(|variant| (variant, MapVariantDeserializer { value: self.value }))
}
}

struct MapVariantDeserializer<V> {
value: V,
}

impl<'de, V> de::VariantAccess<'de> for MapVariantDeserializer<V>
where
V: Deserializer<'de, Error = Error>,
{
type Error = Error;

fn unit_variant(self) -> Result<(), Error> {
struct UnitVisitor;

impl<'de> Visitor<'de> for UnitVisitor {
type Value = ();

fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("unit variant")
}

fn visit_unit<E>(self) -> Result<(), E> {
Ok(())
}
}

self.value.deserialize_unit(UnitVisitor)
}

fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
where
T: de::DeserializeSeed<'de>,
{
seed.deserialize(self.value)
}

fn tuple_variant<A>(self, _len: usize, visitor: A) -> Result<A::Value, Error>
where
A: Visitor<'de>,
{
self.value.deserialize_seq(visitor)
}

fn struct_variant<A>(self, _fields: &'static [&'static str], visitor: A) -> Result<A::Value, Error>
where
A: Visitor<'de>,
{
self.value.deserialize_any(visitor)
}
}

struct VariantDeserializer<U> {
value: Option<U>,
}
Expand Down