diff --git a/core/src/serde/de.rs b/core/src/serde/de.rs index aa2b283f..74fd054d 100644 --- a/core/src/serde/de.rs +++ b/core/src/serde/de.rs @@ -1,15 +1,34 @@ -use alloc::{borrow::ToOwned, collections::BTreeMap, format, string::String, vec::Vec}; -use core::{convert::TryFrom, fmt}; +use alloc::{ + borrow::ToOwned, + collections::BTreeMap, + format, + string::String, + vec::Vec, +}; +use core::{ + convert::TryFrom, + fmt, +}; -use cid::serde::{BytesToCidVisitor, CID_SERDE_PRIVATE_IDENTIFIER}; -use cid::Cid; +use cid::{ + serde::{ + BytesToCidVisitor, + CID_SERDE_PRIVATE_IDENTIFIER, + }, + Cid, +}; use serde::{ - de::{self, IntoDeserializer}, - forward_to_deserialize_any, + de::{ + self, + IntoDeserializer, + }, + forward_to_deserialize_any, }; -use crate::error::SerdeError; -use crate::ipld::Ipld; +use crate::{ + error::SerdeError, + ipld::Ipld, +}; /// Deserialize instances of [`crate::ipld::Ipld`]. /// @@ -18,727 +37,791 @@ use crate::ipld::Ipld; /// ``` /// use std::collections::BTreeMap; /// +/// use libipld_core::{ +/// ipld::Ipld, +/// serde::from_ipld, +/// }; /// use serde::Deserialize; -/// use libipld_core::ipld::Ipld; -/// use libipld_core::serde::from_ipld; /// /// #[derive(Deserialize)] /// struct Person { -/// name: String, -/// age: u8, -/// hobbies: Vec, -/// is_cool: bool, +/// name: String, +/// age: u8, +/// hobbies: Vec, +/// is_cool: bool, /// } /// -/// let ipld = Ipld::Map({ -/// BTreeMap::from([ -/// ("name".into(), Ipld::String("Hello World!".into())), -/// ("age".into(), Ipld::Integer(52)), -/// ( -/// "hobbies".into(), -/// Ipld::List(vec![ -/// Ipld::String("geography".into()), -/// Ipld::String("programming".into()), -/// ]), -/// ), -/// ("is_cool".into(), Ipld::Bool(true)), -/// ]) -/// }); +/// let ipld = Ipld::List(vec![ +/// Ipld::String("Hello World!".into()), +/// Ipld::Integer(52), +/// Ipld::List(vec![ +/// Ipld::String("geography".into()), +/// Ipld::String("programming".into()), +/// ]), +/// Ipld::Bool(true), +/// ]); /// /// let person = from_ipld(ipld); /// assert!(matches!(person, Ok(Person { .. }))); /// ``` -// NOTE vmx 2021-12-22: Taking by value is also what `serde_json` does. pub fn from_ipld(value: Ipld) -> Result -where - T: serde::de::DeserializeOwned, -{ - T::deserialize(value) +where T: serde::de::DeserializeOwned { + T::deserialize(value) } impl<'de> de::Deserialize<'de> for Ipld { - fn deserialize(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct IpldVisitor; - - impl<'de> de::Visitor<'de> for IpldVisitor { - type Value = Ipld; - - fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.write_str("any valid IPLD kind") - } - - #[inline] - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - Ok(Ipld::String(String::from(value))) - } - - #[inline] - fn visit_bytes(self, v: &[u8]) -> Result - where - E: de::Error, - { - self.visit_byte_buf(v.to_owned()) - } - - #[inline] - fn visit_byte_buf(self, v: Vec) -> Result - where - E: de::Error, - { - Ok(Ipld::Bytes(v)) - } - - #[inline] - fn visit_u64(self, v: u64) -> Result - where - E: de::Error, - { - Ok(Ipld::Integer(v.into())) - } - - #[inline] - fn visit_i64(self, v: i64) -> Result - where - E: de::Error, - { - Ok(Ipld::Integer(v.into())) - } - - #[inline] - fn visit_i128(self, v: i128) -> Result - where - E: de::Error, - { - Ok(Ipld::Integer(v)) - } - - #[inline] - fn visit_f64(self, v: f64) -> Result - where - E: de::Error, - { - Ok(Ipld::Float(v)) - } - - #[inline] - fn visit_bool(self, v: bool) -> Result - where - E: de::Error, - { - Ok(Ipld::Bool(v)) - } - - #[inline] - fn visit_none(self) -> Result - where - E: de::Error, - { - Ok(Ipld::Null) - } - - #[inline] - fn visit_seq(self, mut visitor: V) -> Result - where - V: de::SeqAccess<'de>, - { - let mut vec = Vec::with_capacity(visitor.size_hint().unwrap_or(0)); - - while let Some(elem) = visitor.next_element()? { - vec.push(elem); - } - - Ok(Ipld::List(vec)) - } - - #[inline] - fn visit_map(self, mut visitor: V) -> Result - where - V: de::MapAccess<'de>, - { - let mut values = BTreeMap::new(); - - while let Some((key, value)) = visitor.next_entry()? { - values.insert(key, value); - } - - Ok(Ipld::Map(values)) - } - - /// Newtype structs are only used to deserialize CIDs. - #[inline] - fn visit_newtype_struct(self, deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - deserializer - .deserialize_bytes(BytesToCidVisitor) - .map(Ipld::Link) - } + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> { + struct IpldVisitor; + + impl<'de> de::Visitor<'de> for IpldVisitor { + type Value = Ipld; + + fn expecting(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str("any valid IPLD kind") + } + + #[inline] + fn visit_str(self, value: &str) -> Result + where E: de::Error { + Ok(Ipld::String(String::from(value))) + } + + #[inline] + fn visit_bytes(self, v: &[u8]) -> Result + where E: de::Error { + self.visit_byte_buf(v.to_owned()) + } + + #[inline] + fn visit_byte_buf(self, v: Vec) -> Result + where E: de::Error { + Ok(Ipld::Bytes(v)) + } + + #[inline] + fn visit_u64(self, v: u64) -> Result + where E: de::Error { + Ok(Ipld::Integer(v.into())) + } + + #[inline] + fn visit_i64(self, v: i64) -> Result + where E: de::Error { + Ok(Ipld::Integer(v.into())) + } + + #[inline] + fn visit_i128(self, v: i128) -> Result + where E: de::Error { + Ok(Ipld::Integer(v)) + } + + #[inline] + fn visit_f64(self, v: f64) -> Result + where E: de::Error { + Ok(Ipld::Float(v)) + } + + #[inline] + fn visit_bool(self, v: bool) -> Result + where E: de::Error { + Ok(Ipld::Bool(v)) + } + + #[inline] + fn visit_none(self) -> Result + where E: de::Error { + Ok(Ipld::Null) + } + + #[inline] + fn visit_seq(self, mut visitor: V) -> Result + where V: de::SeqAccess<'de> { + let mut vec = Vec::with_capacity(visitor.size_hint().unwrap_or(0)); + + while let Some(elem) = visitor.next_element()? { + vec.push(elem); + } + + Ok(Ipld::List(vec)) + } + + #[inline] + fn visit_map(self, mut visitor: V) -> Result + where V: de::MapAccess<'de> { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = visitor.next_entry()? { + values.insert(key, value); } - deserializer.deserialize_any(IpldVisitor) + Ok(Ipld::Map(values)) + } + + /// Newtype structs are only used to deserialize CIDs. + #[inline] + fn visit_newtype_struct( + self, + deserializer: D, + ) -> Result + where + D: de::Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesToCidVisitor).map(Ipld::Link) + } } + + deserializer.deserialize_any(IpldVisitor) + } } macro_rules! impl_deserialize_integer { - ($ty:ident, $deserialize:ident, $visit:ident) => { - fn $deserialize>(self, visitor: V) -> Result { - match self { - Self::Integer(integer) => match $ty::try_from(integer) { - Ok(int) => visitor.$visit(int), - Err(_) => error(format!( - "`Ipld::Integer` value was bigger than `{}`", - stringify!($ty) - )), - }, - _ => error(format!( - "Only `Ipld::Integer` can be deserialized to `{}`, input was `{:#?}`", - stringify!($ty), - self - )), - } - } - }; + ($ty:ident, $deserialize:ident, $visit:ident) => { + fn $deserialize>( + self, + visitor: V, + ) -> Result { + match self { + Self::Integer(integer) => match $ty::try_from(integer) { + Ok(int) => visitor.$visit(int), + Err(_) => error(format!( + "`Ipld::Integer` value was bigger than `{}`", + stringify!($ty) + )), + }, + _ => error(format!( + "Only `Ipld::Integer` can be deserialized to `{}`, input was `{:#?}`", + stringify!($ty), + self + )), + } + } + }; } /// A Deserializer for CIDs. /// -/// A separate deserializer is needed to make sure we always deserialize only CIDs as `Ipld::Link` -/// and don't deserialize arbitrary bytes. +/// A separate deserializer is needed to make sure we always deserialize only +/// CIDs as `Ipld::Link` and don't deserialize arbitrary bytes. struct CidDeserializer(Cid); impl<'de> de::Deserializer<'de> for CidDeserializer { - type Error = SerdeError; - - #[inline] - fn deserialize_any>(self, _visitor: V) -> Result { - error("Only bytes can be deserialized into a CID") - } - - fn deserialize_bytes>(self, visitor: V) -> Result { - visitor.visit_bytes(&self.0.to_bytes()) - } - - forward_to_deserialize_any! { - bool byte_buf char enum f32 f64 i8 i16 i32 i64 identifier ignored_any map newtype_struct - option seq str string struct tuple tuple_struct u8 u16 u32 u64 unit unit_struct - } + type Error = SerdeError; + + forward_to_deserialize_any! { + bool byte_buf char enum f32 f64 i8 i16 i32 i64 identifier ignored_any map newtype_struct + option seq str string struct tuple tuple_struct u8 u16 u32 u64 unit unit_struct + } + + #[inline] + fn deserialize_any>( + self, + _visitor: V, + ) -> Result { + error("Only bytes can be deserialized into a CID") + } + + fn deserialize_bytes>( + self, + visitor: V, + ) -> Result { + visitor.visit_bytes(&self.0.to_bytes()) + } } /// Deserialize from an [`Ipld`] enum into a Rust type. /// -/// The deserialization will return an error if you try to deserialize into an integer type that -/// would be too small to hold the value stored in [`Ipld::Integer`]. +/// The deserialization will return an error if you try to deserialize into an +/// integer type that would be too small to hold the value stored in +/// [`Ipld::Integer`]. /// -/// [`Ipld::Floats`] can be converted to `f32` if there is no of precision, else it will error. +/// [`Ipld::Floats`] can be converted to `f32` if there is no of precision, else +/// it will error. impl<'de> de::Deserializer<'de> for Ipld { - type Error = SerdeError; - - #[inline] - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - match self { - Self::Null => visitor.visit_none(), - Self::Bool(bool) => visitor.visit_bool(bool), - Self::Integer(i128) => visitor.visit_i128(i128), - Self::Float(f64) => visitor.visit_f64(f64), - Self::String(string) => visitor.visit_str(&string), - Self::Bytes(bytes) => visitor.visit_bytes(&bytes), - Self::List(list) => visit_seq(list, visitor), - Self::Map(map) => visit_map(map, visitor), - Self::Link(cid) => visitor.visit_newtype_struct(CidDeserializer(cid)), + type Error = SerdeError; + + impl_deserialize_integer!(i8, deserialize_i8, visit_i8); + + impl_deserialize_integer!(i16, deserialize_i16, visit_i16); + + impl_deserialize_integer!(i32, deserialize_i32, visit_i32); + + impl_deserialize_integer!(i64, deserialize_i64, visit_i64); + + impl_deserialize_integer!(u8, deserialize_u8, visit_u8); + + impl_deserialize_integer!(u16, deserialize_u16, visit_u16); + + impl_deserialize_integer!(u32, deserialize_u32, visit_u32); + + impl_deserialize_integer!(u64, deserialize_u64, visit_u64); + + #[inline] + fn deserialize_any(self, visitor: V) -> Result + where V: de::Visitor<'de> { + match self { + Self::Null => visitor.visit_none(), + Self::Bool(bool) => visitor.visit_bool(bool), + Self::Integer(i128) => visitor.visit_i128(i128), + Self::Float(f64) => visitor.visit_f64(f64), + Self::String(string) => visitor.visit_str(&string), + Self::Bytes(bytes) => visitor.visit_bytes(&bytes), + Self::List(list) => visit_seq(list, visitor), + Self::Map(_map) => { + use serde::de::Error; + Err(SerdeError::custom("no deserialization for Maps")) + } + Self::Link(cid) => visitor.visit_newtype_struct(CidDeserializer(cid)), + } + } + + fn deserialize_unit>( + self, + visitor: V, + ) -> Result { + match self { + Self::List(xs) if xs.is_empty() => visitor.visit_unit(), + _ => error(format!( + "Only the empty `Ipld::List` can be deserialized to unit, input was + `{:#?}`", + self + )), + } + } + + fn deserialize_bool>( + self, + visitor: V, + ) -> Result { + match self { + Self::Bool(bool) => visitor.visit_bool(bool), + _ => error(format!( + "Only `Ipld::Bool` can be deserialized to bool, input was `{:#?}`", + self + )), + } + } + + fn deserialize_f32>( + self, + visitor: V, + ) -> Result { + match self { + Self::Float(float) => { + if !float.is_finite() { + error(format!( + "`Ipld::Float` must be a finite number, not infinity or NaN, \ + input was `{}`", + float + )) } - } - - fn deserialize_unit>(self, visitor: V) -> Result { - match self { - Self::Null => visitor.visit_unit(), - _ => error(format!( - "Only `Ipld::Null` can be deserialized to unit, input was `{:#?}`", - self - )), + else if (float as f32) as f64 != float { + error( + "`Ipld::Float` cannot be deserialized to `f32`, without loss of \ + precision`", + ) } - } - - fn deserialize_bool>(self, visitor: V) -> Result { - match self { - Self::Bool(bool) => visitor.visit_bool(bool), - _ => error(format!( - "Only `Ipld::Bool` can be deserialized to bool, input was `{:#?}`", - self - )), + else { + visitor.visit_f32(float as f32) } - } - - impl_deserialize_integer!(i8, deserialize_i8, visit_i8); - impl_deserialize_integer!(i16, deserialize_i16, visit_i16); - impl_deserialize_integer!(i32, deserialize_i32, visit_i32); - impl_deserialize_integer!(i64, deserialize_i64, visit_i64); - - impl_deserialize_integer!(u8, deserialize_u8, visit_u8); - impl_deserialize_integer!(u16, deserialize_u16, visit_u16); - impl_deserialize_integer!(u32, deserialize_u32, visit_u32); - impl_deserialize_integer!(u64, deserialize_u64, visit_u64); - - fn deserialize_f32>(self, visitor: V) -> Result { - match self { - Self::Float(float) => { - if !float.is_finite() { - error(format!("`Ipld::Float` must be a finite number, not infinity or NaN, input was `{}`", float)) - } else if (float as f32) as f64 != float { - error( - "`Ipld::Float` cannot be deserialized to `f32`, without loss of precision`", - ) - } else { - visitor.visit_f32(float as f32) - } - } - _ => error(format!( - "Only `Ipld::Float` can be deserialized to `f32`, input was `{:#?}`", - self - )), + } + _ => error(format!( + "Only `Ipld::Float` can be deserialized to `f32`, input was `{:#?}`", + self + )), + } + } + + fn deserialize_f64>( + self, + visitor: V, + ) -> Result { + match self { + Self::Float(float) => { + if float.is_finite() { + visitor.visit_f64(float) } - } - - fn deserialize_f64>(self, visitor: V) -> Result { - match self { - Self::Float(float) => { - if float.is_finite() { - visitor.visit_f64(float) - } else { - error(format!("`Ipld::Float` must be a finite number, not infinity or NaN, input was `{}`", float)) - } - } - _ => error(format!( - "Only `Ipld::Float` can be deserialized to `f64`, input was `{:#?}`", - self - )), - } - } - - fn deserialize_char>(self, visitor: V) -> Result { - match self { - Self::String(string) => { - if string.chars().count() == 1 { - visitor.visit_char(string.chars().next().unwrap()) - } else { - error("`Ipld::String` was longer than a single character") - } - } - _ => error(format!( - "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", - self - )), + else { + error(format!( + "`Ipld::Float` must be a finite number, not infinity or NaN, \ + input was `{}`", + float + )) } - } - - fn deserialize_str>(self, visitor: V) -> Result { - match self { - Self::String(string) => visitor.visit_str(&string), - _ => error(format!( - "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", - self - )), + } + _ => error(format!( + "Only `Ipld::Float` can be deserialized to `f64`, input was `{:#?}`", + self + )), + } + } + + fn deserialize_char>( + self, + visitor: V, + ) -> Result { + match self { + Self::String(string) => { + if string.chars().count() == 1 { + visitor.visit_char(string.chars().next().unwrap()) } - } - - fn deserialize_string>(self, visitor: V) -> Result { - match self { - Self::String(string) => visitor.visit_string(string), - _ => error(format!( - "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", - self - )), + else { + error("`Ipld::String` was longer than a single character") } - } - - fn deserialize_bytes>(self, visitor: V) -> Result { - match self { - Self::Bytes(bytes) => visitor.visit_bytes(&bytes), - _ => error(format!( - "Only `Ipld::Bytes` can be deserialized to bytes, input was `{:#?}`", - self - )), - } - } - - fn deserialize_byte_buf>( - self, - visitor: V, - ) -> Result { - match self { - Self::Bytes(bytes) => visitor.visit_byte_buf(bytes), - _ => error(format!( - "Only `Ipld::Bytes` can be deserialized to bytes, input was `{:#?}`", - self - )), + } + _ => error(format!( + "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", + self + )), + } + } + + fn deserialize_str>( + self, + visitor: V, + ) -> Result { + match self { + Self::String(string) => visitor.visit_str(&string), + _ => error(format!( + "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", + self + )), + } + } + + fn deserialize_string>( + self, + visitor: V, + ) -> Result { + match self { + Self::String(string) => visitor.visit_string(string), + _ => error(format!( + "Only `Ipld::String` can be deserialized to string, input was `{:#?}`", + self + )), + } + } + + fn deserialize_bytes>( + self, + visitor: V, + ) -> Result { + match self { + Self::Bytes(bytes) => visitor.visit_bytes(&bytes), + _ => error(format!( + "Only `Ipld::Bytes` can be deserialized to bytes, input was `{:#?}`", + self + )), + } + } + + fn deserialize_byte_buf>( + self, + visitor: V, + ) -> Result { + match self { + Self::Bytes(bytes) => visitor.visit_byte_buf(bytes), + _ => error(format!( + "Only `Ipld::Bytes` can be deserialized to bytes, input was `{:#?}`", + self + )), + } + } + + fn deserialize_seq>( + self, + visitor: V, + ) -> Result { + match self { + Self::List(list) => visit_seq(list, visitor), + _ => error(format!( + "Only `Ipld::List` can be deserialized to sequence, input was `{:#?}`", + self + )), + } + } + + fn deserialize_tuple>( + self, + len: usize, + visitor: V, + ) -> Result { + match self { + Self::List(list) => { + if len == list.len() { + visit_seq(list, visitor) } - } - - fn deserialize_seq>(self, visitor: V) -> Result { - match self { - Self::List(list) => visit_seq(list, visitor), - _ => error(format!( - "Only `Ipld::List` can be deserialized to sequence, input was `{:#?}`", - self - )), + else { + error(format!( + "The tuple size must match the length of the `Ipld::List`, tuple \ + size: {}, `Ipld::List` length: {}", + len, + list.len() + )) } - } - - fn deserialize_tuple>( - self, - len: usize, - visitor: V, - ) -> Result { - 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())) - } - } - _ => error(format!( - "Only `Ipld::List` can be deserialized to tuple, input was `{:#?}`", - self - )), + } + _ => error(format!( + "Only `Ipld::List` can be deserialized to tuple, input was `{:#?}`", + self + )), + } + } + + fn deserialize_tuple_struct>( + self, + _name: &str, + len: usize, + visitor: V, + ) -> Result { + self.deserialize_tuple(len, visitor) + } + + fn deserialize_map>( + self, + visitor: V, + ) -> Result { + match self { + Self::List(map) => visit_map(map, visitor), + _ => error(format!( + "Only `Ipld::List` can be deserialized to map, input was `{:#?}`", + self + )), + } + } + + fn deserialize_identifier>( + self, + visitor: V, + ) -> Result { + match self { + Self::String(string) => visitor.visit_str(&string), + _ => error(format!( + "Only `Ipld::String` can be deserialized to identifier, input was \ + `{:#?}`", + self + )), + } + } + + fn deserialize_struct>( + self, + _name: &str, + _fields: &[&str], + visitor: V, + ) -> Result { + match self { + Self::List(vec) => visit_seq(vec, visitor), + _ => error(format!( + "Only `Ipld::List` can be deserialized to struct, input was `{:#?}`", + self + )), + } + } + + fn deserialize_unit_struct>( + self, + _name: &str, + _visitor: V, + ) -> Result { + error("Unit struct cannot be deserialized") + } + + fn deserialize_newtype_struct>( + self, + name: &str, + visitor: V, + ) -> Result { + if name == CID_SERDE_PRIVATE_IDENTIFIER { + match self { + Ipld::Link(cid) => visitor.visit_newtype_struct(CidDeserializer(cid)), + _ => error(format!( + "Only `Ipld::Link`s can be deserialized to CIDs, input was `{:#?}`", + self + )), + } + } + else { + visitor.visit_newtype_struct(self) + } + } + + fn deserialize_enum>( + self, + _name: &str, + variants: &[&str], + visitor: V, + ) -> Result { + let (variant, value) = match self { + Ipld::List(xs) if xs.len() >= 1 => match &xs[0] { + Ipld::Integer(idx) + if *idx >= 0i128 && *idx < variants.len() as i128 => + { + let idx = *idx as usize; + let variant = String::from(variants[idx]); + let value = if xs.len() == 1 { + None + } + else { + Some(Ipld::List(xs[1..].to_owned())) + }; + (variant, value) } - } - - fn deserialize_tuple_struct>( - self, - _name: &str, - len: usize, - visitor: V, - ) -> Result { - self.deserialize_tuple(len, visitor) - } - - fn deserialize_map>(self, visitor: V) -> Result { - match self { - Self::Map(map) => visit_map(map, visitor), - _ => error(format!( - "Only `Ipld::Map` can be deserialized to map, input was `{:#?}`", - self - )), + bad_tag => { + return error(format!( + "`enum` tags must be an Ipld::Integer between and the maximum \ + number of variants {:#?}, input was `{:#?}`", + variants.len(), + bad_tag.clone() + )); } - } - - fn deserialize_identifier>( - self, - visitor: V, - ) -> Result { - match self { - Self::String(string) => visitor.visit_str(&string), - _ => error(format!( - "Only `Ipld::String` can be deserialized to identifier, input was `{:#?}`", - self - )), - } - } - - fn deserialize_struct>( - self, - _name: &str, - _fields: &[&str], - visitor: V, - ) -> Result { - match self { - Self::Map(map) => visit_map(map, visitor), - _ => error(format!( - "Only `Ipld::Map` can be deserialized to struct, input was `{:#?}`", - self - )), - } - } - - fn deserialize_unit_struct>( - self, - _name: &str, - _visitor: V, - ) -> Result { - error("Unit struct cannot be deserialized") - } - - fn deserialize_newtype_struct>( - self, - name: &str, - visitor: V, - ) -> Result { - if name == CID_SERDE_PRIVATE_IDENTIFIER { - match self { - Ipld::Link(cid) => visitor.visit_newtype_struct(CidDeserializer(cid)), - _ => error(format!( - "Only `Ipld::Link`s can be deserialized to CIDs, input was `{:#?}`", - self - )), - } - } else { - visitor.visit_newtype_struct(self) - } - } - - // Heavily based on - // https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L249 - fn deserialize_enum>( - self, - _name: &str, - _variants: &[&str], - visitor: V, - ) -> Result { - let (variant, value) = match self { - Ipld::Map(map) => { - let mut iter = map.into_iter(); - let (variant, value) = match iter.next() { - Some(v) => v, - None => { - return error( - "Only `Ipld::Map`s with a single key can be deserialized to `enum`, input had no keys" - ); - } - }; - // Enums are encoded in IPLD as maps with a single key-value pair - if iter.next().is_some() { - return error( - "Only `Ipld::Map`s with a single key can be deserialized to `enum`, input had more keys" - ); - } - (variant, Some(value)) - } - Ipld::String(variant) => (variant, None), - _ => return error(format!( - "Only `Ipld::Map` and `Ipld::String` can be deserialized to `enum`, input was `{:#?}`", - self - )), - }; - - visitor.visit_enum(EnumDeserializer { variant, value }) - } - - // Heavily based on - // https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L446 - fn deserialize_ignored_any>( - self, - visitor: V, - ) -> Result { - drop(self); - visitor.visit_unit() - } + }, + _ => { + return error(format!( + "Only `Ipld::List` can be deserialized to `enum`, input was `{:#?}`", + self + )); + } + }; - fn deserialize_option>(self, visitor: V) -> Result { - match self { - Self::Null => visitor.visit_none(), - _ => visitor.visit_some(self), - } - } + visitor.visit_enum(EnumDeserializer { variant, value }) + } + + fn deserialize_ignored_any>( + self, + visitor: V, + ) -> Result { + drop(self); + visitor.visit_unit() + } + + fn deserialize_option>( + self, + visitor: V, + ) -> Result { + match self { + Self::Null => visitor.visit_none(), + _ => visitor.visit_some(self), + } + } } -fn visit_map<'de, V>(map: BTreeMap, visitor: V) -> Result +fn visit_map<'de, V>( + map: Vec, + visitor: V, +) -> Result where - V: de::Visitor<'de>, + V: de::Visitor<'de>, { - let mut deserializer = MapDeserializer::new(map); - visitor.visit_map(&mut deserializer) + let mut deserializer = MapDeserializer::new(map); + visitor.visit_map(&mut deserializer) } -fn visit_seq<'de, V>(list: Vec, visitor: V) -> Result +fn visit_seq<'de, V>( + list: Vec, + visitor: V, +) -> Result where - V: de::Visitor<'de>, + V: de::Visitor<'de>, { - let mut deserializer = SeqDeserializer::new(list); - visitor.visit_seq(&mut deserializer) + let mut deserializer = SeqDeserializer::new(list); + visitor.visit_seq(&mut deserializer) } -// Heavily based on -// https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L601 struct MapDeserializer { - iter: as IntoIterator>::IntoIter, - value: Option, + iter: as IntoIterator>::IntoIter, + value: Option, } impl MapDeserializer { - fn new(map: BTreeMap) -> Self { - Self { - iter: map.into_iter(), - value: None, - } - } + fn new(map: Vec) -> Self { Self { iter: map.into_iter(), value: None } } } impl<'de> de::MapAccess<'de> for MapDeserializer { - type Error = SerdeError; - - fn next_key_seed(&mut self, seed: K) -> Result, Self::Error> - where - K: de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some((key, value)) => { - self.value = Some(value); - seed.deserialize(Ipld::String(key)).map(Some) - } - None => Ok(None), + type Error = SerdeError; + + fn next_key_seed( + &mut self, + seed: K, + ) -> Result, Self::Error> + where + K: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(Ipld::List(xs)) => match xs.as_slice() { + [key, val] => { + self.value = Some(val.to_owned()); + seed.deserialize(key.to_owned()).map(Some) } + _ => todo!(), + }, + Some(_) => { + todo!() + } + None => Ok(None), } + } - fn next_value_seed(&mut self, seed: T) -> Result - where - T: de::DeserializeSeed<'de>, - { - match self.value.take() { - Some(value) => seed.deserialize(value), - None => error("value is missing"), - } + fn next_value_seed(&mut self, seed: T) -> Result + where T: de::DeserializeSeed<'de> { + match self.value.take() { + Some(value) => seed.deserialize(value), + None => error("value is missing"), } + } - fn size_hint(&self) -> Option { - match self.iter.size_hint() { - (lower, Some(upper)) if lower == upper => Some(upper), - _ => None, - } + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, } + } } // Heavily based on // https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L554 struct SeqDeserializer { - iter: as IntoIterator>::IntoIter, + iter: as IntoIterator>::IntoIter, } impl SeqDeserializer { - fn new(vec: Vec) -> Self { - Self { - iter: vec.into_iter(), - } - } + fn new(vec: Vec) -> Self { Self { iter: vec.into_iter() } } } impl<'de> de::SeqAccess<'de> for SeqDeserializer { - type Error = SerdeError; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: de::DeserializeSeed<'de>, - { - match self.iter.next() { - Some(value) => seed.deserialize(value).map(Some), - None => Ok(None), - } - } - - fn size_hint(&self) -> Option { - match self.iter.size_hint() { - (lower, Some(upper)) if lower == upper => Some(upper), - _ => None, - } - } + type Error = SerdeError; + + fn next_element_seed( + &mut self, + seed: T, + ) -> Result, Self::Error> + where + T: de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(value) => seed.deserialize(value).map(Some), + None => Ok(None), + } + } + + fn size_hint(&self) -> Option { + match self.iter.size_hint() { + (lower, Some(upper)) if lower == upper => Some(upper), + _ => None, + } + } } -// Heavily based on -// https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L455 struct EnumDeserializer { - variant: String, - value: Option, + variant: String, + value: Option, } impl<'de> de::EnumAccess<'de> for EnumDeserializer { - type Error = SerdeError; - type Variant = VariantDeserializer; - - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> - where - V: de::DeserializeSeed<'de>, - { - let variant = self.variant.into_deserializer(); - let visitor = VariantDeserializer(self.value); - seed.deserialize(variant).map(|v| (v, visitor)) - } + type Error = SerdeError; + type Variant = VariantDeserializer; + + fn variant_seed( + self, + seed: V, + ) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: de::DeserializeSeed<'de>, + { + let variant = self.variant.into_deserializer(); + let visitor = VariantDeserializer(self.value); + seed.deserialize(variant).map(|v| (v, visitor)) + } } -// Heavily based on -// https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/de.rs#L482 struct VariantDeserializer(Option); impl<'de> de::VariantAccess<'de> for VariantDeserializer { - type Error = SerdeError; - - fn unit_variant(self) -> Result<(), Self::Error> { - match self.0 { - Some(value) => de::Deserialize::deserialize(value), - None => Ok(()), - } - } - - fn newtype_variant_seed(self, seed: T) -> Result - where - T: de::DeserializeSeed<'de>, - { - match self.0 { - Some(value) => seed.deserialize(value), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"newtype variant", - )), + type Error = SerdeError; + + fn unit_variant(self) -> Result<(), Self::Error> { + match self.0 { + Some(value) => de::Deserialize::deserialize(value), + None => Ok(()), + } + } + + fn newtype_variant_seed(self, seed: T) -> Result + where T: de::DeserializeSeed<'de> { + match self.0 { + Some(Ipld::List(xs)) => match xs.as_slice() { + [value] => seed.deserialize(value.to_owned()), + _ => Err(de::Error::invalid_type( + de::Unexpected::TupleVariant, + &"newtype variant", + )), + }, + _ => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"newtype variant", + )), + } + } + + fn tuple_variant( + self, + len: usize, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self.0 { + Some(Ipld::List(list)) => { + if len == list.len() { + visit_seq(list, visitor) } - } - - fn tuple_variant(self, len: usize, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - match self.0 { - Some(Ipld::List(list)) => { - if len == list.len() { - visit_seq(list, visitor) - } else { - error(format!("The tuple variant size must match the length of the `Ipld::List`, tuple variant size: {}, `Ipld::List` length: {}", len, list.len())) - } - } - Some(_) => error(format!( - "Only `Ipld::List` can be deserialized to tuple variant, input was `{:#?}`", - self.0 - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"tuple variant", - )), + else { + error(format!( + "The tuple variant size must match the length of the \ + `Ipld::List`, tuple variant size: {}, `Ipld::List` length: {}", + len, + list.len() + )) } - } - - fn struct_variant( - self, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - match self.0 { - Some(Ipld::Map(v)) => visit_map(v, visitor), - Some(_) => error(format!( - "Only `Ipld::Map` can be deserialized to struct variant, input was `{:#?}`", - self.0 - )), - None => Err(de::Error::invalid_type( - de::Unexpected::UnitVariant, - &"struct variant", - )), - } - } + } + Some(_) => error(format!( + "Only `Ipld::List` can be deserialized to tuple variant, input was \ + `{:#?}`", + self.0 + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"tuple variant", + )), + } + } + + fn struct_variant( + self, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + match self.0 { + Some(Ipld::List(xs)) => visit_seq(xs, visitor), + Some(_) => error(format!( + "Only `Ipld::List` can be deserialized to struct variant, input was \ + `{:#?}`", + self.0 + )), + None => Err(de::Error::invalid_type( + de::Unexpected::UnitVariant, + &"struct variant", + )), + } + } } /// Returns a general error. fn error(message: S) -> Result -where - S: AsRef + fmt::Display, -{ - Err(de::Error::custom(message)) +where S: AsRef + fmt::Display { + Err(de::Error::custom(message)) } diff --git a/core/src/serde/mod.rs b/core/src/serde/mod.rs index e502fe79..99ed52bf 100644 --- a/core/src/serde/mod.rs +++ b/core/src/serde/mod.rs @@ -1,7 +1,9 @@ //! Serde (de)serializtion for [`crate::ipld::Ipld`]. //! -//! This implementation enables Serde to serialize to/deserialize from [`crate::ipld::Ipld`] -//! values. The `Ipld` enum is similar to the `Value` enum in `serde_json` or `serde_cbor`. +//! This implementation enables Serde to serialize to/deserialize from +//! [`crate::ipld::Ipld`] values. The `Ipld` enum is similar to the `Value` enum +//! in `serde_json` or `serde_cbor`. + mod de; mod ser; @@ -9,127 +11,176 @@ pub use de::from_ipld; pub use ser::to_ipld; #[cfg(test)] -mod tests { - use std::collections::BTreeMap; - use std::convert::TryFrom; - use std::fmt; - - use cid::serde::CID_SERDE_PRIVATE_IDENTIFIER; - use cid::Cid; - use serde::{de::DeserializeOwned, Deserialize, Serialize}; - use serde_test::{assert_tokens, Token}; - - use crate::ipld::Ipld; - use crate::serde::{from_ipld, to_ipld}; - - /// Utility for testing (de)serialization of [`Ipld`]. - /// - /// Checks if `data` and `ipld` match if they are encoded into each other. - fn assert_roundtrip(data: &T, ipld: &Ipld) - where - T: Serialize + DeserializeOwned + PartialEq + fmt::Debug, - { - let encoded: Ipld = to_ipld(&data).unwrap(); - assert_eq!(&encoded, ipld); - let decoded: T = from_ipld(ipld.clone()).unwrap(); - assert_eq!(&decoded, data); - } +mod test { + use std::{ + convert::TryFrom, + fmt, + }; - #[derive(Debug, Deserialize, PartialEq, Serialize)] - struct Person { - name: String, - age: u8, - hobbies: Vec, - is_cool: bool, - link: Cid, - } + use alloc::collections::BTreeMap; + use cid::{ + serde::CID_SERDE_PRIVATE_IDENTIFIER, + Cid, + }; + use serde::{ + de::DeserializeOwned, + Deserialize, + Serialize, + }; + use serde_test::{ + assert_tokens, + Token, + }; - impl Default for Person { - fn default() -> Self { - Self { - name: "Hello World!".into(), - age: 52, - hobbies: vec!["geography".into(), "programming".into()], - is_cool: true, - link: Cid::try_from("bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily") - .unwrap(), - } - } - } + use crate::{ + ipld::Ipld, + serde::{ + from_ipld, + to_ipld, + }, + }; - #[test] - fn test_tokens() { - let person = Person::default(); - - assert_tokens( - &person, - &[ - Token::Struct { - name: "Person", - len: 5, - }, - Token::Str("name"), - Token::Str("Hello World!"), - Token::Str("age"), - Token::U8(52), - Token::Str("hobbies"), - Token::Seq { len: Some(2) }, - Token::Str("geography"), - Token::Str("programming"), - Token::SeqEnd, - Token::Str("is_cool"), - Token::Bool(true), - Token::Str("link"), - Token::NewtypeStruct { - name: CID_SERDE_PRIVATE_IDENTIFIER, - }, - Token::Bytes(&[ - 0x01, 0x71, 0x12, 0x20, 0x35, 0x4d, 0x45, 0x5f, 0xf3, 0xa6, 0x41, 0xb8, 0xca, - 0xc2, 0x5c, 0x38, 0xa7, 0x7e, 0x64, 0xaa, 0x73, 0x5d, 0xc8, 0xa4, 0x89, 0x66, - 0xa6, 0xf, 0x1a, 0x78, 0xca, 0xa1, 0x72, 0xa4, 0x88, 0x5e, - ]), - Token::StructEnd, - ], - ); - } + /// Utility for testing (de)serialization of [`Ipld`]. + /// Checks if `data` and `ipld` match if they are encoded into each other. + fn assert_roundtrip(data: &T, ipld: &Ipld) + where T: Serialize + DeserializeOwned + PartialEq + fmt::Debug { + let encoded: Ipld = to_ipld(&data).unwrap(); + assert_eq!(&encoded, ipld); + let decoded: T = from_ipld(ipld.clone()).unwrap(); + assert_eq!(&decoded, data); + } - /// Test if converting to a struct from [`crate::ipld::Ipld`] and back works. - #[test] - fn test_ipld() { - let person = Person::default(); - - let expected_ipld = Ipld::Map({ - BTreeMap::from([ - ("name".into(), Ipld::String("Hello World!".into())), - ("age".into(), Ipld::Integer(52)), - ( - "hobbies".into(), - Ipld::List(vec![ - Ipld::String("geography".into()), - Ipld::String("programming".into()), - ]), - ), - ("is_cool".into(), Ipld::Bool(true)), - ("link".into(), Ipld::Link(person.link)), - ]) - }); - - assert_roundtrip(&person, &expected_ipld); + #[derive(Debug, Deserialize, PartialEq, Serialize)] + struct Person { + name: String, + age: u8, + hobbies: Vec, + is_cool: bool, + link: Cid, + } + + impl Default for Person { + fn default() -> Self { + Self { + name: "Hello World!".into(), + age: 52, + hobbies: vec!["geography".into(), "programming".into()], + is_cool: true, + link: Cid::try_from( + "bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily", + ) + .unwrap(), + } } + } - /// Test that deserializing arbitrary bytes are not accidently recognized as CID. - #[test] - fn test_bytes_not_cid() { - let cid = - Cid::try_from("bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily").unwrap(); + #[derive(Debug, Deserialize, PartialEq, Serialize)] + enum Enum { + UnitVariant, + NewTypeVariant(bool), + TupleVariant(bool, u8), + StructVariant { x: bool, y: u8 }, + } - let bytes_not_cid = Ipld::Bytes(cid.to_bytes()); - let not_a_cid: Result = from_ipld(bytes_not_cid); - assert!(not_a_cid.is_err()); + #[test] + fn test_tokens() { + let person = Person::default(); - // Make sure that a Ipld::Link deserializes correctly though. - let link = Ipld::Link(cid); - let a_cid: Cid = from_ipld(link).unwrap(); - assert_eq!(a_cid, cid); - } + assert_tokens(&person, &[ + Token::Struct { name: "Person", len: 5 }, + Token::Str("name"), + Token::Str("Hello World!"), + Token::Str("age"), + Token::U8(52), + Token::Str("hobbies"), + Token::Seq { len: Some(2) }, + Token::Str("geography"), + Token::Str("programming"), + Token::SeqEnd, + Token::Str("is_cool"), + Token::Bool(true), + Token::Str("link"), + Token::NewtypeStruct { name: CID_SERDE_PRIVATE_IDENTIFIER }, + Token::Bytes(&[ + 0x01, 0x71, 0x12, 0x20, 0x35, 0x4d, 0x45, 0x5f, 0xf3, 0xa6, 0x41, 0xb8, + 0xca, 0xc2, 0x5c, 0x38, 0xa7, 0x7e, 0x64, 0xaa, 0x73, 0x5d, 0xc8, 0xa4, + 0x89, 0x66, 0xa6, 0xf, 0x1a, 0x78, 0xca, 0xa1, 0x72, 0xa4, 0x88, 0x5e, + ]), + Token::StructEnd, + ]); + } + + /// Test if converting to a struct from [`crate::ipld::Ipld`] and back works. + #[test] + fn test_ipld() { + let person = Person::default(); + + let expected_ipld = Ipld::List(vec![ + Ipld::String("Hello World!".into()), + Ipld::Integer(52), + Ipld::List(vec![ + Ipld::String("geography".into()), + Ipld::String("programming".into()), + ]), + Ipld::Bool(true), + Ipld::Link(person.link), + ]); + + assert_roundtrip(&person, &expected_ipld); + + let unit_enum = Enum::UnitVariant; + let expected_ipld = Ipld::List(vec![Ipld::Integer(0)]); + assert_roundtrip(&unit_enum, &expected_ipld); + + let newtype_enum = Enum::NewTypeVariant(true); + let expected_ipld = Ipld::List(vec![Ipld::Integer(1), Ipld::Bool(true)]); + assert_roundtrip(&newtype_enum, &expected_ipld); + + let tuple_enum = Enum::TupleVariant(true, 1u8); + let expected_ipld = Ipld::List(vec![ + Ipld::Integer(2), + Ipld::Bool(true), + Ipld::Integer(1i128), + ]); + assert_roundtrip(&tuple_enum, &expected_ipld); + let struct_enum = Enum::StructVariant { x: true, y: 1u8 }; + let expected_ipld = Ipld::List(vec![ + Ipld::Integer(3), + Ipld::Bool(true), + Ipld::Integer(1i128), + ]); + assert_roundtrip(&struct_enum, &expected_ipld); + + let unit = (); + let expected_ipld = Ipld::List(vec![]); + + assert_roundtrip(&unit, &expected_ipld); + + let map: BTreeMap = + BTreeMap::from([("hello".into(), 1u64), ("world!".into(), 7u64)]); + let expected_ipld = Ipld::List(vec![ + Ipld::List(vec![Ipld::String("hello".into()), Ipld::Integer(1i128)]), + Ipld::List(vec![Ipld::String("world!".into()), Ipld::Integer(7i128)]), + ]); + assert_roundtrip(&map, &expected_ipld); + } + + /// Test that deserializing arbitrary bytes are not accidently recognized as + /// CID. + #[test] + fn test_bytes_not_cid() { + let cid = Cid::try_from( + "bafyreibvjvcv745gig4mvqs4hctx4zfkono4rjejm2ta6gtyzkqxfjeily", + ) + .unwrap(); + + let bytes_not_cid = Ipld::Bytes(cid.to_bytes()); + let not_a_cid: Result = from_ipld(bytes_not_cid); + assert!(not_a_cid.is_err()); + + // Make sure that a Ipld::Link deserializes correctly though. + let link = Ipld::Link(cid); + let a_cid: Cid = from_ipld(link).unwrap(); + assert_eq!(a_cid, cid); + } } diff --git a/core/src/serde/ser.rs b/core/src/serde/ser.rs index 94b60384..c90e4648 100644 --- a/core/src/serde/ser.rs +++ b/core/src/serde/ser.rs @@ -1,486 +1,543 @@ -// Parts of this code is based on -// https://github.com/serde-rs/json/blob/95f67a09399d546d9ecadeb747a845a77ff309b2/src/value/ser.rs use alloc::{ - borrow::ToOwned, - collections::BTreeMap, - format, - string::{String, ToString}, - vec::Vec, + borrow::ToOwned, + format, + string::ToString, + vec::Vec, }; use core::convert::TryFrom; -use cid::serde::CID_SERDE_PRIVATE_IDENTIFIER; -use cid::Cid; +use cid::{ + serde::CID_SERDE_PRIVATE_IDENTIFIER, + Cid, +}; use serde::ser; -use crate::error::SerdeError; -use crate::ipld::Ipld; +use crate::{ + error::SerdeError, + ipld::Ipld, +}; /// Serialize into instances of [`crate::ipld::Ipld`]. /// -/// All Rust types can be serialized to [`crate::ipld::Ipld`], here is a list of how they are -/// converted: +/// All Rust types can be serialized to [`crate::ipld::Ipld`], here is a list of +/// how they are converted: /// /// - bool -> `Ipld::Bool` -/// - i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize -> `Ipld::Integer` -/// - f32, f64 -> `Ipld::Float` +/// - i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize -> +/// `Ipld::Integer` +/// - f32, f64 -> `Ipld::Float`, but `f32::NaN` and `f64::NaN` are not +/// serializable and will error /// - char, String -> `Ipld::String` /// - slices -> `Ipld::List` /// - struct -/// - struct -> `Ipld::Map` +/// - struct -> `Ipld::List` /// - newtype struct -> the value the struct wraps /// - tuple struct -> `Ipld::List` -/// - unit struct -> cannot be serialized, it errors +/// - unit struct -> the empty `Ipld::List` /// - enum: -/// - unit variant -> `Ipld::String` of the variant name -/// - newtype variant -> single element `Ipld::Map`, key: variant name, value: the one the -/// newtype wraps -/// - tuple variant -> single element `Ipld::Map`, key: variant name, value: `Ipld::List` -/// - struct variant -> single element `Ipld::Map`, key: variant name, value: `Ipld::Map` -/// - unit (`()`) -> cannot be serialized, it errors +/// - unit variant -> indexed Ipld::List, +/// - newtype variant -> indexed Ipld::List, `[idx, value]` +/// - tuple variant -> `indexed Ipld::List, `[idx, value0, value1, ..., +/// valueN]` +/// - struct variant -> `indexed Ipld::List, `[idx, value0, value1, ..., +/// valueN]` +/// - unit (`()`) -> an empty Ipld::List /// /// There are also common compound types that are supported: /// /// - [`std::option::Option`] -> eithe `Ipld::Null` or the value /// - [`serde_bytes::ByteBuf`] -> `Ipld::Bytes` /// - lists (like e.g. [`std::vec::Vec`]) -> `Ipld::List` -/// - maps (like e.g. [`std::collections::BTreeMap`]) -> `Ipld::Map` +/// - maps (like e.g. [`std::collections::BTreeMap`]) -> `Ipld::List` of key +/// value pairs /// - [`cid::Cid`] -> `Ipld::Link` /// /// /// # Example /// /// ``` +/// use libipld_core::{ +/// ipld::Ipld, +/// serde::to_ipld, +/// }; /// use serde::Serialize; -/// use libipld_core::ipld::Ipld; -/// use libipld_core::serde::to_ipld; /// /// #[derive(Serialize)] /// struct Person { -/// name: String, -/// age: u8, -/// hobbies: Vec, -/// is_cool: bool, +/// name: String, +/// age: u8, +/// hobbies: Vec, +/// is_cool: bool, /// } /// /// let person = Person { -/// name: "Hello World!".into(), -/// age: 52, -/// hobbies: vec!["geography".into(), "programming".into()], -/// is_cool: true, +/// name: "Hello World!".into(), +/// age: 52, +/// hobbies: vec!["geography".into(), "programming".into()], +/// is_cool: true, /// }; /// /// let ipld = to_ipld(person); -/// assert!(matches!(ipld, Ok(Ipld::Map(_)))); -/// ``` +/// assert!(matches!(ipld, Ok(Ipld::List(_)))); pub fn to_ipld(value: T) -> Result -where - T: ser::Serialize, -{ - value.serialize(Serializer) +where T: ser::Serialize { + value.serialize(&Serializer) } impl ser::Serialize for Ipld { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - match &self { - Self::Null => serializer.serialize_none(), - Self::Bool(value) => serializer.serialize_bool(*value), - Self::Integer(value) => serializer.serialize_i128(*value), - Self::Float(value) => serializer.serialize_f64(*value), - Self::String(value) => serializer.serialize_str(value), - Self::Bytes(value) => serializer.serialize_bytes(value), - Self::List(value) => serializer.collect_seq(value), - Self::Map(value) => serializer.collect_map(value), - Self::Link(value) => value.serialize(serializer), - } - } + fn serialize(&self, serializer: S) -> Result + where S: ser::Serializer { + match &self { + Self::Null => serializer.serialize_none(), + Self::Bool(value) => serializer.serialize_bool(*value), + Self::Integer(value) => serializer.serialize_i128(*value), + Self::Float(value) => serializer.serialize_f64(*value), + Self::String(value) => serializer.serialize_str(value), + Self::Bytes(value) => serializer.serialize_bytes(value), + Self::List(value) => serializer.collect_seq(value), + Self::Map(value) => serializer.collect_seq(value), + Self::Link(value) => value.serialize(serializer), + } + } } struct Serializer; -impl serde::Serializer for Serializer { - type Ok = Ipld; - type Error = SerdeError; - - type SerializeSeq = SerializeVec; - type SerializeTuple = SerializeVec; - type SerializeTupleStruct = SerializeVec; - type SerializeTupleVariant = SerializeTupleVariant; - type SerializeMap = SerializeMap; - type SerializeStruct = SerializeMap; - type SerializeStructVariant = SerializeStructVariant; - - #[inline] - fn serialize_bool(self, value: bool) -> Result { - Ok(Self::Ok::Bool(value)) - } - - #[inline] - fn serialize_i8(self, value: i8) -> Result { - self.serialize_i64(i64::from(value)) - } - - #[inline] - fn serialize_i16(self, value: i16) -> Result { - self.serialize_i64(i64::from(value)) - } - - #[inline] - fn serialize_i32(self, value: i32) -> Result { - self.serialize_i64(i64::from(value)) - } - - #[inline] - fn serialize_i64(self, value: i64) -> Result { - self.serialize_i128(i128::from(value)) - } - - fn serialize_i128(self, value: i128) -> Result { - Ok(Self::Ok::Integer(value)) - } - - #[inline] - fn serialize_u8(self, value: u8) -> Result { - self.serialize_i128(value.into()) - } - - #[inline] - fn serialize_u16(self, value: u16) -> Result { - self.serialize_i128(value.into()) - } - - #[inline] - fn serialize_u32(self, value: u32) -> Result { - self.serialize_i128(value.into()) - } - - #[inline] - fn serialize_u64(self, value: u64) -> Result { - self.serialize_i128(value.into()) - } - - #[inline] - fn serialize_f32(self, value: f32) -> Result { - self.serialize_f64(f64::from(value)) - } - - #[inline] - fn serialize_f64(self, value: f64) -> Result { - Ok(Self::Ok::Float(value)) - } - - #[inline] - fn serialize_char(self, value: char) -> Result { - self.serialize_str(&value.to_string()) - } - - #[inline] - fn serialize_str(self, value: &str) -> Result { - Ok(Self::Ok::String(value.to_owned())) - } - - fn serialize_bytes(self, value: &[u8]) -> Result { - Ok(Self::Ok::Bytes(value.to_vec())) - } - - #[inline] - fn serialize_unit(self) -> Result { - Err(ser::Error::custom("Unit is not supported")) - } - - #[inline] - fn serialize_unit_struct(self, _name: &'static str) -> Result { - Err(ser::Error::custom("Unit structs are not supported")) - } - - #[inline] - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - ) -> Result { - self.serialize_str(variant) - } - - #[inline] - fn serialize_newtype_struct( - self, - name: &'static str, - value: &T, - ) -> Result - where - T: ser::Serialize, - { - let ipld = value.serialize(self); - if name == CID_SERDE_PRIVATE_IDENTIFIER { - if let Ok(Ipld::Bytes(bytes)) = ipld { - let cid = Cid::try_from(bytes) - .map_err(|err| ser::Error::custom(format!("Invalid CID: {}", err)))?; - return Ok(Self::Ok::Link(cid)); - } - } - ipld - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - value: &T, - ) -> Result - where - T: ser::Serialize, - { - let values = BTreeMap::from([(variant.to_owned(), value.serialize(self)?)]); - Ok(Self::Ok::Map(values)) - } - - #[inline] - fn serialize_none(self) -> Result { - Ok(Self::Ok::Null) - } - - #[inline] - fn serialize_some(self, value: &T) -> Result - where - T: ser::Serialize, - { - value.serialize(self) - } - - fn serialize_seq(self, len: Option) -> Result { - Ok(SerializeVec { - vec: Vec::with_capacity(len.unwrap_or(0)), - }) - } - - fn serialize_tuple(self, len: usize) -> Result { - self.serialize_seq(Some(len)) - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.serialize_tuple(len) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - len: usize, - ) -> Result { - Ok(SerializeTupleVariant { - name: String::from(variant), - vec: Vec::with_capacity(len), - }) - } - - fn serialize_map(self, _len: Option) -> Result { - Ok(SerializeMap { - map: BTreeMap::new(), - next_key: None, - }) - } - - fn serialize_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.serialize_map(Some(len)) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - variant: &'static str, - _len: usize, - ) -> Result { - Ok(SerializeStructVariant { - name: String::from(variant), - map: BTreeMap::new(), - }) - } +pub struct StructSerializer<'a> { + ser: &'a Serializer, + vec: Vec, + variant_index: u32, +} - #[inline] - fn is_human_readable(&self) -> bool { - false - } +impl<'a> serde::Serializer for &'a Serializer { + type Error = SerdeError; + type Ok = Ipld; + type SerializeMap = SerializeMap; + type SerializeSeq = SerializeVec; + type SerializeStruct = StructSerializer<'a>; + type SerializeStructVariant = StructSerializer<'a>; + type SerializeTuple = SerializeVec; + type SerializeTupleStruct = SerializeVec; + type SerializeTupleVariant = SerializeTupleVariant; + + #[inline] + fn serialize_bool(self, value: bool) -> Result { + Ok(Self::Ok::Bool(value)) + } + + #[inline] + fn serialize_i8(self, value: i8) -> Result { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i16(self, value: i16) -> Result { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i32(self, value: i32) -> Result { + self.serialize_i64(i64::from(value)) + } + + #[inline] + fn serialize_i64(self, value: i64) -> Result { + self.serialize_i128(i128::from(value)) + } + + fn serialize_i128(self, value: i128) -> Result { + Ok(Self::Ok::Integer(value)) + } + + #[inline] + fn serialize_u8(self, value: u8) -> Result { + self.serialize_i128(value.into()) + } + + #[inline] + fn serialize_u16(self, value: u16) -> Result { + self.serialize_i128(value.into()) + } + + #[inline] + fn serialize_u32(self, value: u32) -> Result { + self.serialize_i128(value.into()) + } + + #[inline] + fn serialize_u64(self, value: u64) -> Result { + self.serialize_i128(value.into()) + } + + #[inline] + fn serialize_f32(self, value: f32) -> Result { + if value.is_nan() || value.is_infinite() { + Err(ser::Error::custom("Cannot serialize NaN or infinity for f32")) + } + else { + self.serialize_f64(f64::from(value)) + } + } + + #[inline] + fn serialize_f64(self, value: f64) -> Result { + if value.is_nan() || value.is_infinite() { + Err(ser::Error::custom("Cannot serialize NaN or infinity for f64")) + } + else { + Ok(Self::Ok::Float(value)) + } + } + + #[inline] + fn serialize_char(self, value: char) -> Result { + self.serialize_str(&value.to_string()) + } + + #[inline] + fn serialize_str(self, value: &str) -> Result { + Ok(Self::Ok::String(value.to_owned())) + } + + fn serialize_bytes(self, value: &[u8]) -> Result { + Ok(Self::Ok::Bytes(value.to_vec())) + } + + #[inline] + fn serialize_unit(self) -> Result { + Ok(Self::Ok::List(vec![])) + } + + #[inline] + fn serialize_unit_struct( + self, + _name: &'static str, + ) -> Result { + Ok(Self::Ok::List(vec![])) + } + + #[inline] + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result { + let idx = self.serialize_u32(variant_index)?; + Ok(Self::Ok::List(vec![idx])) + } + + #[inline] + fn serialize_newtype_struct( + self, + name: &'static str, + value: &T, + ) -> Result + where + T: ser::Serialize, + { + let ipld = value.serialize(self); + if name == CID_SERDE_PRIVATE_IDENTIFIER { + if let Ok(Ipld::Bytes(bytes)) = ipld { + let cid = Cid::try_from(bytes) + .map_err(|err| ser::Error::custom(format!("Invalid CID: {}", err)))?; + return Ok(Self::Ok::Link(cid)); + } + } + ipld + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &T, + ) -> Result + where + T: ser::Serialize, + { + let values = + Vec::from([self.serialize_u32(variant_index)?, value.serialize(self)?]); + Ok(Self::Ok::List(values)) + } + + #[inline] + fn serialize_none(self) -> Result { + Ok(Self::Ok::Null) + } + + #[inline] + fn serialize_some( + self, + value: &T, + ) -> Result + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq( + self, + len: Option, + ) -> Result { + Ok(SerializeVec { vec: Vec::with_capacity(len.unwrap_or(0)) }) + } + + fn serialize_tuple( + self, + len: usize, + ) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_tuple(len) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result { + Ok(SerializeTupleVariant { + idx: variant_index, + vec: Vec::with_capacity(len), + }) + } + + fn serialize_map( + self, + _len: Option, + ) -> Result { + Ok(SerializeMap { vec: Vec::new(), next_key: None }) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Ok(StructSerializer { ser: &self, vec: Vec::new(), variant_index: 0 }) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Ok(StructSerializer { ser: &self, vec: Vec::new(), variant_index }) + } + + #[inline] + fn is_human_readable(&self) -> bool { false } } pub struct SerializeVec { - vec: Vec, + vec: Vec, } pub struct SerializeTupleVariant { - name: String, - vec: Vec, + idx: u32, + vec: Vec, } pub struct SerializeMap { - map: BTreeMap, - next_key: Option, -} - -pub struct SerializeStructVariant { - name: String, - map: BTreeMap, + vec: Vec, + next_key: Option, } impl ser::SerializeSeq for SerializeVec { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - self.vec.push(value.serialize(Serializer)?); - Ok(()) - } + type Error = SerdeError; + type Ok = Ipld; + + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + self.vec.push(value.serialize(&Serializer)?); + Ok(()) + } - fn end(self) -> Result { - Ok(Self::Ok::List(self.vec)) - } + fn end(self) -> Result { Ok(Self::Ok::List(self.vec)) } } impl ser::SerializeTuple for SerializeVec { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - ser::SerializeSeq::serialize_element(self, value) - } + type Error = SerdeError; + type Ok = Ipld; + + fn serialize_element( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } - fn end(self) -> Result { - ser::SerializeSeq::end(self) - } + fn end(self) -> Result { ser::SerializeSeq::end(self) } } impl ser::SerializeTupleStruct for SerializeVec { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - ser::SerializeSeq::serialize_element(self, value) - } + type Error = SerdeError; + type Ok = Ipld; + + fn serialize_field( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } - fn end(self) -> Result { - ser::SerializeSeq::end(self) - } + fn end(self) -> Result { ser::SerializeSeq::end(self) } } impl ser::SerializeTupleVariant for SerializeTupleVariant { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - self.vec.push(value.serialize(Serializer)?); - Ok(()) - } - - fn end(self) -> Result { - let map = BTreeMap::from([(self.name, Self::Ok::List(self.vec))]); - Ok(Self::Ok::Map(map)) - } + type Error = SerdeError; + type Ok = Ipld; + + fn serialize_field( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + self.vec.push(value.serialize(&Serializer)?); + Ok(()) + } + + fn end(self) -> Result { + let mut vec = Vec::new(); + let mut args = self.vec.clone(); + vec.push(Ipld::Integer(self.idx.clone() as i128)); + vec.append(&mut args); + Ok(Ipld::List(vec)) + } } impl ser::SerializeMap for SerializeMap { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - match key.serialize(Serializer)? { - Ipld::String(string_key) => { - self.next_key = Some(string_key); - Ok(()) - } - _ => Err(ser::Error::custom("Map keys must be strings".to_string())), - } - } - - fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - let key = self.next_key.take(); - // Panic because this indicates a bug in the program rather than an - // expected failure. - let key = key.expect("serialize_value called before serialize_key"); - self.map.insert(key, value.serialize(Serializer)?); + type Error = SerdeError; + type Ok = Ipld; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where T: ser::Serialize { + match key.serialize(&Serializer)? { + key => { + self.next_key = Some(key); Ok(()) + } } + } - fn end(self) -> Result { - Ok(Self::Ok::Map(self.map)) - } + fn serialize_value( + &mut self, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + let key = self.next_key.take(); + // Panic because this indicates a bug in the program rather than an + // expected failure. + let key = key.expect("serialize_value called before serialize_key"); + self.vec.push(Ipld::List(vec![key, value.serialize(&Serializer)?])); + Ok(()) + } + + fn end(self) -> Result { Ok(Self::Ok::List(self.vec)) } } -impl ser::SerializeStruct for SerializeMap { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - serde::ser::SerializeMap::serialize_key(self, key)?; - serde::ser::SerializeMap::serialize_value(self, value) - } - - fn end(self) -> Result { - serde::ser::SerializeMap::end(self) - } +impl<'a> StructSerializer<'a> { + #[inline] + fn serialize_field_inner( + &mut self, + _: &'static str, + value: &T, + ) -> Result<(), SerdeError> + where + T: ?Sized + ser::Serialize, + { + let val = value.serialize(self.ser)?; + self.vec.push(val); + Ok(()) + } + + #[inline] + fn skip_field_inner(&mut self, _: &'static str) -> Result<(), SerdeError> { + Ok(()) + } + + #[inline] + fn end_inner(self) -> Result, SerdeError> { Ok(self.vec) } } -impl ser::SerializeStructVariant for SerializeStructVariant { - type Ok = Ipld; - type Error = SerdeError; - - fn serialize_field( - &mut self, - key: &'static str, - value: &T, - ) -> Result<(), Self::Error> - where - T: ser::Serialize, - { - self.map - .insert(key.to_string(), value.serialize(Serializer)?); - Ok(()) - } - - fn end(self) -> Result { - let mut object = BTreeMap::new(); +impl<'a> ser::SerializeStruct for StructSerializer<'a> { + type Error = SerdeError; + type Ok = Ipld; + + #[inline] + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + self.serialize_field_inner(key, value)?; + Ok(()) + } + + #[inline] + fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { + self.skip_field_inner(key) + } + + #[inline] + fn end(self) -> Result { + let x = self.end_inner()?; + Ok(Ipld::List(x)) + } +} - object.insert(self.name, Self::Ok::Map(self.map)); +impl<'a> ser::SerializeStructVariant for StructSerializer<'a> { + type Error = SerdeError; + type Ok = Ipld; - Ok(Self::Ok::Map(object)) - } + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: ser::Serialize, + { + self.serialize_field_inner(key, value)?; + Ok(()) + } + + fn end(self) -> Result { + let mut vec = Vec::new(); + vec.push(Ipld::Integer(self.variant_index.clone() as i128)); + let mut args = self.end_inner()?; + vec.append(&mut args); + Ok(Ipld::List(vec)) + } } diff --git a/core/tests/serde_deserializer.rs b/core/tests/serde_deserializer.rs index c0f6a2f3..d9a92aad 100644 --- a/core/tests/serde_deserializer.rs +++ b/core/tests/serde_deserializer.rs @@ -9,700 +9,736 @@ use serde::Deserialize; use serde_bytes::ByteBuf; use serde_json::json; -use libipld_core::cid::Cid; -use libipld_core::ipld::Ipld; +use libipld_core::{ + cid::Cid, + ipld::Ipld, +}; -/// This function is to test that all IPLD kinds except the given one errors, when trying to -/// deserialize to the given Rust type. +/// This function is to test that all IPLD kinds except the given one errors, +/// when trying to deserialize to the given Rust type. fn error_except<'de, T>(_input: T, except: &Ipld) -where - T: Deserialize<'de> + core::fmt::Debug, -{ - if !matches!(except, Ipld::Null) { - assert!(T::deserialize(Ipld::Null).is_err()); - } - if !matches!(except, Ipld::Bool(_)) { - assert!(T::deserialize(Ipld::Bool(true)).is_err()); - } - if !matches!(except, Ipld::Integer(_)) { - assert!(T::deserialize(Ipld::Integer(22)).is_err()); - } - if !matches!(except, Ipld::Float(_)) { - assert!(T::deserialize(Ipld::Float(5.3)).is_err()); - } - if !matches!(except, Ipld::String(_)) { - assert!(T::deserialize(Ipld::String("hello".into())).is_err()); - } - if !matches!(except, Ipld::Bytes(_)) { - assert!(T::deserialize(Ipld::Bytes(vec![0x68, 0x65, 0x6c, 0x6c, 0x6f])).is_err()); - } - if !matches!(except, Ipld::List(_)) { - assert!(T::deserialize(Ipld::List(vec![Ipld::Integer(22), Ipld::Bool(false)])).is_err()); - } - if !matches!(except, Ipld::Map(_)) { - assert!(T::deserialize(Ipld::Map(BTreeMap::from([ - ("hello".into(), Ipld::Null), - ("world!".into(), Ipld::Float(7.4)) - ]))) - .is_err()); - } - if !matches!(except, Ipld::Link(_)) { - assert!(T::deserialize(Ipld::Link( - Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap() - )) - .is_err()); - } +where T: Deserialize<'de> + core::fmt::Debug { + if !matches!(except, Ipld::Null) { + assert!(T::deserialize(Ipld::Null).is_err()); + } + if !matches!(except, Ipld::Bool(_)) { + assert!(T::deserialize(Ipld::Bool(true)).is_err()); + } + if !matches!(except, Ipld::Integer(_)) { + assert!(T::deserialize(Ipld::Integer(22)).is_err()); + } + if !matches!(except, Ipld::Float(_)) { + assert!(T::deserialize(Ipld::Float(5.3)).is_err()); + } + if !matches!(except, Ipld::String(_)) { + assert!(T::deserialize(Ipld::String("hello".into())).is_err()); + } + if !matches!(except, Ipld::Bytes(_)) { + assert!( + T::deserialize(Ipld::Bytes(vec![0x68, 0x65, 0x6c, 0x6c, 0x6f])).is_err() + ); + } + if !matches!(except, Ipld::List(_)) { + assert!( + T::deserialize(Ipld::List(vec![Ipld::Integer(22), Ipld::Bool(false)])) + .is_err() + ); + } + if !matches!(except, Ipld::Map(_)) { + assert!( + T::deserialize(Ipld::Map(BTreeMap::from([ + ("hello".into(), Ipld::Null), + ("world!".into(), Ipld::Float(7.4)) + ]))) + .is_err() + ); + } + if !matches!(except, Ipld::Link(_)) { + assert!( + T::deserialize(Ipld::Link( + Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m" + ) + .unwrap() + )) + .is_err() + ); + } } #[test] #[allow(clippy::unit_cmp)] fn ipld_deserializer_unit() { - let unit = (); - let ipld = Ipld::Null; - error_except(unit, &ipld); + let unit = (); + let ipld = Ipld::List(vec![]); + error_except(unit, &ipld); - let deserialized = <()>::deserialize(ipld).unwrap(); - assert_eq!(deserialized, ()); + let deserialized = <()>::deserialize(ipld).unwrap(); + assert_eq!(deserialized, ()); } #[test] fn ipld_deserializer_unit_struct() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct UnitStruct; + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct UnitStruct; - let ipld = Ipld::Null; - let deserialized = UnitStruct::deserialize(ipld); - assert!(deserialized.is_err()); + let ipld = Ipld::Null; + let deserialized = UnitStruct::deserialize(ipld); + assert!(deserialized.is_err()); } #[test] fn ipld_deserializer_bool() { - let bool = false; - let ipld = Ipld::Bool(bool); - error_except(bool, &ipld); + let bool = false; + let ipld = Ipld::Bool(bool); + error_except(bool, &ipld); - let deserialized = bool::deserialize(ipld).unwrap(); - assert_eq!(deserialized, bool); + let deserialized = bool::deserialize(ipld).unwrap(); + assert_eq!(deserialized, bool); } #[test] fn ipld_deserializer_u8() { - let integer = 34u8; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = u8::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to u8." - ); + let integer = 34u8; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); + + let deserialized = u8::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to u8." + ); - let too_large = u8::deserialize(Ipld::Integer((u8::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = u8::deserialize(Ipld::Integer((u8::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let too_large = u8::deserialize(Ipld::Integer((u8::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = u8::deserialize(Ipld::Integer((u8::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_u16() { - let integer = 345u16; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = u16::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to u16." - ); + let integer = 345u16; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); - let too_large = u16::deserialize(Ipld::Integer((u16::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = u16::deserialize(Ipld::Integer((u16::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let deserialized = u16::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to u16." + ); + + let too_large = u16::deserialize(Ipld::Integer((u16::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = u16::deserialize(Ipld::Integer((u16::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_u32() { - let integer = 345678u32; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = u32::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to u32." - ); + let integer = 345678u32; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); - let too_large = u32::deserialize(Ipld::Integer((u32::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = u32::deserialize(Ipld::Integer((u32::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let deserialized = u32::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to u32." + ); + + let too_large = u32::deserialize(Ipld::Integer((u32::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = u32::deserialize(Ipld::Integer((u32::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_u64() { - let integer = 34567890123u64; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = u64::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to u64." - ); + let integer = 34567890123u64; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); + + let deserialized = u64::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to u64." + ); - let too_large = u64::deserialize(Ipld::Integer((u64::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = u64::deserialize(Ipld::Integer((u64::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let too_large = u64::deserialize(Ipld::Integer((u64::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = u64::deserialize(Ipld::Integer((u64::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_i8() { - let integer = -23i8; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = i8::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to i8." - ); + let integer = -23i8; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); + + let deserialized = i8::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to i8." + ); - let too_large = i8::deserialize(Ipld::Integer((i8::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = i8::deserialize(Ipld::Integer((i8::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let too_large = i8::deserialize(Ipld::Integer((i8::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = i8::deserialize(Ipld::Integer((i8::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_i16() { - let integer = 2345i16; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = i16::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to i16." - ); + let integer = 2345i16; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); + + let deserialized = i16::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to i16." + ); - let too_large = i16::deserialize(Ipld::Integer((i16::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = i16::deserialize(Ipld::Integer((i16::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let too_large = i16::deserialize(Ipld::Integer((i16::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = i16::deserialize(Ipld::Integer((i16::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_i32() { - let integer = 234567i32; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = i32::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to i32." - ); + let integer = 234567i32; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); - let too_large = i32::deserialize(Ipld::Integer((i32::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = i32::deserialize(Ipld::Integer((i32::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let deserialized = i32::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to i32." + ); + + let too_large = i32::deserialize(Ipld::Integer((i32::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = i32::deserialize(Ipld::Integer((i32::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_i64() { - let integer = 2345678901i64; - let ipld = Ipld::Integer(integer.into()); - error_except(integer, &ipld); - - let deserialized = i64::deserialize(ipld).unwrap(); - assert_eq!( - deserialized, integer, - "Correctly deserialize Ipld::Integer to i64." - ); + let integer = 2345678901i64; + let ipld = Ipld::Integer(integer.into()); + error_except(integer, &ipld); - let too_large = i64::deserialize(Ipld::Integer((i64::MAX as i128) + 10)); - assert!(too_large.is_err(), "Number must be within range."); - let too_small = i64::deserialize(Ipld::Integer((i64::MIN as i128) - 10)); - assert!(too_small.is_err(), "Number must be within range."); + let deserialized = i64::deserialize(ipld).unwrap(); + assert_eq!( + deserialized, integer, + "Correctly deserialize Ipld::Integer to i64." + ); + + let too_large = i64::deserialize(Ipld::Integer((i64::MAX as i128) + 10)); + assert!(too_large.is_err(), "Number must be within range."); + let too_small = i64::deserialize(Ipld::Integer((i64::MIN as i128) - 10)); + assert!(too_small.is_err(), "Number must be within range."); } #[test] fn ipld_deserializer_f32() { - let float = 7.3f32; - let ipld = Ipld::Float(float.into()); - error_except(float, &ipld); + let float = 7.3f32; + let ipld = Ipld::Float(float.into()); + error_except(float, &ipld); - let deserialized = f32::deserialize(ipld).unwrap(); - assert_eq!(deserialized, float); + let deserialized = f32::deserialize(ipld).unwrap(); + assert_eq!(deserialized, float); } #[test] fn ipld_deserializer_f32_with_loss() { - // Make sure that there is an error if the value can only be converted with loss. 7.3f32 is - // different from 7.3f64. - let ipld = Ipld::Float(7.3f64); - let error = f32::deserialize(ipld); - assert!(error.is_err()); + // Make sure that there is an error if the value can only be converted with + // loss. 7.3f32 is different from 7.3f64. + let ipld = Ipld::Float(7.3f64); + let error = f32::deserialize(ipld); + assert!(error.is_err()); } #[test] fn ipld_deserializer_f32_nan() { - let ipld = Ipld::Float(f32::NAN.into()); - let error = f32::deserialize(ipld); - assert!(error.is_err()); + let ipld = Ipld::Float(f32::NAN.into()); + let error = f32::deserialize(ipld); + assert!(error.is_err()); } #[test] fn ipld_deserializer_f32_infinity() { - let ipld = Ipld::Float(f32::INFINITY.into()); - let error = f32::deserialize(ipld); - assert!(error.is_err()); + let ipld = Ipld::Float(f32::INFINITY.into()); + let error = f32::deserialize(ipld); + assert!(error.is_err()); } #[test] fn ipld_deserializer_f64() { - let float = 427.8f64; - let ipld = Ipld::Float(float); - error_except(float, &ipld); + let float = 427.8f64; + let ipld = Ipld::Float(float); + error_except(float, &ipld); - let deserialized = f64::deserialize(ipld).unwrap(); - assert_eq!(deserialized, float); + let deserialized = f64::deserialize(ipld).unwrap(); + assert_eq!(deserialized, float); } #[test] fn ipld_deserializer_f64_nan() { - let ipld = Ipld::Float(f64::NAN); - let error = f64::deserialize(ipld); - assert!(error.is_err()); + let ipld = Ipld::Float(f64::NAN); + let error = f64::deserialize(ipld); + assert!(error.is_err()); } #[test] fn ipld_deserializer_f64_infinity() { - let ipld = Ipld::Float(f64::INFINITY); - let error = f64::deserialize(ipld); - assert!(error.is_err()); + let ipld = Ipld::Float(f64::INFINITY); + let error = f64::deserialize(ipld); + assert!(error.is_err()); } #[test] fn ipld_deserializer_char() { - let char = 'x'; - let ipld = Ipld::String(char.to_string()); - error_except(char, &ipld); + let char = 'x'; + let ipld = Ipld::String(char.to_string()); + error_except(char, &ipld); - let deserialized = char::deserialize(ipld).unwrap(); - assert_eq!(deserialized, char); + let deserialized = char::deserialize(ipld).unwrap(); + assert_eq!(deserialized, char); } #[test] fn ipld_deserializer_str() { - let str: &str = "hello"; - let ipld = Ipld::String(str.to_string()); - error_except(str, &ipld); + let str: &str = "hello"; + let ipld = Ipld::String(str.to_string()); + error_except(str, &ipld); - // TODO vmx 2022-02-09: Doesn't work yet. If we would have a zero-copy version, it should - //let deserialized = <&str>::deserialize(ipld).unwrap(); - //assert_eq!(deserialized, string); + // TODO vmx 2022-02-09: Doesn't work yet. If we would have a zero-copy + // version, it should let deserialized = <&str>::deserialize(ipld).unwrap(); + // assert_eq!(deserialized, string); } #[test] fn ipld_deserializer_string() { - let string = "hello".to_string(); - let ipld = Ipld::String(string.clone()); - error_except(string.clone(), &ipld); + let string = "hello".to_string(); + let ipld = Ipld::String(string.clone()); + error_except(string.clone(), &ipld); - let deserialized = String::deserialize(ipld).unwrap(); - assert_eq!(deserialized, string); + let deserialized = String::deserialize(ipld).unwrap(); + assert_eq!(deserialized, string); } #[test] fn ipld_deserializer_bytes() { - let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::Bytes(bytes.clone()); - error_except(&bytes[..], &ipld); + let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::Bytes(bytes.clone()); + error_except(&bytes[..], &ipld); - // TODO vmx 2022-02-09: Doesn't work yet. If we would have a zero-copy version, it should - //let deserialized = <&[u8]>::deserialize(ipld).unwrap(); - //assert_eq!(deserialized, bytes); + // TODO vmx 2022-02-09: Doesn't work yet. If we would have a zero-copy + // version, it should let deserialized = + // <&[u8]>::deserialize(ipld).unwrap(); assert_eq!(deserialized, bytes); } #[test] fn ipld_deserializer_byte_buf() { - let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::Bytes(bytes.clone()); - error_except(ByteBuf::from(bytes.clone()), &ipld); + let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::Bytes(bytes.clone()); + error_except(ByteBuf::from(bytes.clone()), &ipld); - let deserialized = ByteBuf::deserialize(ipld).unwrap(); - assert_eq!(deserialized, bytes); + let deserialized = ByteBuf::deserialize(ipld).unwrap(); + assert_eq!(deserialized, bytes); } #[test] fn ipld_deserializer_list() { - let list = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::List(vec![ - Ipld::Integer(0x68), - Ipld::Integer(0x65), - Ipld::Integer(0x6c), - Ipld::Integer(0x6c), - Ipld::Integer(0x6f), - ]); - error_except(list.clone(), &ipld); + let list = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::List(vec![ + Ipld::Integer(0x68), + Ipld::Integer(0x65), + Ipld::Integer(0x6c), + Ipld::Integer(0x6c), + Ipld::Integer(0x6f), + ]); + error_except(list.clone(), &ipld); - let deserialized = Vec::::deserialize(ipld).unwrap(); - assert_eq!(deserialized, list); + let deserialized = Vec::::deserialize(ipld).unwrap(); + assert_eq!(deserialized, list); } #[test] fn ipld_deserializer_tuple() { - let tuple = (true, "hello".to_string()); - let ipld = Ipld::List(vec![Ipld::Bool(tuple.0), Ipld::String(tuple.1.clone())]); - error_except(tuple.clone(), &ipld); + let tuple = (true, "hello".to_string()); + let ipld = + Ipld::List(vec![Ipld::Bool(tuple.0), Ipld::String(tuple.1.clone())]); + error_except(tuple.clone(), &ipld); - let deserialized = <(bool, String)>::deserialize(ipld).unwrap(); - assert_eq!(deserialized, tuple); + let deserialized = <(bool, String)>::deserialize(ipld).unwrap(); + assert_eq!(deserialized, tuple); } #[test] fn ipld_deserializer_tuple_errors() { - let tuple = (true, "hello".to_string()); + let tuple = (true, "hello".to_string()); - let ipld_not_enough = Ipld::List(vec![Ipld::Bool(tuple.0)]); - error_except(tuple.clone(), &ipld_not_enough); - let error_not_enough = <(bool, String)>::deserialize(ipld_not_enough); - assert!(error_not_enough.is_err()); + let ipld_not_enough = Ipld::List(vec![Ipld::Bool(tuple.0)]); + error_except(tuple.clone(), &ipld_not_enough); + let error_not_enough = <(bool, String)>::deserialize(ipld_not_enough); + assert!(error_not_enough.is_err()); - let ipld_too_many = Ipld::List(vec![ - Ipld::Bool(tuple.0), - Ipld::String(tuple.1.clone()), - Ipld::Null, - ]); - error_except(tuple.clone(), &ipld_too_many); - let error_too_many = <(bool, String)>::deserialize(ipld_too_many); - assert!(error_too_many.is_err()); + let ipld_too_many = Ipld::List(vec![ + Ipld::Bool(tuple.0), + Ipld::String(tuple.1.clone()), + Ipld::Null, + ]); + error_except(tuple.clone(), &ipld_too_many); + let error_too_many = <(bool, String)>::deserialize(ipld_too_many); + assert!(error_too_many.is_err()); - let ipld_not_matching = Ipld::List(vec![Ipld::String(tuple.1.clone()), Ipld::Bool(tuple.0)]); - error_except(tuple, &ipld_not_matching); - let error_not_matching = <(bool, String)>::deserialize(ipld_not_matching); - assert!(error_not_matching.is_err()); + let ipld_not_matching = + Ipld::List(vec![Ipld::String(tuple.1.clone()), Ipld::Bool(tuple.0)]); + error_except(tuple, &ipld_not_matching); + let error_not_matching = <(bool, String)>::deserialize(ipld_not_matching); + assert!(error_not_matching.is_err()); } #[test] fn ipld_deserializer_tuple_struct() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct TupleStruct(u8, bool); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct TupleStruct(u8, bool); - let tuple_struct = TupleStruct(82, true); - let ipld = Ipld::List(vec![Ipld::Integer(82), Ipld::Bool(true)]); - error_except(tuple_struct.clone(), &ipld); + let tuple_struct = TupleStruct(82, true); + let ipld = Ipld::List(vec![Ipld::Integer(82), Ipld::Bool(true)]); + error_except(tuple_struct.clone(), &ipld); - let deserialized = TupleStruct::deserialize(ipld).unwrap(); - assert_eq!(deserialized, tuple_struct); + let deserialized = TupleStruct::deserialize(ipld).unwrap(); + assert_eq!(deserialized, tuple_struct); } #[test] fn ipld_deserializer_tuple_struct_errors() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct TupleStruct(u8, bool); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct TupleStruct(u8, bool); - let tuple_struct = TupleStruct(82, true); + let tuple_struct = TupleStruct(82, true); - let ipld_not_enough = Ipld::List(vec![Ipld::Integer(tuple_struct.0.into())]); - error_except(tuple_struct.clone(), &ipld_not_enough); - let error_not_enough = TupleStruct::deserialize(ipld_not_enough); - assert!(error_not_enough.is_err()); + let ipld_not_enough = Ipld::List(vec![Ipld::Integer(tuple_struct.0.into())]); + error_except(tuple_struct.clone(), &ipld_not_enough); + let error_not_enough = TupleStruct::deserialize(ipld_not_enough); + assert!(error_not_enough.is_err()); - let ipld_too_many = Ipld::List(vec![ - Ipld::Integer(tuple_struct.0.into()), - Ipld::Bool(tuple_struct.1), - Ipld::Null, - ]); - error_except(tuple_struct.clone(), &ipld_too_many); - let error_too_many = TupleStruct::deserialize(ipld_too_many); - assert!(error_too_many.is_err()); + let ipld_too_many = Ipld::List(vec![ + Ipld::Integer(tuple_struct.0.into()), + Ipld::Bool(tuple_struct.1), + Ipld::Null, + ]); + error_except(tuple_struct.clone(), &ipld_too_many); + let error_too_many = TupleStruct::deserialize(ipld_too_many); + assert!(error_too_many.is_err()); - let ipld_not_matching = Ipld::List(vec![ - Ipld::Bool(tuple_struct.1), - Ipld::Integer(tuple_struct.0.into()), - ]); - error_except(tuple_struct, &ipld_not_matching); - let error_not_matching = TupleStruct::deserialize(ipld_not_matching); - assert!(error_not_matching.is_err()); + let ipld_not_matching = Ipld::List(vec![ + Ipld::Bool(tuple_struct.1), + Ipld::Integer(tuple_struct.0.into()), + ]); + error_except(tuple_struct, &ipld_not_matching); + let error_not_matching = TupleStruct::deserialize(ipld_not_matching); + assert!(error_not_matching.is_err()); } #[test] fn ipld_deserializer_map() { - let map = BTreeMap::from([("hello".to_string(), true), ("world!".to_string(), false)]); - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".to_string(), Ipld::Bool(true)), - ("world!".to_string(), Ipld::Bool(false)), - ])); - error_except(map.clone(), &ipld); + let map = BTreeMap::from([ + ("hello".to_string(), true), + ("world!".to_string(), false), + ]); + let ipld = Ipld::List(vec![ + Ipld::List(vec![Ipld::String("hello".into()), Ipld::Bool(true)]), + Ipld::List(vec![Ipld::String("world!".into()), Ipld::Bool(false)]), + ]); + error_except(map.clone(), &ipld); - let deserialized = BTreeMap::deserialize(ipld).unwrap(); - assert_eq!(deserialized, map); + let deserialized = BTreeMap::deserialize(ipld).unwrap(); + assert_eq!(deserialized, map); } /// A CID is deserialized through a newtype struct. #[test] fn ipld_deserializer_cid() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - error_except(cid, &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + error_except(cid, &ipld); - let deserialized = Cid::deserialize(ipld).unwrap(); - assert_eq!(deserialized, cid); + let deserialized = Cid::deserialize(ipld).unwrap(); + assert_eq!(deserialized, cid); } /// Make sure that a CID cannot be deserialized into bytes. #[test] fn ipld_deserializer_cid_not_bytes() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - error_except(cid, &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + error_except(cid, &ipld); - let deserialized = ByteBuf::deserialize(ipld); - assert!(deserialized.is_err()); + let deserialized = ByteBuf::deserialize(ipld); + assert!(deserialized.is_err()); } /// Make sure that a CID cannot be deserialized into bytes. #[test] fn ipld_deserializer_cid_not_bytes_newtype_struct() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct Wrapped(ByteBuf); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct Wrapped(ByteBuf); - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - error_except(cid, &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + error_except(cid, &ipld); - let deserialized = Wrapped::deserialize(ipld); - assert!(deserialized.is_err()); + let deserialized = Wrapped::deserialize(ipld); + assert!(deserialized.is_err()); } /// Make sure that a CID cannot be deserialized into bytes. #[test] fn ipld_deserializer_cid_untagged() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - #[serde(untagged)] - enum MyOption { - Some(ByteBuf), - None, - } + #[derive(Clone, Debug, Deserialize, PartialEq)] + #[serde(untagged)] + enum MyOption { + Some(ByteBuf), + None, + } - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - error_except(cid, &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + error_except(cid, &ipld); - let deserialized = MyOption::deserialize(ipld); - assert!(deserialized.is_err()); + let deserialized = MyOption::deserialize(ipld); + assert!(deserialized.is_err()); } #[test] fn ipld_deserializer_newtype_struct() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct Wrapped(u8); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct Wrapped(u8); - let newtype_struct = Wrapped(5); - let ipld = Ipld::Integer(5); - error_except(newtype_struct.clone(), &ipld); + let newtype_struct = Wrapped(5); + let ipld = Ipld::Integer(5); + error_except(newtype_struct.clone(), &ipld); - let deserialized = Wrapped::deserialize(ipld).unwrap(); - assert_eq!(deserialized, newtype_struct); + let deserialized = Wrapped::deserialize(ipld).unwrap(); + assert_eq!(deserialized, newtype_struct); } /// An additional test, just to make sure that wrapped CIDs also work. #[test] fn ipld_deserializer_newtype_struct_cid() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct Wrapped(Cid); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct Wrapped(Cid); - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let newtype_struct = Wrapped(cid); - let ipld = Ipld::Link(cid); - error_except(newtype_struct.clone(), &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let newtype_struct = Wrapped(cid); + let ipld = Ipld::Link(cid); + error_except(newtype_struct.clone(), &ipld); - let deserialized = Wrapped::deserialize(ipld).unwrap(); - assert_eq!(deserialized, newtype_struct); + let deserialized = Wrapped::deserialize(ipld).unwrap(); + assert_eq!(deserialized, newtype_struct); } #[test] fn ipld_deserializer_option() { - let option_some: Option = Some(58u8); - let option_none: Option = None; - let ipld_some = Ipld::Integer(option_some.unwrap().into()); - let ipld_none = Ipld::Null; - - // This is similar to `error_except`, which cannot be used here, as we need to excluse - // `Ipld::Integer` *and* `Ipld::Null`. - assert!(>::deserialize(Ipld::Bool(true)).is_err()); - assert!(>::deserialize(Ipld::Float(5.3)).is_err()); - assert!(>::deserialize(Ipld::String("hello".into())).is_err()); - assert!(>::deserialize(Ipld::Bytes(vec![0x01, 0x97])).is_err()); - assert!( - >::deserialize(Ipld::List(vec![Ipld::Integer(22), Ipld::Bool(false)])).is_err() - ); - assert!(>::deserialize(Ipld::Map(BTreeMap::from([ - ("hello".into(), Ipld::Null), - ("world!".into(), Ipld::Float(7.4)) + let option_some: Option = Some(58u8); + let option_none: Option = None; + let ipld_some = Ipld::Integer(option_some.unwrap().into()); + let ipld_none = Ipld::Null; + + // This is similar to `error_except`, which cannot be used here, as we need to + // excluse `Ipld::Integer` *and* `Ipld::Null`. + assert!(>::deserialize(Ipld::Bool(true)).is_err()); + assert!(>::deserialize(Ipld::Float(5.3)).is_err()); + assert!(>::deserialize(Ipld::String("hello".into())).is_err()); + assert!(>::deserialize(Ipld::Bytes(vec![0x01, 0x97])).is_err()); + assert!( + >::deserialize(Ipld::List(vec![ + Ipld::Integer(22), + Ipld::Bool(false) + ])) + .is_err() + ); + assert!( + >::deserialize(Ipld::Map(BTreeMap::from([ + ("hello".into(), Ipld::Null), + ("world!".into(), Ipld::Float(7.4)) ]))) - .is_err()); - assert!(>::deserialize(Ipld::Link( - Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap() + .is_err() + ); + assert!( + >::deserialize(Ipld::Link( + Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m" + ) + .unwrap() )) - .is_err()); + .is_err() + ); - let deserialized_some = >::deserialize(ipld_some).unwrap(); - assert_eq!(deserialized_some, option_some); - let deserialized_none = >::deserialize(ipld_none).unwrap(); - assert_eq!(deserialized_none, option_none); + let deserialized_some = >::deserialize(ipld_some).unwrap(); + assert_eq!(deserialized_some, option_some); + let deserialized_none = >::deserialize(ipld_none).unwrap(); + assert_eq!(deserialized_none, option_none); } #[test] fn ipld_deserializer_enum() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - enum MyEnum { - One, - Two(u8), - Three { value: bool }, - } - - let enum_one = MyEnum::One; - let ipld_one = Ipld::String("One".into()); - error_except(enum_one.clone(), &ipld_one); - let deserialized_one = MyEnum::deserialize(ipld_one).unwrap(); - assert_eq!(deserialized_one, enum_one); - - let enum_two = MyEnum::Two(4); - let ipld_two = Ipld::Map(BTreeMap::from([("Two".into(), Ipld::Integer(4))])); - error_except(enum_two.clone(), &ipld_two); - let deserialized_two = MyEnum::deserialize(ipld_two).unwrap(); - assert_eq!(deserialized_two, enum_two); - - let enum_three = MyEnum::Three { value: true }; - let ipld_three = Ipld::Map(BTreeMap::from([( - "Three".into(), - Ipld::Map(BTreeMap::from([("value".into(), Ipld::Bool(true))])), - )])); - error_except(enum_three.clone(), &ipld_three); - let deserialized_three = MyEnum::deserialize(ipld_three).unwrap(); - assert_eq!(deserialized_three, enum_three); + #[derive(Clone, Debug, Deserialize, PartialEq)] + enum MyEnum { + One, + Two(u8), + Three { value: bool }, + } + + let enum_one = MyEnum::One; + let ipld_one = Ipld::List(vec![Ipld::Integer(0)]); + error_except(enum_one.clone(), &ipld_one); + let deserialized_one = MyEnum::deserialize(ipld_one).unwrap(); + assert_eq!(deserialized_one, enum_one); + + let enum_two = MyEnum::Two(4); + let ipld_two = Ipld::List(vec![Ipld::Integer(1), Ipld::Integer(4)]); + error_except(enum_two.clone(), &ipld_two); + let deserialized_two = MyEnum::deserialize(ipld_two).unwrap(); + assert_eq!(deserialized_two, enum_two); + + let enum_three = MyEnum::Three { value: true }; + let ipld_three = Ipld::List(vec![Ipld::Integer(2), Ipld::Bool(true)]); + error_except(enum_three.clone(), &ipld_three); + let deserialized_three = MyEnum::deserialize(ipld_three).unwrap(); + assert_eq!(deserialized_three, enum_three); } #[test] fn ipld_deserializer_enum_tuple_variant_errors() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - enum MyEnum { - Two(u8, bool), - } - - let tuple_variant = MyEnum::Two(17, false); - - let ipld_not_enough = Ipld::Map(BTreeMap::from([( - "Two".into(), - Ipld::List(vec![Ipld::Integer(17)]), - )])); - error_except(tuple_variant.clone(), &ipld_not_enough); - let error_not_enough = MyEnum::deserialize(ipld_not_enough); - assert!(error_not_enough.is_err()); - - let ipld_too_many = Ipld::Map(BTreeMap::from([( - "Two".into(), - Ipld::List(vec![Ipld::Integer(17), Ipld::Bool(false), Ipld::Null]), - )])); - error_except(tuple_variant.clone(), &ipld_too_many); - let error_too_many = MyEnum::deserialize(ipld_too_many); - assert!(error_too_many.is_err()); - - let ipld_not_matching = Ipld::Map(BTreeMap::from([( - "Two".into(), - Ipld::List(vec![Ipld::Bool(false), Ipld::Integer(17)]), - )])); - error_except(tuple_variant, &ipld_not_matching); - let error_not_matching = MyEnum::deserialize(ipld_not_matching); - assert!(error_not_matching.is_err()); + #[derive(Clone, Debug, Deserialize, PartialEq)] + enum MyEnum { + Two(u8, bool), + } + + let tuple_variant = MyEnum::Two(17, false); + + let ipld_not_enough = Ipld::List(vec![Ipld::Integer(0), Ipld::Integer(17)]); + error_except(tuple_variant.clone(), &ipld_not_enough); + let error_not_enough = MyEnum::deserialize(ipld_not_enough); + assert!(error_not_enough.is_err()); + + let ipld_too_many = Ipld::List(vec![ + Ipld::Integer(0), + Ipld::Integer(17), + Ipld::Bool(false), + Ipld::Null, + ]); + error_except(tuple_variant.clone(), &ipld_too_many); + let error_too_many = MyEnum::deserialize(ipld_too_many); + assert!(error_too_many.is_err()); + + let ipld_not_matching = + Ipld::List(vec![Ipld::Integer(0), Ipld::Bool(false), Ipld::Integer(17)]); + error_except(tuple_variant, &ipld_not_matching); + let error_not_matching = MyEnum::deserialize(ipld_not_matching); + assert!(error_not_matching.is_err()); } #[test] fn ipld_deserializer_struct() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct MyStruct { - hello: u8, - world: bool, - } + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct MyStruct { + hello: u8, + world: bool, + } - let my_struct = MyStruct { - hello: 91, - world: false, - }; - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".into(), Ipld::Integer(my_struct.hello.into())), - ("world".into(), Ipld::Bool(my_struct.world)), - ])); - error_except(my_struct.clone(), &ipld); + let my_struct = MyStruct { hello: 91, world: false }; + let ipld = Ipld::List(vec![ + Ipld::Integer(my_struct.hello.into()), + Ipld::Bool(my_struct.world), + ]); + error_except(my_struct.clone(), &ipld); - let deserialized = MyStruct::deserialize(ipld).unwrap(); - assert_eq!(deserialized, my_struct); + let deserialized = MyStruct::deserialize(ipld).unwrap(); + assert_eq!(deserialized, my_struct); } #[test] fn ipld_deserializer_struct_errors() { - #[derive(Clone, Debug, Deserialize, PartialEq)] - struct MyStruct { - hello: u8, - world: bool, - } - - let my_struct = MyStruct { - hello: 91, - world: false, - }; - - let ipld_missing = Ipld::Map(BTreeMap::from([( - "hello".into(), - Ipld::Integer(my_struct.hello.into()), - )])); - error_except(my_struct.clone(), &ipld_missing); - let error_missing = MyStruct::deserialize(ipld_missing); - assert!(error_missing.is_err()); - - let ipld_wrong = Ipld::Map(BTreeMap::from([( - "wrong".into(), - Ipld::Integer(my_struct.hello.into()), - )])); - error_except(my_struct, &ipld_wrong); - let error_wrong = MyStruct::deserialize(ipld_wrong); - assert!(error_wrong.is_err()); + #[derive(Clone, Debug, Deserialize, PartialEq)] + struct MyStruct { + hello: u8, + world: bool, + } + + let my_struct = MyStruct { hello: 91, world: false }; + + let ipld_missing = Ipld::List(vec![(Ipld::Integer(my_struct.hello.into()))]); + error_except(my_struct.clone(), &ipld_missing); + let error_missing = MyStruct::deserialize(ipld_missing); + assert!(error_missing.is_err()); + + // let ipld_wrong = Ipld::List(vec![Ipld::Integer(my_struct.hello.into())]); + // error_except(my_struct, &ipld_wrong); + // let error_wrong = MyStruct::deserialize(ipld_wrong); + // assert!(error_wrong.is_err()); } /// This tests excercises the `deserialize_any` code path. #[test] fn ipld_deserializer_ipld() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - error_except(cid, &ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + error_except(cid, &ipld); - let deserialized = Ipld::deserialize(ipld.clone()).unwrap(); - assert_eq!(deserialized, ipld); + let deserialized = Ipld::deserialize(ipld.clone()).unwrap(); + assert_eq!(deserialized, ipld); } -/// This test shows that the values [`serde_json::Value`] supports, can be deserialized into Ipld +/// This test shows that the values [`serde_json::Value`] supports, can be +/// deserialized into Ipld #[test] fn ipld_deserializer_serde_json_value() { - let json_value = json!({ "hello": true, "world": "it is" }); - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".into(), Ipld::Bool(true)), - ("world".into(), Ipld::String("it is".into())), - ])); - let deserialized = serde_json::Value::deserialize(ipld).unwrap(); - assert_eq!(deserialized, json_value); + let json_value = json!([["hello", true], ["world!", "it is"]]); + let ipld = Ipld::List(vec![ + Ipld::List(vec![Ipld::String("hello".into()), Ipld::Bool(true)]), + Ipld::List(vec![ + Ipld::String("world!".into()), + Ipld::String("it is".into()), + ]), + ]); + let deserialized = serde_json::Value::deserialize(ipld).unwrap(); + assert_eq!(deserialized, json_value); } -/// This test shows that CIDs cannot be deserialized into a [`serde_json::Value`]. +/// This test shows that CIDs cannot be deserialized into a +/// [`serde_json::Value`]. #[test] fn ipld_deserializer_serde_json_value_cid_fails() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - let error = serde_json::Value::deserialize(ipld); - assert!(error.is_err()); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + let error = serde_json::Value::deserialize(ipld); + assert!(error.is_err()); } diff --git a/core/tests/serde_serialize.rs b/core/tests/serde_serialize.rs index 1e9c17b9..eec26404 100644 --- a/core/tests/serde_serialize.rs +++ b/core/tests/serde_serialize.rs @@ -5,118 +5,123 @@ extern crate alloc; use alloc::collections::BTreeMap; use core::convert::TryFrom; -use serde_test::{assert_ser_tokens, Token}; +use serde_test::{ + assert_ser_tokens, + Token, +}; -use libipld_core::cid::{serde::CID_SERDE_PRIVATE_IDENTIFIER, Cid}; -use libipld_core::ipld::Ipld; +use libipld_core::{ + cid::{ + serde::CID_SERDE_PRIVATE_IDENTIFIER, + Cid, + }, + ipld::Ipld, +}; #[test] fn ipld_serialize_null() { - let ipld = Ipld::Null; - assert_ser_tokens(&ipld, &[Token::None]); + let ipld = Ipld::Null; + assert_ser_tokens(&ipld, &[Token::None]); } #[test] fn ipld_serialize_bool() { - let bool = true; - let ipld = Ipld::Bool(bool); - assert_ser_tokens(&ipld, &[Token::Bool(bool)]); + let bool = true; + let ipld = Ipld::Bool(bool); + assert_ser_tokens(&ipld, &[Token::Bool(bool)]); } // NOTE vmx 2022-02-15: assert_ser_tokens doesn't support i128 //#[test] -//fn ipld_serialize_integer() { +// fn ipld_serialize_integer() { // let integer = 32u8; // let ipld = Ipld::Integer(integer.into()); //} #[test] fn ipld_serialize_float() { - let float = 32.41f32; - let ipld = Ipld::Float(float.into()); - assert_ser_tokens(&ipld, &[Token::F64(float.into())]); + let float = 32.41f32; + let ipld = Ipld::Float(float.into()); + assert_ser_tokens(&ipld, &[Token::F64(float.into())]); } #[test] fn ipld_serialize_string() { - let string = "hello"; - let ipld = Ipld::String(string.into()); - assert_ser_tokens(&ipld, &[Token::Str(string)]); - assert_ser_tokens(&ipld, &[Token::BorrowedStr(string)]); - assert_ser_tokens(&ipld, &[Token::String(string)]); + let string = "hello"; + let ipld = Ipld::String(string.into()); + assert_ser_tokens(&ipld, &[Token::Str(string)]); + assert_ser_tokens(&ipld, &[Token::BorrowedStr(string)]); + assert_ser_tokens(&ipld, &[Token::String(string)]); } #[test] fn ipld_serialize_bytes() { - let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::Bytes(bytes); - assert_ser_tokens(&ipld, &[Token::Bytes(b"hello")]); - assert_ser_tokens(&ipld, &[Token::BorrowedBytes(b"hello")]); - assert_ser_tokens(&ipld, &[Token::ByteBuf(b"hello")]); + let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::Bytes(bytes); + assert_ser_tokens(&ipld, &[Token::Bytes(b"hello")]); + assert_ser_tokens(&ipld, &[Token::BorrowedBytes(b"hello")]); + assert_ser_tokens(&ipld, &[Token::ByteBuf(b"hello")]); } #[test] fn ipld_serialize_list() { - let ipld = Ipld::List(vec![Ipld::Bool(false), Ipld::Float(22.7)]); - assert_ser_tokens( - &ipld, - &[ - Token::Seq { len: Some(2) }, - Token::Bool(false), - Token::F64(22.7), - Token::SeqEnd, - ], - ); + let ipld = Ipld::List(vec![Ipld::Bool(false), Ipld::Float(22.7)]); + assert_ser_tokens(&ipld, &[ + Token::Seq { len: Some(2) }, + Token::Bool(false), + Token::F64(22.7), + Token::SeqEnd, + ]); } #[test] fn ipld_serialize_map() { - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".to_string(), Ipld::Bool(true)), - ("world!".to_string(), Ipld::Bool(false)), - ])); - assert_ser_tokens( - &ipld, - &[ - Token::Map { len: Some(2) }, - Token::Str("hello"), - Token::Bool(true), - Token::Str("world!"), - Token::Bool(false), - Token::MapEnd, - ], - ); + let ipld = Ipld::Map(BTreeMap::from([ + ("hello".to_string(), Ipld::Bool(true)), + ("world!".to_string(), Ipld::Bool(false)), + ])); + assert_ser_tokens(&ipld, &[ + Token::Seq { len: Some(2) }, + Token::Tuple { len: 2 }, + Token::Str("hello"), + Token::Bool(true), + Token::TupleEnd, + Token::Tuple { len: 2 }, + Token::Str("world!"), + Token::Bool(false), + Token::TupleEnd, + Token::SeqEnd, + ]); } #[test] fn ipld_serialize_link() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - assert_ser_tokens( - &ipld, - &[ - Token::NewtypeStruct { - name: CID_SERDE_PRIVATE_IDENTIFIER, - }, - Token::Bytes(&[ - 1, 85, 18, 32, 159, 228, 204, 198, 222, 22, 114, 79, 58, 48, 199, 232, 242, 84, - 243, 198, 71, 25, 134, 172, 177, 248, 216, 207, 142, 150, 206, 42, 215, 219, 231, - 251, - ]), - ], - ); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + assert_ser_tokens(&ipld, &[ + Token::NewtypeStruct { name: CID_SERDE_PRIVATE_IDENTIFIER }, + Token::Bytes(&[ + 1, 85, 18, 32, 159, 228, 204, 198, 222, 22, 114, 79, 58, 48, 199, 232, + 242, 84, 243, 198, 71, 25, 134, 172, 177, 248, 216, 207, 142, 150, 206, + 42, 215, 219, 231, 251, + ]), + ]); } #[test] #[should_panic(expected = "expected Token::Bytes")] fn ipld_serialize_link_not_as_bytes() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - assert_ser_tokens( - &ipld, - &[Token::Bytes(&[ - 1, 85, 18, 32, 159, 228, 204, 198, 222, 22, 114, 79, 58, 48, 199, 232, 242, 84, 243, - 198, 71, 25, 134, 172, 177, 248, 216, 207, 142, 150, 206, 42, 215, 219, 231, 251, - ])], - ); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + assert_ser_tokens(&ipld, &[Token::Bytes(&[ + 1, 85, 18, 32, 159, 228, 204, 198, 222, 22, 114, 79, 58, 48, 199, 232, 242, + 84, 243, 198, 71, 25, 134, 172, 177, 248, 216, 207, 142, 150, 206, 42, 215, + 219, 231, 251, + ])]); } diff --git a/core/tests/serde_serializer.rs b/core/tests/serde_serializer.rs index 353e3d1d..c8b0dc08 100644 --- a/core/tests/serde_serializer.rs +++ b/core/tests/serde_serializer.rs @@ -5,263 +5,283 @@ extern crate alloc; use alloc::collections::BTreeMap; use core::convert::TryFrom; -use serde::{ser, Serialize}; +use serde::{ + ser, + Serialize, +}; use serde_bytes::ByteBuf; -use libipld_core::cid::Cid; -use libipld_core::ipld::Ipld; -use libipld_core::serde::to_ipld; +use libipld_core::{ + cid::Cid, + ipld::Ipld, + serde::to_ipld, +}; fn assert_serialized(input: T, ipld: Ipld) -where - T: ser::Serialize, -{ - let serialized = to_ipld(input).unwrap(); - assert_eq!(serialized, ipld); +where T: ser::Serialize { + let serialized = to_ipld(input).unwrap(); + assert_eq!(serialized, ipld); } #[test] fn ipld_serializer_unit() { - let unit = (); - let serialized = to_ipld(unit); - assert!(serialized.is_err()); + let unit = (); + let serialized = to_ipld(unit).unwrap(); + let ipld = Ipld::List(vec![]); + assert_eq!(serialized, ipld) } #[test] fn ipld_serializer_unit_struct() { - #[derive(Clone, Debug, Serialize, PartialEq)] - struct UnitStruct; + #[derive(Clone, Debug, Serialize, PartialEq)] + struct UnitStruct; - let unit_struct = UnitStruct; - let serialized = to_ipld(unit_struct); - assert!(serialized.is_err()); + let unit_struct = UnitStruct; + let serialized = to_ipld(unit_struct).unwrap(); + let ipld = Ipld::List(vec![]); + assert_eq!(serialized, ipld) } #[test] fn ipld_serializer_bool() { - let bool = false; - let ipld = Ipld::Bool(bool); - assert_serialized(bool, ipld); + let bool = false; + let ipld = Ipld::Bool(bool); + assert_serialized(bool, ipld); } #[test] fn ipld_serializer_u8() { - let integer = 34u8; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 34u8; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_u16() { - let integer = 345u16; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 345u16; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_u32() { - let integer = 345678u32; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 345678u32; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_u64() { - let integer = 34567890123u64; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 34567890123u64; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_i8() { - let integer = -23i8; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = -23i8; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_i16() { - let integer = 2345i16; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 2345i16; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_i32() { - let integer = 234567i32; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 234567i32; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_i64() { - let integer = 2345678901i64; - let ipld = Ipld::Integer(integer.into()); - assert_serialized(integer, ipld); + let integer = 2345678901i64; + let ipld = Ipld::Integer(integer.into()); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_i128() { - let integer = 34567890123467890123i128; - let ipld = Ipld::Integer(integer); - assert_serialized(integer, ipld); + let integer = 34567890123467890123i128; + let ipld = Ipld::Integer(integer); + assert_serialized(integer, ipld); } #[test] fn ipld_serializer_f32() { - let float = 7.3f32; - let ipld = Ipld::Float(float.into()); - assert_serialized(float, ipld); + let float = 7.3f32; + let ipld = Ipld::Float(float.into()); + assert_serialized(float, ipld); + assert!(to_ipld(f32::NAN).is_err()); + assert!(to_ipld(f32::INFINITY).is_err()); + assert!(to_ipld(f32::NEG_INFINITY).is_err()); } #[test] fn ipld_serializer_f64() { - let float = 427.8f64; - let ipld = Ipld::Float(float); - assert_serialized(float, ipld); + let float = 427.8f64; + let ipld = Ipld::Float(float); + assert_serialized(float, ipld); + assert!(to_ipld(f64::NAN).is_err()); + assert!(to_ipld(f64::INFINITY).is_err()); + assert!(to_ipld(f64::NEG_INFINITY).is_err()); } #[test] fn ipld_serializer_char() { - let char = 'x'; - let ipld = Ipld::String(char.to_string()); - assert_serialized(char, ipld); + let char = 'x'; + let ipld = Ipld::String(char.to_string()); + assert_serialized(char, ipld); } #[test] fn ipld_serializer_str() { - let str: &str = "hello"; - let ipld = Ipld::String(str.to_string()); - assert_serialized(str, ipld); + let str: &str = "hello"; + let ipld = Ipld::String(str.to_string()); + assert_serialized(str, ipld); } #[test] fn ipld_serializer_bytes() { - let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::Bytes(bytes.clone()); - assert_serialized(ByteBuf::from(bytes), ipld); + let bytes = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::Bytes(bytes.clone()); + assert_serialized(ByteBuf::from(bytes), ipld); } #[test] fn ipld_serializer_list() { - let list = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let ipld = Ipld::List(vec![ - Ipld::Integer(0x68), - Ipld::Integer(0x65), - Ipld::Integer(0x6c), - Ipld::Integer(0x6c), - Ipld::Integer(0x6f), - ]); - assert_serialized(list, ipld); + let list = vec![0x68, 0x65, 0x6c, 0x6c, 0x6f]; + let ipld = Ipld::List(vec![ + Ipld::Integer(0x68), + Ipld::Integer(0x65), + Ipld::Integer(0x6c), + Ipld::Integer(0x6c), + Ipld::Integer(0x6f), + ]); + assert_serialized(list, ipld); } #[test] fn ipld_serializer_tuple() { - let tuple = (true, "hello".to_string()); - let ipld = Ipld::List(vec![Ipld::Bool(tuple.0), Ipld::String(tuple.1.clone())]); - assert_serialized(tuple, ipld); + let tuple = (true, "hello".to_string()); + let ipld = + Ipld::List(vec![Ipld::Bool(tuple.0), Ipld::String(tuple.1.clone())]); + assert_serialized(tuple, ipld); } #[test] fn ipld_serializer_tuple_struct() { - #[derive(Clone, Debug, Serialize, PartialEq)] - struct TupleStruct(u8, bool); + #[derive(Clone, Debug, Serialize, PartialEq)] + struct TupleStruct(u8, bool); - let tuple_struct = TupleStruct(82, true); - let ipld = Ipld::List(vec![Ipld::Integer(82), Ipld::Bool(true)]); - assert_serialized(tuple_struct, ipld); + let tuple_struct = TupleStruct(82, true); + let ipld = Ipld::List(vec![Ipld::Integer(82), Ipld::Bool(true)]); + assert_serialized(tuple_struct, ipld); } #[test] fn ipld_serializer_map() { - let map = BTreeMap::from([("hello".to_string(), true), ("world!".to_string(), false)]); - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".to_string(), Ipld::Bool(true)), - ("world!".to_string(), Ipld::Bool(false)), - ])); - assert_serialized(map, ipld); + let map = BTreeMap::from([ + ("hello".to_string(), true), + ("world!".to_string(), false), + ]); + let ipld = Ipld::List(vec![ + Ipld::List(vec![Ipld::String("hello".to_string()), Ipld::Bool(true)]), + Ipld::List(vec![Ipld::String("world!".to_string()), Ipld::Bool(false)]), + ]); + assert_serialized(map, ipld); } /// A CID is deserialized through a newtype struct. #[test] fn ipld_serializer_cid() { - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let ipld = Ipld::Link(cid); - assert_serialized(cid, ipld); + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let ipld = Ipld::Link(cid); + assert_serialized(cid, ipld); } #[test] fn ipld_serializer_newtype_struct() { - #[derive(Clone, Debug, Serialize, PartialEq)] - struct Wrapped(u8); + #[derive(Clone, Debug, Serialize, PartialEq)] + struct Wrapped(u8); - let newtype_struct = Wrapped(3); - let ipld = Ipld::Integer(3); - assert_serialized(newtype_struct, ipld); + let newtype_struct = Wrapped(3); + let ipld = Ipld::Integer(3); + assert_serialized(newtype_struct, ipld); } /// An additional test, just to make sure that wrapped CIDs also work. #[test] fn ipld_serializer_newtype_struct_cid() { - #[derive(Clone, Debug, Serialize, PartialEq)] - struct Wrapped(Cid); - - let cid = Cid::try_from("bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m").unwrap(); - let newtype_struct = Wrapped(cid); - let ipld = Ipld::Link(cid); - assert_serialized(newtype_struct, ipld); + #[derive(Clone, Debug, Serialize, PartialEq)] + struct Wrapped(Cid); + + let cid = Cid::try_from( + "bafkreie74tgmnxqwojhtumgh5dzfj46gi4mynlfr7dmm7duwzyvnpw7h7m", + ) + .unwrap(); + let newtype_struct = Wrapped(cid); + let ipld = Ipld::Link(cid); + assert_serialized(newtype_struct, ipld); } #[test] fn ipld_serializer_option() { - let option_some: Option = Some(58u8); - let option_none: Option = None; - let ipld_some = Ipld::Integer(option_some.unwrap().into()); - let ipld_none = Ipld::Null; - assert_serialized(option_some, ipld_some); - assert_serialized(option_none, ipld_none); + let option_some: Option = Some(58u8); + let option_none: Option = None; + let ipld_some = Ipld::Integer(option_some.unwrap().into()); + let ipld_none = Ipld::Null; + assert_serialized(option_some, ipld_some); + assert_serialized(option_none, ipld_none); } #[test] fn ipld_serializer_enum() { - #[derive(Clone, Debug, Serialize, PartialEq)] - enum MyEnum { - One, - Two(u8), - Three { value: bool }, - } - - let enum_one = MyEnum::One; - let ipld_one = Ipld::String("One".into()); - assert_serialized(enum_one, ipld_one); - - let enum_two = MyEnum::Two(4); - let ipld_two = Ipld::Map(BTreeMap::from([("Two".into(), Ipld::Integer(4))])); - assert_serialized(enum_two, ipld_two); - - let enum_three = MyEnum::Three { value: true }; - let ipld_three = Ipld::Map(BTreeMap::from([( - "Three".into(), - Ipld::Map(BTreeMap::from([("value".into(), Ipld::Bool(true))])), - )])); - assert_serialized(enum_three, ipld_three); + #[derive(Clone, Debug, Serialize, PartialEq)] + enum MyEnum { + Unit, + Newtype(u8), + Tuple(u8, u8), + Struct { value: bool }, + } + + let enum_unit = MyEnum::Unit; + let ipld_unit = Ipld::List(vec![Ipld::Integer(0)]); + assert_serialized(enum_unit, ipld_unit); + + let enum_newtype = MyEnum::Newtype(4); + let ipld_newtype = Ipld::List(vec![Ipld::Integer(1), Ipld::Integer(4)]); + assert_serialized(enum_newtype, ipld_newtype); + + let enum_tuple = MyEnum::Tuple(4, 5); + let ipld_tuple = + Ipld::List(vec![Ipld::Integer(2), Ipld::Integer(4), Ipld::Integer(5)]); + assert_serialized(enum_tuple, ipld_tuple); + let enum_struct = MyEnum::Struct { value: true }; + let ipld_struct = Ipld::List(vec![Ipld::Integer(3), Ipld::Bool(true)]); + assert_serialized(enum_struct, ipld_struct); } #[test] fn ipld_serializer_struct() { - #[derive(Clone, Debug, Serialize, PartialEq)] - struct MyStruct { - hello: u8, - world: bool, - } - - let my_struct = MyStruct { - hello: 91, - world: false, - }; - let ipld = Ipld::Map(BTreeMap::from([ - ("hello".into(), Ipld::Integer(my_struct.hello.into())), - ("world".into(), Ipld::Bool(my_struct.world)), - ])); - assert_serialized(my_struct, ipld); + #[derive(Clone, Debug, Serialize, PartialEq)] + struct MyStruct { + hello: u8, + world: bool, + } + + let my_struct = MyStruct { hello: 91, world: false }; + let ipld = Ipld::List(vec![ + Ipld::Integer(my_struct.hello.into()), + Ipld::Bool(my_struct.world), + ]); + assert_serialized(my_struct, ipld); } diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 00000000..089bedf4 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly-2022-04-24 diff --git a/shell.nix b/shell.nix new file mode 100644 index 00000000..a99929f2 --- /dev/null +++ b/shell.nix @@ -0,0 +1,39 @@ +{ pkgs ? import {} }: + pkgs.mkShell rec { + buildInputs = with pkgs; [ + llvmPackages_latest.llvm + llvmPackages_latest.bintools + zlib.out + rustup + xorriso + grub2 + llvmPackages_latest.lld + python3 + ]; + RUSTC_VERSION = pkgs.lib.readFile ./rust-toolchain; + # https://github.com/rust-lang/rust-bindgen#environment-variables + LIBCLANG_PATH= pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ]; + HISTFILE=toString ./.history; + shellHook = '' + export PATH=$PATH:~/.cargo/bin + export PATH=$PATH:~/.rustup/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/ + ''; + # Add libvmi precompiled library to rustc search path + RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [ + pkgs.libvmi + ]); + # Add libvmi, glibc, clang, glib headers to bindgen search path + BINDGEN_EXTRA_CLANG_ARGS = + # Includes with normal include path + (builtins.map (a: ''-I"${a}/include"'') [ + pkgs.libvmi + pkgs.glibc.dev + ]) + # Includes with special directory paths + ++ [ + ''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"'' + ''-I"${pkgs.glib.dev}/include/glib-2.0"'' + ''-I${pkgs.glib.out}/lib/glib-2.0/include/'' + ]; + + }