From bc12f1179143f20a54664ba8ce51d24834d2f1ff Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 16 Jan 2020 17:20:10 +0000 Subject: Deserialize more types --- serde_dhall/src/lib.rs | 22 +++++++++ serde_dhall/src/serde.rs | 109 ++++++++++++++++++++++++++++++++++------- serde_dhall/src/static_type.rs | 11 +++-- 3 files changed, 121 insertions(+), 21 deletions(-) (limited to 'serde_dhall/src') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 45aca57..0878471 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -64,6 +64,28 @@ //! # } //! ``` //! +//! # Type correspondence +//! +//! The following Dhall types correspond to the following Rust types: +//! +//! Dhall | Rust +//! -------|------ +//! `Bool` | `bool` +//! `Natural` | `u64`, `u32`, ... +//! `Integer` | `i64`, `i32`, ... +//! `Double` | `f64`, `f32`, ... +//! `Text` | `String` +//! `List T` | `Vec` +//! `Optional T` | `Option` +//! `{ x: T, y: U }` | structs +//! `{ _1: T, _2: U }` | `(T, U)`, structs +//! `{ x: T, y: T }` | `HashMap`, structs +//! `< x: T \| y: U >` | enums +//! `T -> U` | unsupported +//! `Prelude.JSON.Type` | unsupported +//! `Prelude.Map.Type T U` | unsupported +//! +//! //! # Replacing `serde_json` or `serde_yaml` //! //! If you used to consume JSON or YAML, you only need to replace [serde_json::from_str] or diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 99b9014..2e449df 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,5 +1,9 @@ use std::borrow::Cow; +use serde::de::value::{ + MapAccessDeserializer, MapDeserializer, SeqDeserializer, +}; + use dhall::semantics::phase::NormalizedExpr; use dhall::syntax::ExprKind; @@ -28,43 +32,112 @@ 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 where V: serde::de::Visitor<'de>, { use std::convert::TryInto; use ExprKind::*; - match self.0.as_ref().as_ref() { - NaturalLit(n) => { - if let Ok(n64) = (*n).try_into() { - visitor.visit_u64(n64) - } else if let Ok(n32) = (*n).try_into() { - visitor.visit_u32(n32) + let expr = self.0.as_ref(); + let not_serde_compatible = || { + Err(Error::Deserialize(format!( + "this cannot be deserialized into the serde data model: {}", + expr + ))) + }; + + match expr.as_ref() { + BoolLit(x) => visitor.visit_bool(*x), + NaturalLit(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!() } } - IntegerLit(n) => { - if let Ok(n64) = (*n).try_into() { - visitor.visit_i64(n64) - } else if let Ok(n32) = (*n).try_into() { - visitor.visit_i32(n32) + IntegerLit(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!() } } - RecordLit(m) => visitor.visit_map( - serde::de::value::MapDeserializer::new(m.iter().map( - |(k, v)| (k.as_ref(), Deserializer(Cow::Borrowed(v))), - )), - ), - _ => unimplemented!(), + DoubleLit(x) => visitor.visit_f64((*x).into()), + TextLit(x) => { + // Normal form ensures that the tail is empty. + assert!(x.tail().is_empty()); + visitor.visit_str(x.head()) + } + EmptyListLit(..) => { + visitor.visit_seq(SeqDeserializer::new(None::<()>.into_iter())) + } + NEListLit(xs) => visitor.visit_seq(SeqDeserializer::new( + xs.iter().map(|x| Deserializer(Cow::Borrowed(x))), + )), + SomeLit(x) => visitor.visit_some(Deserializer(Cow::Borrowed(x))), + App(f, x) => match f.as_ref() { + Builtin(dhall::syntax::Builtin::OptionalNone) => { + visitor.visit_none() + } + Field(y, name) => match y.as_ref() { + UnionType(..) => { + let name: String = name.into(); + visitor.visit_enum(MapAccessDeserializer::new( + MapDeserializer::new( + Some((name, Deserializer(Cow::Borrowed(x)))) + .into_iter(), + ), + )) + } + _ => not_serde_compatible(), + }, + _ => not_serde_compatible(), + }, + RecordLit(m) => visitor + .visit_map(MapDeserializer::new(m.iter().map(|(k, v)| { + (k.as_ref(), Deserializer(Cow::Borrowed(v))) + }))), + Field(y, name) => match y.as_ref() { + UnionType(..) => { + let name: String = name.into(); + visitor.visit_enum(MapAccessDeserializer::new( + MapDeserializer::new(Some((name, ())).into_iter()), + )) + } + _ => not_serde_compatible(), + }, + Const(..) | Var(..) | Lam(..) | Pi(..) | Let(..) | Annot(..) + | Assert(..) | Builtin(..) | BinOp(..) | BoolIf(..) + | RecordType(..) | UnionType(..) | Merge(..) | ToMap(..) + | Projection(..) | ProjectionByExpr(..) | Completion(..) + | Import(..) | Embed(..) => not_serde_compatible(), + } + } + + fn deserialize_tuple(self, _: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + use ExprKind::*; + let expr = self.0.as_ref(); + + match expr.as_ref() { + // Blindly takes keys in sorted order. + RecordLit(m) => visitor.visit_seq(SeqDeserializer::new( + m.iter().map(|(_, v)| Deserializer(Cow::Borrowed(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 + bytes byte_buf option unit unit_struct newtype_struct seq tuple_struct map struct enum identifier ignored_any } } diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 1323aa3..1eb9150 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,4 +1,4 @@ -use dhall::syntax::{Builtin, Integer, Natural}; +use dhall::syntax::Builtin; use crate::Value; @@ -28,9 +28,14 @@ macro_rules! derive_builtin { } derive_builtin!(bool, Bool); -derive_builtin!(Natural, Natural); +derive_builtin!(usize, Natural); derive_builtin!(u64, Natural); -derive_builtin!(Integer, Integer); +derive_builtin!(u32, Natural); +derive_builtin!(isize, Integer); +derive_builtin!(i64, Integer); +derive_builtin!(i32, Integer); +derive_builtin!(f64, Double); +derive_builtin!(f32, Double); derive_builtin!(String, Text); impl StaticType for (A, B) -- cgit v1.2.3