use crate::any::Any; use crate::encoding::read::Error; use serde::de::value::{MapAccessDeserializer, MapDeserializer, SeqDeserializer}; use serde::de::{IntoDeserializer, MapAccess, SeqAccess, Visitor}; use serde::{Deserialize, Deserializer}; use std::any::type_name; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fmt::{Display, Formatter}; use std::sync::Arc; pub fn from_any<'de, T: Deserialize<'de>>(any: &'de Any) -> Result { let deserializer = AnyDeserializer { value: any }; T::deserialize(deserializer) } impl<'de> Deserialize<'de> for Any { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct AnyVisitor; impl<'de> Visitor<'de> for AnyVisitor { type Value = Any; fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { formatter.write_str("enum Any") } fn visit_bool(self, v: bool) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_i8(self, v: i8) -> Result where E: serde::de::Error, { Ok(Any::Number(v as f64)) } fn visit_i16(self, v: i16) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_i32(self, v: i32) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_i64(self, v: i64) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_u8(self, v: u8) -> Result where E: serde::de::Error, { Ok(Any::Number(v as f64)) } fn visit_u16(self, v: u16) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_u32(self, v: u32) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_u64(self, v: u64) -> Result where E: serde::de::Error, { match Any::try_from(v) { Ok(any) => Ok(any), Err(v) => Err(serde::de::Error::custom(format!( "Value {} out of range for i64", v ))), } } fn visit_f32(self, v: f32) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_f64(self, v: f64) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_char(self, v: char) -> Result where E: serde::de::Error, { Ok(Any::from(v.to_string())) } fn visit_str(self, v: &str) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_borrowed_str(self, v: &'de str) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_string(self, v: String) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_bytes(self, v: &[u8]) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_byte_buf(self, v: Vec) -> Result where E: serde::de::Error, { Ok(Any::from(v)) } fn visit_none(self) -> Result where E: serde::de::Error, { Ok(Any::Null) } fn visit_some(self, deserializer: D) -> Result where D: Deserializer<'de>, { Any::deserialize(deserializer) } fn visit_unit(self) -> Result where E: serde::de::Error, { Ok(Any::Null) } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut vec = Vec::new(); while let Some(value) = seq.next_element()? { vec.push(value); } Ok(Any::Array(vec.into())) } fn visit_map(self, mut map: A) -> Result where A: MapAccess<'de>, { let mut any_map = HashMap::new(); while let Some((key, value)) = map.next_entry()? { any_map.insert(key, value); } Ok(Any::Map(Arc::new(any_map))) } } deserializer.deserialize_any(AnyVisitor) } } pub struct AnyDeserializer<'a> { value: &'a Any, } impl<'de, 'a: 'de> IntoDeserializer<'de, Error> for &'a Any { type Deserializer = AnyDeserializer<'de>; fn into_deserializer(self) -> Self::Deserializer { AnyDeserializer { value: self } } } impl serde::de::Error for Error { fn custom(msg: T) -> Self where T: Display, { Error::Custom(msg.to_string()) } } impl<'de> Deserializer<'de> for AnyDeserializer<'de> { type Error = Error; fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Null => self.deserialize_unit(visitor), Any::Undefined => self.deserialize_unit(visitor), Any::Bool(_) => self.deserialize_bool(visitor), Any::Number(_) => self.deserialize_f64(visitor), Any::BigInt(_) => self.deserialize_i64(visitor), Any::String(_) => self.deserialize_string(visitor), Any::Buffer(_) => self.deserialize_byte_buf(visitor), Any::Array(_) => self.deserialize_seq(visitor), Any::Map(_) => self.deserialize_map(visitor), } } fn deserialize_bool(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Bool(b) => visitor.visit_bool(*b), _ => Err(Error::TypeMismatch(type_name::())), } } fn deserialize_i8(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_i8(value) } fn deserialize_i16(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_i16(value) } fn deserialize_i32(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_i32(value) } fn deserialize_i64(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), }; visitor.visit_i64(value) } fn deserialize_u8(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_u8(value) } fn deserialize_u16(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_u16(value) } fn deserialize_u32(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_u32(value) } fn deserialize_u64(self, visitor: V) -> Result where V: Visitor<'de>, { let value = match self.value { Any::Number(i) => { if i.fract() == 0.0 { *i as i64 } else { return Err(Error::type_mismatch::()); } } Any::BigInt(i) => *i, _ => return Err(Error::type_mismatch::()), } .try_into() .map_err(|_| Error::UnexpectedValue)?; visitor.visit_u64(value) } fn deserialize_f32(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Number(f) => visitor.visit_f32(*f as f32), Any::BigInt(f) => visitor.visit_f32(*f as f32), _ => Err(Error::type_mismatch::()), } } fn deserialize_f64(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Number(f) => visitor.visit_f64(*f), Any::BigInt(f) => visitor.visit_f64(*f as f64), _ => Err(Error::type_mismatch::()), } } fn deserialize_char(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::String(s) => { let mut chars = s.chars(); // Match on first two characters match (chars.next(), chars.next()) { (Some(c), None) => visitor.visit_char(c), _ => Err(Error::type_mismatch::()), } } _ => Err(Error::type_mismatch::()), } } fn deserialize_str(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::String(s) => visitor.visit_borrowed_str(s), _ => Err(Error::type_mismatch::<&str>()), } } fn deserialize_string(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::String(s) => visitor.visit_string(s.to_string()), _ => Err(Error::type_mismatch::()), } } fn deserialize_bytes(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Buffer(b) => visitor.visit_borrowed_bytes(b), _ => Err(Error::type_mismatch::<&[u8]>()), } } fn deserialize_byte_buf(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Buffer(b) => visitor.visit_bytes(b), _ => Err(Error::type_mismatch::>()), } } fn deserialize_option(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Null | Any::Undefined => visitor.visit_none(), _ => visitor.visit_some(self), } } fn deserialize_unit(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Null | Any::Undefined => visitor.visit_unit(), _ => Err(Error::type_mismatch::<()>()), } } fn deserialize_unit_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_unit(visitor) } fn deserialize_newtype_struct( self, _name: &'static str, visitor: V, ) -> Result where V: Visitor<'de>, { visitor.visit_newtype_struct(self) } fn deserialize_seq(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Array(a) => visitor.visit_seq(SeqDeserializer::new(a.iter())), _ => visitor.visit_some(self), } } fn deserialize_tuple(self, _len: usize, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_tuple_struct( self, _name: &'static str, _len: usize, visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_seq(visitor) } fn deserialize_map(self, visitor: V) -> Result where V: Visitor<'de>, { match self.value { Any::Map(m) => visitor.visit_map(MapDeserializer::new( m.iter().map(|(key, value)| (key.as_str(), value)), )), _ => Err(Error::type_mismatch::()), } } fn deserialize_struct( self, _name: &'static str, _fields: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_enum( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: Visitor<'de>, { match self.value { Any::String(s) => visitor.visit_enum(s.into_deserializer()), Any::Map(m) => visitor.visit_enum(MapAccessDeserializer::new(MapDeserializer::new( m.iter().map(|(key, value)| (key.as_str(), value)), ))), _ => Err(Error::type_mismatch::()), } } fn deserialize_identifier(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_str(visitor) } fn deserialize_ignored_any(self, visitor: V) -> Result where V: Visitor<'de>, { self.deserialize_any(visitor) } } #[cfg(test)] mod test { use super::*; use crate::any::Any; use serde::Deserialize; use std::collections::HashMap; #[test] fn test_deserialize_any_from_bool() { assert_eq!( serde_json::from_str::("true").unwrap(), Any::from(true) ); } #[test] fn test_deserialize_any_from_float() { assert_eq!( serde_json::from_str::("18.812036").unwrap(), Any::from(18.812036f64) ); } #[test] fn test_deserialize_any_from_int() { assert_eq!(serde_json::from_str::("18").unwrap(), Any::from(18)); } #[test] fn test_deserialize_any_from_int_unrepresentable() { assert!(serde_json::from_str::(&u64::MAX.to_string()).is_err()); } #[test] fn test_deserialize_any_from_string() { assert_eq!( serde_json::from_str::("\"string\"").unwrap(), Any::from("string") ); } #[test] fn test_deserialize_any_from_null() { assert_eq!(serde_json::from_str::("null").unwrap(), Any::Null); } #[test] fn test_deserialize_any_from_array() { assert_eq!( serde_json::from_str::("[true, -101]").unwrap(), Any::from(vec![Any::from(true), Any::from(-101)]) ); } #[test] fn test_deserialize_any_from_map() { assert_eq!( serde_json::from_str::("{\"key1\":true,\"key2\":-12307.2138}").unwrap(), Any::from(HashMap::from([ ("key1".into(), Any::from(true)), ("key2".into(), Any::from(-12307.2138f64)) ])) ); } #[test] fn test_deserialize_any_from_nested_map() { assert_eq!( serde_json::from_str::("{\"key1\":true,\"key2\":1.1,\"key3\":{\"key4\":true,\"key5\":1},\"key6\":[true,1,null]}").unwrap(), Any::from(HashMap::from([ ("key1".into(), Any::from(true)), ("key2".into(), Any::from(1.1f64)), ("key3".into(), Any::from( HashMap::from([ ("key4".into(), Any::from(true)), ("key5".into(), Any::from(1)) ]) )), ("key6".into(), Any::from(vec![Any::from(true), Any::from(1), Any::Null])) ]) ) ); } #[test] fn test_any_deserializer_many_fields() { #[derive(Debug, Deserialize, PartialEq)] struct Test { bool: bool, int: i64, negative_int: i64, max_int: i64, min_int: i64, real_number: f64, max_number: f64, min_number: f64, null: Option, some: Option, undefined: Option, nested: Nested, enum_a: StringEnum, enum_b: StringEnum, } #[derive(Debug, Deserialize, PartialEq)] struct Nested { int: i16, other: f32, } #[derive(Debug, Deserialize, PartialEq)] enum StringEnum { VariantA, VariantB, } let any = Any::from(HashMap::from([ ("bool".to_string(), Any::from(true)), ("int".to_string(), Any::from(1)), ("negative_int".to_string(), Any::from(-1)), ("max_int".to_string(), Any::from(i64::MAX)), ("min_int".to_string(), Any::from(i64::MIN)), ("real_number".to_string(), Any::from(-123.2387f64)), ("max_number".to_string(), Any::from(f64::MIN)), ("min_number".to_string(), Any::from(f64::MAX)), ("null".to_string(), Any::Null), ("some".to_string(), Any::from(false)), ("undefined".to_string(), Any::Undefined), ( "nested".to_string(), Any::from(HashMap::from([ ("int".to_string(), Any::from(100)), ("other".to_string(), Any::from(100.0)), ])), ), ("enum_a".to_string(), "VariantA".into()), ("enum_b".to_string(), "VariantB".into()), ])); assert_eq!( Test { bool: true, int: 1, negative_int: -1, max_int: i64::MAX, min_int: i64::MIN, real_number: -123.2387f64, max_number: f64::MIN, min_number: f64::MAX, null: None, some: Some(false), undefined: None, nested: Nested { int: 100, other: 100.0 }, enum_a: StringEnum::VariantA, enum_b: StringEnum::VariantB }, from_any(&any).unwrap() ) } #[test] fn test_deserialize_any_to_any() { let any = Any::from(HashMap::from([ ("bool".to_string(), Any::from(true)), ("int".to_string(), Any::from(1)), ("negative_int".to_string(), Any::from(-1)), ("max_int".to_string(), Any::from(i64::MAX)), ("min_int".to_string(), Any::from(i64::MIN)), ("real_number".to_string(), Any::from(-123.2387f64)), ("max_number".to_string(), Any::from(f64::MIN)), ("min_number".to_string(), Any::from(f64::MAX)), ("null".to_string(), Any::Null), ("some".to_string(), Any::from(false)), ( "nested".to_string(), Any::from(HashMap::from([ ("int".to_string(), Any::from(1i64 << 54)), ("other".to_string(), Any::from(100.0)), ])), ), ("enum_a".to_string(), "VariantA".into()), ("enum_b".to_string(), "VariantB".into()), ])); assert_eq!(any, from_any(&any.clone()).unwrap()) } #[test] fn test_any_deserializer_multiple_borrows() { #[derive(Debug, Deserialize, PartialEq)] struct Test<'a> { str: &'a str, bytes: &'a [u8], } let any = Any::from(HashMap::from([ ("str".to_string(), Any::from("String")), ("bytes".to_string(), b"Bytes".to_vec().into()), ])); assert_eq!( Test { str: "String", bytes: b"Bytes" }, from_any(&any).unwrap() ) } #[test] fn test_any_deserializer_nested_array() { #[derive(Debug, Deserialize, PartialEq)] struct Test { array: Vec>, } let any: Any = HashMap::from([( "array".to_string(), Any::from(vec![ Any::from(vec![Any::Bool(true), Any::Bool(false)]), Any::from(vec![Any::Bool(true)]), ]), )]) .into(); assert_eq!( Test { array: vec![vec![true, false], vec![true]] }, from_any(&any).unwrap() ) } #[test] fn test_any_deserializer_undefined() { #[derive(Debug, Deserialize, PartialEq)] struct Test { undefined: Option, } let any: Any = HashMap::from([("undefined".to_string(), Any::Undefined)]).into(); assert_eq!(Test { undefined: None }, from_any(&any).unwrap()) } #[test] fn test_any_deserializer_int_does_not_fit_error() { #[derive(Debug, Deserialize, PartialEq)] struct Test { test: i8, } let any: Any = HashMap::from([("test".to_string(), Any::BigInt(1000))]).into(); assert!(matches!( from_any::(&any).unwrap_err(), Error::UnexpectedValue, )) } #[test] fn test_any_deserializer_type_mismatch_error() { #[derive(Debug, Deserialize, PartialEq)] struct Test { test: i8, } let any: Any = HashMap::from([("test".to_string(), Any::Number(1000.1f64))]).into(); let error = from_any::(&any).unwrap_err(); match error { Error::TypeMismatch("i8") => { /* ok */ } other => panic!("unexpected error {}", other), } } }