From 77258af83dfe93293ad854ccb401d1ce7453edfc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Oct 2020 23:33:26 +0000 Subject: Make `SimpleValue` deserializable within other types Fixes https://github.com/Nadrieril/dhall-rust/issues/184 --- serde_dhall/src/deserialize.rs | 119 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 7 deletions(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 6d3aab8..1206033 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -1,12 +1,17 @@ +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::convert::TryInto as _; +use std::fmt; + use serde::de::value::{ MapAccessDeserializer, MapDeserializer, SeqDeserializer, }; -use std::borrow::Cow; +use serde::de::VariantAccess as _; use dhall::syntax::NumKind; use crate::value::SimpleValue; -use crate::{Error, ErrorKind, Result, Value}; +use crate::{Error, ErrorKind, Value}; pub trait Sealed {} @@ -38,7 +43,7 @@ pub trait Sealed {} /// [serde]: https://serde.rs pub trait FromDhall: Sealed + Sized { #[doc(hidden)] - fn from_dhall(v: &Value) -> Result; + fn from_dhall(v: &Value) -> crate::Result; } impl Sealed for T where T: serde::de::DeserializeOwned {} @@ -83,7 +88,7 @@ struct Deserializer<'a>(Cow<'a, SimpleValue>); /// ``` /// /// [`SimpleValue`]: enum.SimpleValue.html -pub fn from_simple_value(v: SimpleValue) -> Result +pub fn from_simple_value(v: SimpleValue) -> crate::Result where T: serde::de::DeserializeOwned, { @@ -94,7 +99,7 @@ impl FromDhall for T where T: serde::de::DeserializeOwned, { - fn from_dhall(v: &Value) -> Result { + 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: {}", @@ -115,7 +120,7 @@ impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { type Error = Error; - fn deserialize_any(self, visitor: V) -> Result + fn deserialize_any(self, visitor: V) -> crate::Result where V: serde::de::Visitor<'de>, { @@ -167,7 +172,11 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { } } - fn deserialize_tuple(self, _: usize, visitor: V) -> Result + fn deserialize_tuple( + self, + _: usize, + visitor: V, + ) -> crate::Result where V: serde::de::Visitor<'de>, { @@ -186,3 +195,99 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { 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 { + // TODO: use `i64` instead of `isize` in `NumKind`. + Ok(SimpleValue::Num(NumKind::Integer( + value.try_into().unwrap(), + ))) + } + + fn visit_u64(self, value: u64) -> Result { + // TODO: use `u64` instead of `usize` in `NumKind`. + Ok(SimpleValue::Num(NumKind::Natural( + value.try_into().unwrap(), + ))) + } + + 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) + } +} -- cgit v1.2.3