diff options
author | Nadrieril | 2020-04-05 17:57:07 +0100 |
---|---|---|
committer | GitHub | 2020-04-05 17:57:07 +0100 |
commit | 7e977f282fb6a0eff0ef45738b9b5c98dc4c6fee (patch) | |
tree | ad4249609707fd8720a44469152105c2f6a67c79 /serde_dhall/src/deserialize.rs | |
parent | 5a5aa49e64197899006751db72e404f4b2292d4e (diff) | |
parent | 820214615547101f8f2b5de209b5189968bddfee (diff) |
Merge pull request #154 from Nadrieril/cleanup-api
Rewrite serde_dhall API
Diffstat (limited to '')
-rw-r--r-- | serde_dhall/src/deserialize.rs | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs new file mode 100644 index 0000000..92be2e9 --- /dev/null +++ b/serde_dhall/src/deserialize.rs @@ -0,0 +1,143 @@ +use serde::de::value::{ + MapAccessDeserializer, MapDeserializer, SeqDeserializer, +}; +use std::borrow::Cow; + +use dhall::syntax::NumKind; + +use crate::value::SimpleValue; +use crate::{Error, ErrorKind, Result, 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) -> Result<Self>; +} + +impl<T> Sealed for T where T: serde::de::DeserializeOwned {} + +struct Deserializer<'a>(Cow<'a, SimpleValue>); + +impl<T> FromDhall for T +where + T: serde::de::DeserializeOwned, +{ + fn from_dhall(v: &Value) -> Result<Self> { + let sval = v.to_simple_value().ok_or_else(|| { + Error(ErrorKind::Deserialize(format!( + "this cannot be deserialized into the serde data model: {}", + v + ))) + })?; + T::deserialize(Deserializer(Cow::Owned(sval))) + } +} + +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<V>(self, visitor: V) -> Result<V::Value> + where + V: serde::de::Visitor<'de>, + { + use std::convert::TryInto; + 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)) => { + if let Ok(x64) = (*x).try_into() { + visitor.visit_u64(x64) + } else if let Ok(x32) = (*x).try_into() { + visitor.visit_u32(x32) + } else { + unimplemented!() + } + } + Num(Integer(x)) => { + if let Ok(x64) = (*x).try_into() { + visitor.visit_i64(x64) + } else if let Ok(x32) = (*x).try_into() { + visitor.visit_i32(x32) + } else { + unimplemented!() + } + } + 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_ref(), 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<V>(self, _: usize, visitor: V) -> Result<V::Value> + 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), + } + } + + 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 unit_struct newtype_struct seq + tuple_struct map struct enum identifier ignored_any + } +} |