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
4 changes: 2 additions & 2 deletions src/ipld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@ pub enum IpldIndex<'a> {
MapRef(&'a str),
}

impl<'a> From<usize> for IpldIndex<'a> {
impl From<usize> for IpldIndex<'_> {
fn from(index: usize) -> Self {
Self::List(index)
}
}

impl<'a> From<String> for IpldIndex<'a> {
impl From<String> for IpldIndex<'_> {
fn from(key: String) -> Self {
Self::Map(key)
}
Expand Down
33 changes: 23 additions & 10 deletions src/serde/de.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use alloc::{borrow::ToOwned, collections::BTreeMap, format, string::String, vec::Vec};
use core::{convert::TryFrom, fmt};
use serde::de::Error;

use cid::serde::{BytesToCidVisitor, CID_SERDE_PRIVATE_IDENTIFIER};
use cid::Cid;
Expand Down Expand Up @@ -413,17 +414,11 @@ impl<'de> de::Deserializer<'de> for Ipld {

fn deserialize_tuple<V: de::Visitor<'de>>(
self,
len: usize,
_len: usize,
visitor: V,
) -> Result<V::Value, Self::Error> {
match self {
Self::List(list) => {
if len == list.len() {
visit_seq(list, visitor)
} else {
error(format!("The tuple size must match the length of the `Ipld::List`, tuple size: {}, `Ipld::List` length: {}", len, list.len()))
}
}
Self::List(list) => visit_seq(list, visitor),
_ => error(format!(
"Only `Ipld::List` can be deserialized to tuple, input was `{:#?}`",
self
Expand Down Expand Up @@ -568,15 +563,27 @@ where
V: de::Visitor<'de>,
{
let mut deserializer = MapDeserializer::new(map);
visitor.visit_map(&mut deserializer)
let res = visitor.visit_map(&mut deserializer)?;
match deserializer.remaining() {
0 => Ok(res),
remaining => Err(SerdeError::custom(format!(
"The type failed to consume the entire map: {remaining} items remaining"
))),
}
}

fn visit_seq<'de, V>(list: Vec<Ipld>, visitor: V) -> Result<V::Value, SerdeError>
where
V: de::Visitor<'de>,
{
let mut deserializer = SeqDeserializer::new(list);
visitor.visit_seq(&mut deserializer)
let res = visitor.visit_seq(&mut deserializer)?;
match deserializer.remaining() {
0 => Ok(res),
remaining => Err(SerdeError::custom(format!(
"The type failed to consume the entire sequence: {remaining} items remaining"
))),
}
}

// Heavily based on
Expand All @@ -593,6 +600,9 @@ impl MapDeserializer {
value: None,
}
}
fn remaining(self) -> usize {
self.iter.count()
}
}

impl<'de> de::MapAccess<'de> for MapDeserializer {
Expand Down Expand Up @@ -641,6 +651,9 @@ impl SeqDeserializer {
iter: vec.into_iter(),
}
}
fn remaining(self) -> usize {
self.iter.count()
}
}

impl<'de> de::SeqAccess<'de> for SeqDeserializer {
Expand Down
32 changes: 30 additions & 2 deletions tests/serde_deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extern crate alloc;
use alloc::collections::BTreeMap;
use core::convert::TryFrom;

use serde::Deserialize;
use serde::{Deserialize, Serialize};
use serde_bytes::ByteBuf;
use serde_json::json;

Expand Down Expand Up @@ -367,7 +367,11 @@ fn ipld_deserializer_tuple() {

#[test]
fn ipld_deserializer_tuple_errors() {
let tuple = (true, "hello".to_string());
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct Tuple(bool, String);

let tuple = Tuple(true, "hello".to_string());

let ipld_not_enough = Ipld::List(vec![Ipld::Bool(tuple.0)]);
error_except(tuple.clone(), &ipld_not_enough);
Expand Down Expand Up @@ -405,6 +409,7 @@ fn ipld_deserializer_tuple_struct() {
#[test]
fn ipld_deserializer_tuple_struct_errors() {
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct TupleStruct(u8, bool);

let tuple_struct = TupleStruct(82, true);
Expand Down Expand Up @@ -644,11 +649,23 @@ fn ipld_deserializer_struct() {

let deserialized = MyStruct::deserialize(ipld).unwrap();
assert_eq!(deserialized, my_struct);

// Unknown fields are ignored by default.
let ipld = Ipld::Map(BTreeMap::from([
("hello".into(), Ipld::Integer(my_struct.hello.into())),
("world".into(), Ipld::Bool(my_struct.world)),
("ignored".into(), Ipld::Bool(true)),
]));
error_except(my_struct.clone(), &ipld);

let deserialized = MyStruct::deserialize(ipld).unwrap();
assert_eq!(deserialized, my_struct);
}

#[test]
fn ipld_deserializer_struct_errors() {
#[derive(Clone, Debug, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct MyStruct {
hello: u8,
world: bool,
Expand All @@ -671,7 +688,18 @@ fn ipld_deserializer_struct_errors() {
"wrong".into(),
Ipld::Integer(my_struct.hello.into()),
)]));
error_except(my_struct.clone(), &ipld_wrong);
let error_wrong = MyStruct::deserialize(ipld_wrong);
assert!(error_wrong.is_err());

// Unknown fields are rejected.
let ipld_wrong = Ipld::Map(BTreeMap::from([
("hello".into(), Ipld::Integer(my_struct.hello.into())),
("world".into(), Ipld::Bool(my_struct.world)),
("ignored".into(), Ipld::Bool(true)),
]));
error_except(my_struct, &ipld_wrong);

let error_wrong = MyStruct::deserialize(ipld_wrong);
assert!(error_wrong.is_err());
}
Expand Down