use std::borrow::Cow; use std::collections::BTreeMap; use std::fmt; use serde::de::value::{ MapAccessDeserializer, MapDeserializer, SeqDeserializer, }; use serde::de::VariantAccess as _; use dhall::syntax::NumKind; use crate::value::SimpleValue; use crate::{Error, ErrorKind, Value}; pub trait Sealed {} /// A data structure that can be deserialized from a Dhall expression. /// /// This is automatically implemented for any type that [serde] can deserialize. /// In fact, this trait cannot be implemented manually. To implement it for your type, /// use serde's derive mechanism. /// /// # Example /// /// ```rust /// # fn main() -> serde_dhall::Result<()> { /// use serde::Deserialize; /// /// // Use serde's derive /// #[derive(Deserialize)] /// struct Point { /// x: u64, /// y: u64, /// } /// /// // Convert a Dhall string to a Point. /// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }").parse()?; /// # Ok(()) /// # } /// ``` /// /// [serde]: https://serde.rs pub trait FromDhall: Sealed + Sized { #[doc(hidden)] fn from_dhall(v: &Value) -> crate::Result; } impl Sealed for T where T: serde::de::DeserializeOwned {} /// Deserialize a Rust value from a Dhall [`SimpleValue`]. /// /// # Example /// /// ```rust /// # fn main() -> serde_dhall::Result<()> { /// use std::collections::BTreeMap; /// use serde::Deserialize; /// /// // We use serde's derive feature /// #[derive(Deserialize)] /// struct Point { /// x: u64, /// y: u64, /// } /// /// // Some Dhall data /// let mut data = BTreeMap::new(); /// data.insert( /// "x".to_string(), /// serde_dhall::SimpleValue::Num(serde_dhall::NumKind::Natural(1)) /// ); /// data.insert( /// "y".to_string(), /// serde_dhall::SimpleValue::Num(serde_dhall::NumKind::Natural(2)) /// ); /// let data = serde_dhall::SimpleValue::Record(data); /// /// // Parse the Dhall value as a Point. /// let point: Point = serde_dhall::from_simple_value(data)?; /// /// assert_eq!(point.x, 1); /// assert_eq!(point.y, 2); /// # Ok(()) /// # } /// ``` /// pub fn from_simple_value(v: SimpleValue) -> crate::Result where T: serde::de::DeserializeOwned, { T::deserialize(Deserializer(Cow::Owned(v))) } impl FromDhall for T where T: serde::de::DeserializeOwned, { fn from_dhall(v: &Value) -> crate::Result { let sval = v.to_simple_value().ok_or_else(|| { Error(ErrorKind::Deserialize(format!( "this cannot be deserialized into the serde data model: {}", v ))) })?; from_simple_value(sval) } } struct Deserializer<'a>(Cow<'a, SimpleValue>); impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { type Deserializer = Deserializer<'a>; fn into_deserializer(self) -> Self::Deserializer { self } } impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { type Error = Error; fn deserialize_any(self, visitor: V) -> crate::Result where V: serde::de::Visitor<'de>, { use NumKind::*; use SimpleValue::*; let val = |x| Deserializer(Cow::Borrowed(x)); match self.0.as_ref() { Num(Bool(x)) => visitor.visit_bool(*x), Num(Natural(x)) => visitor.visit_u64(*x), Num(Integer(x)) => visitor.visit_i64(*x), Num(Double(x)) => visitor.visit_f64((*x).into()), Text(x) => visitor.visit_str(x), List(xs) => { visitor.visit_seq(SeqDeserializer::new(xs.iter().map(val))) } Optional(None) => visitor.visit_none(), Optional(Some(x)) => visitor.visit_some(val(x)), Record(m) => visitor.visit_map(MapDeserializer::new( m.iter().map(|(k, v)| (k.as_str(), val(v))), )), Union(field_name, Some(x)) => visitor.visit_enum( MapAccessDeserializer::new(MapDeserializer::new( Some((field_name.as_str(), val(x))).into_iter(), )), ), Union(field_name, None) => visitor.visit_enum( MapAccessDeserializer::new(MapDeserializer::new( Some((field_name.as_str(), ())).into_iter(), )), ), } } fn deserialize_tuple( self, _: usize, visitor: V, ) -> crate::Result where V: serde::de::Visitor<'de>, { let val = |x| Deserializer(Cow::Borrowed(x)); match self.0.as_ref() { // Blindly takes keys in sorted order. SimpleValue::Record(m) => visitor .visit_seq(SeqDeserializer::new(m.iter().map(|(_, v)| val(v)))), _ => self.deserialize_any(visitor), } } fn deserialize_unit(self, visitor: V) -> crate::Result where V: serde::de::Visitor<'de>, { match self.0.as_ref() { SimpleValue::Record(m) if m.is_empty() => visitor.visit_unit(), _ => self.deserialize_any(visitor), } } serde::forward_to_deserialize_any! { bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes byte_buf option unit_struct newtype_struct seq tuple_struct map struct enum identifier ignored_any } } struct SimpleValueVisitor; impl<'de> serde::de::Visitor<'de> for SimpleValueVisitor { type Value = SimpleValue; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("any valid Dhall value") } fn visit_bool(self, value: bool) -> Result { Ok(SimpleValue::Num(NumKind::Bool(value))) } fn visit_i64(self, value: i64) -> Result { Ok(SimpleValue::Num(NumKind::Integer(value))) } fn visit_u64(self, value: u64) -> Result { Ok(SimpleValue::Num(NumKind::Natural(value))) } fn visit_f64(self, value: f64) -> Result { Ok(SimpleValue::Num(NumKind::Double(value.into()))) } fn visit_str(self, value: &str) -> Result { Ok(SimpleValue::Text(String::from(value))) } fn visit_string(self, value: String) -> Result { Ok(SimpleValue::Text(value)) } fn visit_none(self) -> Result { Ok(SimpleValue::Optional(None)) } fn visit_some(self, val: D) -> Result where D: serde::Deserializer<'de>, { let val = val.deserialize_any(SimpleValueVisitor)?; Ok(SimpleValue::Optional(Some(Box::new(val)))) } fn visit_enum(self, visitor: V) -> Result where V: serde::de::EnumAccess<'de>, { let (name, variant): (String, _) = visitor.variant()?; // Serde does not allow me to check what kind of variant it is. This will work for dhall // values, because there are only two possible kinds of cvariants, but doesn't work in // general. Given that the `serde_value` crate ignores enums, I assume this is not fixable // :(. let val = variant.newtype_variant().ok(); Ok(SimpleValue::Union(name, val)) } fn visit_seq(self, mut visitor: V) -> Result where V: serde::de::SeqAccess<'de>, { let mut vec = Vec::new(); while let Some(elem) = visitor.next_element()? { vec.push(elem); } Ok(SimpleValue::List(vec)) } fn visit_map(self, mut visitor: V) -> Result where V: serde::de::MapAccess<'de>, { let mut record = BTreeMap::default(); while let Some((key, value)) = visitor.next_entry()? { record.insert(key, value); } Ok(SimpleValue::Record(record)) } } impl<'de> serde::de::Deserialize<'de> for SimpleValue { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { deserializer.deserialize_any(SimpleValueVisitor) } }