From 52f9ecfc4dac65d305fd920e8c7f748889a0804f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 12 Aug 2019 23:24:48 +0200 Subject: Move api into its own crate --- serde_dhall/Cargo.toml | 12 ++ serde_dhall/src/lib.rs | 264 +++++++++++++++++++++++++++++++++++++++++ serde_dhall/src/serde.rs | 70 +++++++++++ serde_dhall/src/static_type.rs | 93 +++++++++++++++ serde_dhall/tests/traits.rs | 68 +++++++++++ 5 files changed, 507 insertions(+) create mode 100644 serde_dhall/Cargo.toml create mode 100644 serde_dhall/src/lib.rs create mode 100644 serde_dhall/src/serde.rs create mode 100644 serde_dhall/src/static_type.rs create mode 100644 serde_dhall/tests/traits.rs (limited to 'serde_dhall') diff --git a/serde_dhall/Cargo.toml b/serde_dhall/Cargo.toml new file mode 100644 index 0000000..c61ddcd --- /dev/null +++ b/serde_dhall/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "serde_dhall" +version = "0.1.0" +authors = ["Nadrieril "] +license = "BSD-2-Clause" +edition = "2018" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +dhall = { path = "../dhall" } +dhall_syntax = { path = "../dhall_syntax" } +dhall_proc_macros = { path = "../dhall_proc_macros" } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs new file mode 100644 index 0000000..1dbbf99 --- /dev/null +++ b/serde_dhall/src/lib.rs @@ -0,0 +1,264 @@ +//! [Dhall][dhall] is a programmable configuration language that provides a non-repetitive +//! alternative to JSON and YAML. +//! +//! You can think of Dhall as: JSON + types + imports + functions +//! +//! For a description of the dhall language, examples, tutorials, and more, see the [language +//! website][dhall]. +//! +//! This crate provides support for consuming dhall files the same way you would consume JSON or +//! YAML. It uses the [Serde][serde] serialization library to provide drop-in support for dhall +//! for any datatype that supports serde (and that's a lot of them !). +//! +//! This library is limited to deserializing (reading) dhall values; serializing (writing) +//! values to dhall is not supported for now. +//! +//! # Examples +//! +//! ### Custom datatype +//! +//! If you have a custom datatype for which you derived [serde::Deserialize], chances are +//! you will be able to derive [StaticType][de::StaticType] for it as well. +//! This gives you access to a dhall representation of your datatype that can be outputted +//! to users, and allows easy type-safe deserializing. +//! +//! ```edition2018 +//! use serde::Deserialize; +//! use serde_dhall::de::StaticType; +//! +//! #[derive(Debug, Deserialize, StaticType)] +//! struct Point { +//! x: u64, +//! y: u64, +//! } +//! +//! fn main() { +//! // Some dhall data +//! let data = "{ x = 1, y = 1 + 1 }"; +//! +//! // Convert the dhall string to a Point. +//! let point: Point = +//! serde_dhall::de::from_str_auto_type(&data) +//! .expect("An error ocurred !"); +//! +//! // Prints "point = Point { x: 1, y: 2 }" +//! println!("point = {:?}", point); +//! } +//! ``` +//! +//! ### Loosely typed +//! +//! If you used to consume JSON or YAML in a loosely typed way, you can continue to do so +//! with dhall. You only need to replace [serde_json::from_str] or [serde_yaml::from_str] +//! with [serde_dhall::de::from_str][de::from_str]. +//! More generally, if the [StaticType][de::StaticType] derive doesn't suit your +//! needs, you can still deserialize any valid dhall file that serde can handle. +//! +//! [serde_json::from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html +//! [serde_yaml::from_str]: https://docs.serde.rs/serde_yaml/fn.from_str.html +//! +//! ```edition2018 +//! use std::collections::BTreeMap; +//! +//! let mut map = BTreeMap::new(); +//! map.insert("x".to_string(), 1); +//! map.insert("y".to_string(), 2); +//! +//! // Some dhall data +//! let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; +//! +//! // Deserialize it to a Rust type. +//! let deserialized_map: BTreeMap = +//! serde_dhall::de::from_str(&data, None) +//! .expect("Failed reading the data !"); +//! assert_eq!(map, deserialized_map); +//! ``` +//! +//! You can of course specify a dhall type that the input should match. +//! +//! ```edition2018 +//! use std::collections::BTreeMap; +//! +//! let mut map = BTreeMap::new(); +//! map.insert("x".to_string(), 1); +//! map.insert("y".to_string(), 2); +//! +//! // Some dhall data +//! let point_data = "{ x = 1, y = 1 + 1 }"; +//! let point_type_data = "{ x: Natural, y: Natural }"; +//! +//! // Construct a type +//! let point_type = +//! serde_dhall::de::from_str(point_type_data, None) +//! .expect("Could not parse the Point type"); +//! +//! // Deserialize it to a Rust type. +//! let deserialized_map: BTreeMap = +//! serde_dhall::de::from_str(&point_data, Some(&point_type)) +//! .expect("Failed reading the data !"); +//! assert_eq!(map, deserialized_map); +//! ``` +//! +//! [dhall]: https://dhall-lang.org/ +//! [serde]: https://docs.serde.rs/serde/ +//! [serde::Deserialize]: https://docs.serde.rs/serde/trait.Deserialize.html + +mod serde; +pub(crate) mod static_type; + +pub use value::Value; + +mod value { + use super::Type; + use dhall::error::Result; + use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; + + // A Dhall value + pub struct Value(Typed); + + impl Value { + pub fn from_str(s: &str, ty: Option<&Type>) -> Result { + let resolved = Parsed::parse_str(s)?.resolve()?; + let typed = match ty { + None => resolved.typecheck()?, + Some(t) => resolved.typecheck_with(&t.to_type())?, + }; + Ok(Value(typed)) + } + pub(crate) fn to_expr(&self) -> NormalizedSubExpr { + self.0.to_expr() + } + pub(crate) fn to_typed(&self) -> Typed { + self.0.clone() + } + } +} + +pub use typ::Type; + +mod typ { + use dhall_syntax::Builtin; + + use dhall::core::thunk::{Thunk, TypeThunk}; + use dhall::core::value::Value; + use dhall::error::Result; + use dhall::phase::{NormalizedSubExpr, Typed}; + + /// A Dhall expression representing a type. + /// + /// This captures what is usually simply called a "type", like + /// `Bool`, `{ x: Integer }` or `Natural -> Text`. + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Type(Typed); + + impl Type { + pub(crate) fn from_value(v: Value) -> Self { + Type(Typed::from_value_untyped(v)) + } + pub(crate) fn make_builtin_type(b: Builtin) -> Self { + Self::from_value(Value::from_builtin(b)) + } + pub(crate) fn make_optional_type(t: Type) -> Self { + Self::from_value(Value::AppliedBuiltin( + Builtin::Optional, + vec![t.to_thunk()], + )) + } + pub(crate) fn make_list_type(t: Type) -> Self { + Self::from_value(Value::AppliedBuiltin( + Builtin::List, + vec![t.to_thunk()], + )) + } + #[doc(hidden)] + pub fn make_record_type( + kts: impl Iterator, + ) -> Self { + Self::from_value(Value::RecordType( + kts.map(|(k, t)| { + (k.into(), TypeThunk::from_thunk(t.to_thunk())) + }) + .collect(), + )) + } + #[doc(hidden)] + pub fn make_union_type( + kts: impl Iterator)>, + ) -> Self { + Self::from_value(Value::UnionType( + kts.map(|(k, t)| { + (k.into(), t.map(|t| TypeThunk::from_thunk(t.to_thunk()))) + }) + .collect(), + )) + } + + pub(crate) fn to_thunk(&self) -> Thunk { + self.0.to_thunk() + } + #[allow(dead_code)] + pub(crate) fn to_expr(&self) -> NormalizedSubExpr { + self.0.to_expr() + } + pub(crate) fn to_type(&self) -> dhall::phase::Type { + self.0.to_type() + } + } + + impl crate::de::Deserialize for Type { + fn from_dhall(v: &super::Value) -> Result { + Ok(Type(v.to_typed())) + } + } +} + +/// Deserialization of Dhall expressions into Rust +pub mod de { + pub use super::static_type::StaticType; + pub use super::{Type, Value}; + use dhall::error::Result; + #[doc(hidden)] + pub use dhall_proc_macros::StaticType; + + /// A data structure that can be deserialized from a Dhall expression + /// + /// This is automatically implemented for any type that [serde][serde] + /// can deserialize. + /// + /// This trait cannot be implemented manually. + // TODO: seal trait + pub trait Deserialize: Sized { + /// See [dhall::de::from_str][crate::de::from_str] + fn from_dhall(v: &Value) -> Result; + } + + /// Deserialize an instance of type T from a string of Dhall text. + /// + /// This will recursively resolve all imports in the expression, and + /// typecheck it before deserialization. Relative imports will be resolved relative to the + /// provided file. More control over this process is not yet available + /// but will be in a coming version of this crate. + /// + /// If a type is provided, this additionally checks that the provided + /// expression has that type. + pub fn from_str(s: &str, ty: Option<&Type>) -> Result + where + T: Deserialize, + { + T::from_dhall(&Value::from_str(s, ty)?) + } + + /// Deserialize an instance of type T from a string of Dhall text, + /// additionally checking that it matches the type of T. + /// + /// This will recursively resolve all imports in the expression, and + /// typecheck it before deserialization. Relative imports will be resolved relative to the + /// provided file. More control over this process is not yet available + /// but will be in a coming version of this crate. + pub fn from_str_auto_type(s: &str) -> Result + where + T: Deserialize + StaticType, + { + from_str(s, Some(&::static_type())) + } +} diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs new file mode 100644 index 0000000..3dad2d8 --- /dev/null +++ b/serde_dhall/src/serde.rs @@ -0,0 +1,70 @@ +use crate::de::{Deserialize, Value}; +use dhall::error::{Error, Result}; +use dhall_syntax::{ExprF, SubExpr, X}; +use std::borrow::Cow; + +impl<'a, T> Deserialize for T +where + T: serde::Deserialize<'a>, +{ + fn from_dhall(v: &Value) -> Result { + T::deserialize(Deserializer(Cow::Owned(v.to_expr()))) + } +} + +struct Deserializer<'a>(Cow<'a, SubExpr>); + +// impl serde::de::Error for Error { +// fn custom(msg: T) -> Self +// where +// T: std::fmt::Display, +// { +// Error::Deserialize(msg.to_string()) +// } +// } + +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) -> Result + where + V: serde::de::Visitor<'de>, + { + use std::convert::TryInto; + use ExprF::*; + match self.0.as_ref().as_ref() { + NaturalLit(n) => match (*n).try_into() { + Ok(n64) => visitor.visit_u64(n64), + Err(_) => match (*n).try_into() { + Ok(n32) => visitor.visit_u32(n32), + Err(_) => unimplemented!(), + }, + }, + IntegerLit(n) => match (*n).try_into() { + Ok(n64) => visitor.visit_i64(n64), + Err(_) => match (*n).try_into() { + Ok(n32) => visitor.visit_i32(n32), + Err(_) => unimplemented!(), + }, + }, + RecordLit(m) => visitor.visit_map( + serde::de::value::MapDeserializer::new(m.iter().map( + |(k, v)| (k.as_ref(), Deserializer(Cow::Borrowed(v))), + )), + ), + _ => unimplemented!(), + } + } + + 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 + tuple_struct map struct enum identifier ignored_any + } +} diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs new file mode 100644 index 0000000..13d5d70 --- /dev/null +++ b/serde_dhall/src/static_type.rs @@ -0,0 +1,93 @@ +use dhall_syntax::{Builtin, Integer, Natural}; + +use crate::Type; + +/// A Rust type that can be represented as a Dhall type. +/// +/// A typical example is `Option`, +/// represented by the dhall expression `Optional Bool`. +/// +/// This trait can and should be automatically derived. +/// +/// The representation needs to be independent of the value. +/// For this reason, something like `HashMap` cannot implement +/// [StaticType] because each different value would +/// have a different Dhall record type. +pub trait StaticType { + fn static_type() -> Type; +} + +macro_rules! derive_builtin { + ($ty:ty, $builtin:ident) => { + impl StaticType for $ty { + fn static_type() -> Type { + Type::make_builtin_type(Builtin::$builtin) + } + } + }; +} + +derive_builtin!(bool, Bool); +derive_builtin!(Natural, Natural); +derive_builtin!(u64, Natural); +derive_builtin!(Integer, Integer); +derive_builtin!(String, Text); + +impl StaticType for (A, B) +where + A: StaticType, + B: StaticType, +{ + fn static_type() -> Type { + Type::make_record_type( + vec![ + ("_1".to_owned(), A::static_type()), + ("_2".to_owned(), B::static_type()), + ] + .into_iter(), + ) + } +} + +impl StaticType for std::result::Result +where + T: StaticType, + E: StaticType, +{ + fn static_type() -> Type { + Type::make_union_type( + vec![ + ("Ok".to_owned(), Some(T::static_type())), + ("Err".to_owned(), Some(E::static_type())), + ] + .into_iter(), + ) + } +} + +impl StaticType for Option +where + T: StaticType, +{ + fn static_type() -> Type { + Type::make_optional_type(T::static_type()) + } +} + +impl StaticType for Vec +where + T: StaticType, +{ + fn static_type() -> Type { + Type::make_list_type(T::static_type()) + } +} + +impl<'a, T> StaticType for &'a T +where + T: StaticType, +{ + fn static_type() -> Type { + T::static_type() + } +} diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs new file mode 100644 index 0000000..99f1109 --- /dev/null +++ b/serde_dhall/tests/traits.rs @@ -0,0 +1,68 @@ +#![feature(proc_macro_hygiene)] +use serde_dhall::de::{from_str, StaticType, Type}; + +#[test] +fn test_static_type() { + fn parse(s: &str) -> Type { + from_str(s, None).unwrap() + } + + assert_eq!(bool::static_type(), parse("Bool")); + assert_eq!(String::static_type(), parse("Text")); + assert_eq!(>::static_type(), parse("Optional Bool")); + assert_eq!( + <(bool, Vec)>::static_type(), + parse("{ _1: Bool, _2: List Text }") + ); + + #[derive(serde_dhall::de::StaticType)] + #[allow(dead_code)] + struct A { + field1: bool, + field2: Option, + } + assert_eq!( + ::static_type(), + parse("{ field1: Bool, field2: Optional Bool }") + ); + + #[derive(StaticType)] + #[allow(dead_code)] + struct B<'a, T: 'a> { + field1: &'a T, + field2: Option, + } + assert_eq!(>::static_type(), A::static_type()); + + #[derive(StaticType)] + #[allow(dead_code)] + struct C(T, Option); + assert_eq!( + >::static_type(), + <(bool, Option)>::static_type() + ); + + #[derive(StaticType)] + #[allow(dead_code)] + struct D(); + assert_eq!( + >::static_type(), + parse("{ _1: {}, _2: Optional Text }") + ); + + #[derive(StaticType)] + #[allow(dead_code)] + enum E { + A(T), + B(String), + }; + assert_eq!(>::static_type(), parse("< A: Bool | B: Text >")); + + #[derive(StaticType)] + #[allow(dead_code)] + enum F { + A, + B(bool), + }; + assert_eq!(F::static_type(), parse("< A | B: Bool >")); +} -- cgit v1.2.3 From 74bb40e88c71b80ab785f07fd19da22404ab6e95 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 15:11:31 +0200 Subject: Add new error type for serde_dhall --- serde_dhall/src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++++------- serde_dhall/src/serde.rs | 12 +--------- 2 files changed, 51 insertions(+), 19 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 1dbbf99..f8f9ae9 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(non_exhaustive)] + //! [Dhall][dhall] is a programmable configuration language that provides a non-repetitive //! alternative to JSON and YAML. //! @@ -109,8 +111,8 @@ pub(crate) mod static_type; pub use value::Value; mod value { + use super::de::{Error, Result}; use super::Type; - use dhall::error::Result; use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; // A Dhall value @@ -118,6 +120,12 @@ mod value { impl Value { pub fn from_str(s: &str, ty: Option<&Type>) -> Result { + Value::from_str_using_dhall_error_type(s, ty).map_err(Error::Dhall) + } + fn from_str_using_dhall_error_type( + s: &str, + ty: Option<&Type>, + ) -> dhall::error::Result { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { None => resolved.typecheck()?, @@ -137,12 +145,12 @@ mod value { pub use typ::Type; mod typ { - use dhall_syntax::Builtin; - use dhall::core::thunk::{Thunk, TypeThunk}; use dhall::core::value::Value; - use dhall::error::Result; use dhall::phase::{NormalizedSubExpr, Typed}; + use dhall_syntax::Builtin; + + use super::de::Result; /// A Dhall expression representing a type. /// @@ -205,21 +213,55 @@ mod typ { } } - impl crate::de::Deserialize for Type { + impl super::de::Deserialize for Type { fn from_dhall(v: &super::Value) -> Result { Ok(Type(v.to_typed())) } } } +mod error { + use dhall::error::Error as DhallError; + + pub type Result = std::result::Result; + + #[derive(Debug)] + #[non_exhaustive] + pub enum Error { + Dhall(DhallError), + Deserialize(String), + } + + impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::Dhall(err) => write!(f, "{}", err), + Error::Deserialize(err) => write!(f, "{}", err), + } + } + } + + impl std::error::Error for Error {} + + impl serde::de::Error for Error { + fn custom(msg: T) -> Self + where + T: std::fmt::Display, + { + Error::Deserialize(msg.to_string()) + } + } +} + /// Deserialization of Dhall expressions into Rust pub mod de { - pub use super::static_type::StaticType; - pub use super::{Type, Value}; - use dhall::error::Result; #[doc(hidden)] pub use dhall_proc_macros::StaticType; + pub use super::error::{Error, Result}; + pub use super::static_type::StaticType; + pub use super::{Type, Value}; + /// A data structure that can be deserialized from a Dhall expression /// /// This is automatically implemented for any type that [serde][serde] diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 3dad2d8..1f639e6 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,5 +1,4 @@ -use crate::de::{Deserialize, Value}; -use dhall::error::{Error, Result}; +use crate::de::{Deserialize, Error, Result, Value}; use dhall_syntax::{ExprF, SubExpr, X}; use std::borrow::Cow; @@ -14,15 +13,6 @@ where struct Deserializer<'a>(Cow<'a, SubExpr>); -// impl serde::de::Error for Error { -// fn custom(msg: T) -> Self -// where -// T: std::fmt::Display, -// { -// Error::Deserialize(msg.to_string()) -// } -// } - impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { type Deserializer = Deserializer<'a>; fn into_deserializer(self) -> Self::Deserializer { -- cgit v1.2.3 From 1ea8b10051d29c634399304273d6ee565d039bc2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 15:25:53 +0200 Subject: Merge `Type` and `Value` in serde_dhall There was no point in separating them --- serde_dhall/src/lib.rs | 87 ++++++++++++++++-------------------------- serde_dhall/src/static_type.rs | 26 ++++++------- serde_dhall/tests/traits.rs | 4 +- 3 files changed, 47 insertions(+), 70 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index f8f9ae9..8e1af82 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -106,25 +106,29 @@ //! [serde::Deserialize]: https://docs.serde.rs/serde/trait.Deserialize.html mod serde; -pub(crate) mod static_type; +mod static_type; pub use value::Value; mod value { + use dhall::core::thunk::{Thunk, TypeThunk}; + use dhall::core::value::Value as DhallValue; + use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; + use dhall_syntax::Builtin; + use super::de::{Error, Result}; - use super::Type; - use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; - // A Dhall value + /// A Dhall value + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Value(Typed); impl Value { - pub fn from_str(s: &str, ty: Option<&Type>) -> Result { + pub fn from_str(s: &str, ty: Option<&Value>) -> Result { Value::from_str_using_dhall_error_type(s, ty).map_err(Error::Dhall) } fn from_str_using_dhall_error_type( s: &str, - ty: Option<&Type>, + ty: Option<&Value>, ) -> dhall::error::Result { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { @@ -136,53 +140,37 @@ mod value { pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - pub(crate) fn to_typed(&self) -> Typed { - self.0.clone() + pub(crate) fn to_thunk(&self) -> Thunk { + self.0.to_thunk() + } + pub(crate) fn to_type(&self) -> Type { + self.0.to_type() } - } -} - -pub use typ::Type; - -mod typ { - use dhall::core::thunk::{Thunk, TypeThunk}; - use dhall::core::value::Value; - use dhall::phase::{NormalizedSubExpr, Typed}; - use dhall_syntax::Builtin; - - use super::de::Result; - - /// A Dhall expression representing a type. - /// - /// This captures what is usually simply called a "type", like - /// `Bool`, `{ x: Integer }` or `Natural -> Text`. - #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Type(Typed); - impl Type { - pub(crate) fn from_value(v: Value) -> Self { - Type(Typed::from_value_untyped(v)) + pub(crate) fn from_dhall_value(v: DhallValue) -> Self { + Value(Typed::from_value_untyped(v)) } pub(crate) fn make_builtin_type(b: Builtin) -> Self { - Self::from_value(Value::from_builtin(b)) + Self::from_dhall_value(DhallValue::from_builtin(b)) } - pub(crate) fn make_optional_type(t: Type) -> Self { - Self::from_value(Value::AppliedBuiltin( + pub(crate) fn make_optional_type(t: Value) -> Self { + Self::from_dhall_value(DhallValue::AppliedBuiltin( Builtin::Optional, vec![t.to_thunk()], )) } - pub(crate) fn make_list_type(t: Type) -> Self { - Self::from_value(Value::AppliedBuiltin( + pub(crate) fn make_list_type(t: Value) -> Self { + Self::from_dhall_value(DhallValue::AppliedBuiltin( Builtin::List, vec![t.to_thunk()], )) } + // Made public for the StaticType derive macro #[doc(hidden)] pub fn make_record_type( - kts: impl Iterator, + kts: impl Iterator, ) -> Self { - Self::from_value(Value::RecordType( + Self::from_dhall_value(DhallValue::RecordType( kts.map(|(k, t)| { (k.into(), TypeThunk::from_thunk(t.to_thunk())) }) @@ -191,31 +179,20 @@ mod typ { } #[doc(hidden)] pub fn make_union_type( - kts: impl Iterator)>, + kts: impl Iterator)>, ) -> Self { - Self::from_value(Value::UnionType( + Self::from_dhall_value(DhallValue::UnionType( kts.map(|(k, t)| { (k.into(), t.map(|t| TypeThunk::from_thunk(t.to_thunk()))) }) .collect(), )) } - - pub(crate) fn to_thunk(&self) -> Thunk { - self.0.to_thunk() - } - #[allow(dead_code)] - pub(crate) fn to_expr(&self) -> NormalizedSubExpr { - self.0.to_expr() - } - pub(crate) fn to_type(&self) -> dhall::phase::Type { - self.0.to_type() - } } - impl super::de::Deserialize for Type { - fn from_dhall(v: &super::Value) -> Result { - Ok(Type(v.to_typed())) + impl super::de::Deserialize for Value { + fn from_dhall(v: &Value) -> Result { + Ok(v.clone()) } } } @@ -260,7 +237,7 @@ pub mod de { pub use super::error::{Error, Result}; pub use super::static_type::StaticType; - pub use super::{Type, Value}; + pub use super::Value; /// A data structure that can be deserialized from a Dhall expression /// @@ -283,7 +260,7 @@ pub mod de { /// /// If a type is provided, this additionally checks that the provided /// expression has that type. - pub fn from_str(s: &str, ty: Option<&Type>) -> Result + pub fn from_str(s: &str, ty: Option<&Value>) -> Result where T: Deserialize, { diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 13d5d70..67a7bc4 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,6 +1,6 @@ use dhall_syntax::{Builtin, Integer, Natural}; -use crate::Type; +use crate::Value; /// A Rust type that can be represented as a Dhall type. /// @@ -14,14 +14,14 @@ use crate::Type; /// [StaticType] because each different value would /// have a different Dhall record type. pub trait StaticType { - fn static_type() -> Type; + fn static_type() -> Value; } macro_rules! derive_builtin { ($ty:ty, $builtin:ident) => { impl StaticType for $ty { - fn static_type() -> Type { - Type::make_builtin_type(Builtin::$builtin) + fn static_type() -> Value { + Value::make_builtin_type(Builtin::$builtin) } } }; @@ -38,8 +38,8 @@ where A: StaticType, B: StaticType, { - fn static_type() -> Type { - Type::make_record_type( + fn static_type() -> Value { + Value::make_record_type( vec![ ("_1".to_owned(), A::static_type()), ("_2".to_owned(), B::static_type()), @@ -54,8 +54,8 @@ where T: StaticType, E: StaticType, { - fn static_type() -> Type { - Type::make_union_type( + fn static_type() -> Value { + Value::make_union_type( vec![ ("Ok".to_owned(), Some(T::static_type())), ("Err".to_owned(), Some(E::static_type())), @@ -69,8 +69,8 @@ impl StaticType for Option where T: StaticType, { - fn static_type() -> Type { - Type::make_optional_type(T::static_type()) + fn static_type() -> Value { + Value::make_optional_type(T::static_type()) } } @@ -78,8 +78,8 @@ impl StaticType for Vec where T: StaticType, { - fn static_type() -> Type { - Type::make_list_type(T::static_type()) + fn static_type() -> Value { + Value::make_list_type(T::static_type()) } } @@ -87,7 +87,7 @@ impl<'a, T> StaticType for &'a T where T: StaticType, { - fn static_type() -> Type { + fn static_type() -> Value { T::static_type() } } diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index 99f1109..40ac1d7 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,9 +1,9 @@ #![feature(proc_macro_hygiene)] -use serde_dhall::de::{from_str, StaticType, Type}; +use serde_dhall::de::{from_str, StaticType, Value}; #[test] fn test_static_type() { - fn parse(s: &str) -> Type { + fn parse(s: &str) -> Value { from_str(s, None).unwrap() } -- cgit v1.2.3 From bf5d33f3ba991afe398d58fb4fed38ec72d6f4c7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 16:31:41 +0200 Subject: Rework API to resemble that of serde_json --- serde_dhall/src/lib.rs | 200 ++++++++++++++++++++++++-------------------- serde_dhall/src/serde.rs | 3 +- serde_dhall/tests/traits.rs | 8 +- 3 files changed, 115 insertions(+), 96 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 8e1af82..19aabec 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -5,28 +5,27 @@ //! //! You can think of Dhall as: JSON + types + imports + functions //! -//! For a description of the dhall language, examples, tutorials, and more, see the [language +//! For a description of the Dhall language, examples, tutorials, and more, see the [language //! website][dhall]. //! -//! This crate provides support for consuming dhall files the same way you would consume JSON or -//! YAML. It uses the [Serde][serde] serialization library to provide drop-in support for dhall +//! This crate provides support for consuming Dhall files the same way you would consume JSON or +//! YAML. It uses the [Serde][serde] serialization library to provide drop-in support for Dhall //! for any datatype that supports serde (and that's a lot of them !). //! -//! This library is limited to deserializing (reading) dhall values; serializing (writing) -//! values to dhall is not supported for now. +//! This library is limited to deserializing (reading) Dhall values; serializing (writing) +//! values to Dhall is not supported for now. //! //! # Examples //! //! ### Custom datatype //! //! If you have a custom datatype for which you derived [serde::Deserialize], chances are -//! you will be able to derive [StaticType][de::StaticType] for it as well. -//! This gives you access to a dhall representation of your datatype that can be outputted -//! to users, and allows easy type-safe deserializing. +//! you will be able to derive [StaticType] for it as well. +//! This allows easy type-safe deserializing. //! //! ```edition2018 //! use serde::Deserialize; -//! use serde_dhall::de::StaticType; +//! use serde_dhall::{de::Error, StaticType}; //! //! #[derive(Debug, Deserialize, StaticType)] //! struct Point { @@ -34,71 +33,78 @@ //! y: u64, //! } //! -//! fn main() { -//! // Some dhall data +//! fn main() -> Result<(), Error> { +//! // Some Dhall data //! let data = "{ x = 1, y = 1 + 1 }"; //! -//! // Convert the dhall string to a Point. -//! let point: Point = -//! serde_dhall::de::from_str_auto_type(&data) -//! .expect("An error ocurred !"); +//! // Convert the Dhall string to a Point. +//! let point: Point = serde_dhall::from_str_auto_type(data)?; +//! assert_eq!(point.x, 1); +//! assert_eq!(point.y, 2); //! -//! // Prints "point = Point { x: 1, y: 2 }" -//! println!("point = {:?}", point); +//! // Invalid data fails the type validation +//! let invalid_data = "{ x = 1, z = 0.3 }"; +//! assert!(serde_dhall::from_str_auto_type::(invalid_data).is_err()); +//! +//! Ok(()) //! } //! ``` //! //! ### Loosely typed //! //! If you used to consume JSON or YAML in a loosely typed way, you can continue to do so -//! with dhall. You only need to replace [serde_json::from_str] or [serde_yaml::from_str] -//! with [serde_dhall::de::from_str][de::from_str]. -//! More generally, if the [StaticType][de::StaticType] derive doesn't suit your -//! needs, you can still deserialize any valid dhall file that serde can handle. +//! with Dhall. You only need to replace [serde_json::from_str] or [serde_yaml::from_str] +//! with [serde_dhall::from_str][from_str]. +//! More generally, if the [StaticType] derive doesn't suit your +//! needs, you can still deserialize any valid Dhall file that serde can handle. //! //! [serde_json::from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html //! [serde_yaml::from_str]: https://docs.serde.rs/serde_yaml/fn.from_str.html //! //! ```edition2018 +//! # fn main() -> serde_dhall::de::Result<()> { //! use std::collections::BTreeMap; //! -//! let mut map = BTreeMap::new(); -//! map.insert("x".to_string(), 1); -//! map.insert("y".to_string(), 2); -//! -//! // Some dhall data +//! // Some Dhall data //! let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; //! //! // Deserialize it to a Rust type. -//! let deserialized_map: BTreeMap = -//! serde_dhall::de::from_str(&data, None) -//! .expect("Failed reading the data !"); -//! assert_eq!(map, deserialized_map); +//! let deserialized_map: BTreeMap = serde_dhall::from_str(data)?; +//! +//! let mut expected_map = BTreeMap::new(); +//! expected_map.insert("x".to_string(), 1); +//! expected_map.insert("y".to_string(), 2); +//! +//! assert_eq!(deserialized_map, expected_map); +//! # Ok(()) +//! # } //! ``` //! -//! You can of course specify a dhall type that the input should match. +//! You can alternatively specify a Dhall type that the input should match. //! //! ```edition2018 +//! # fn main() -> serde_dhall::de::Result<()> { //! use std::collections::BTreeMap; //! -//! let mut map = BTreeMap::new(); -//! map.insert("x".to_string(), 1); -//! map.insert("y".to_string(), 2); +//! // Parse a Dhall type +//! let point_type_str = "{ x: Natural, y: Natural }"; +//! let point_type = serde_dhall::from_str(point_type_str)?; //! -//! // Some dhall data +//! // Some Dhall data //! let point_data = "{ x = 1, y = 1 + 1 }"; -//! let point_type_data = "{ x: Natural, y: Natural }"; -//! -//! // Construct a type -//! let point_type = -//! serde_dhall::de::from_str(point_type_data, None) -//! .expect("Could not parse the Point type"); //! -//! // Deserialize it to a Rust type. +//! // Deserialize the data to a Rust type. This ensures that +//! // the data matches the point type. //! let deserialized_map: BTreeMap = -//! serde_dhall::de::from_str(&point_data, Some(&point_type)) -//! .expect("Failed reading the data !"); -//! assert_eq!(map, deserialized_map); +//! serde_dhall::from_str_check_type(point_data, &point_type)?; +//! +//! let mut expected_map = BTreeMap::new(); +//! expected_map.insert("x".to_string(), 1); +//! expected_map.insert("y".to_string(), 2); +//! +//! assert_eq!(deserialized_map, expected_map); +//! # Ok(()) +//! # } //! ``` //! //! [dhall]: https://dhall-lang.org/ @@ -108,9 +114,16 @@ mod serde; mod static_type; +#[doc(inline)] +pub use de::{from_str, from_str_auto_type, from_str_check_type}; +#[doc(hidden)] +pub use dhall_proc_macros::StaticType; +pub use static_type::StaticType; +#[doc(inline)] pub use value::Value; -mod value { +// A Dhall value. +pub mod value { use dhall::core::thunk::{Thunk, TypeThunk}; use dhall::core::value::Value as DhallValue; use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; @@ -197,47 +210,44 @@ mod value { } } -mod error { - use dhall::error::Error as DhallError; +/// Deserialize Dhall data to a Rust data structure. +pub mod de { + use super::StaticType; + use super::Value; + pub use error::{Error, Result}; - pub type Result = std::result::Result; + mod error { + use dhall::error::Error as DhallError; - #[derive(Debug)] - #[non_exhaustive] - pub enum Error { - Dhall(DhallError), - Deserialize(String), - } + pub type Result = std::result::Result; - impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Error::Dhall(err) => write!(f, "{}", err), - Error::Deserialize(err) => write!(f, "{}", err), + #[derive(Debug)] + #[non_exhaustive] + pub enum Error { + Dhall(DhallError), + Deserialize(String), + } + + impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Error::Dhall(err) => write!(f, "{}", err), + Error::Deserialize(err) => write!(f, "{}", err), + } } } - } - impl std::error::Error for Error {} + impl std::error::Error for Error {} - impl serde::de::Error for Error { - fn custom(msg: T) -> Self - where - T: std::fmt::Display, - { - Error::Deserialize(msg.to_string()) + impl serde::de::Error for Error { + fn custom(msg: T) -> Self + where + T: std::fmt::Display, + { + Error::Deserialize(msg.to_string()) + } } } -} - -/// Deserialization of Dhall expressions into Rust -pub mod de { - #[doc(hidden)] - pub use dhall_proc_macros::StaticType; - - pub use super::error::{Error, Result}; - pub use super::static_type::StaticType; - pub use super::Value; /// A data structure that can be deserialized from a Dhall expression /// @@ -247,37 +257,45 @@ pub mod de { /// This trait cannot be implemented manually. // TODO: seal trait pub trait Deserialize: Sized { - /// See [dhall::de::from_str][crate::de::from_str] + /// See [serde_dhall::from_str][crate::from_str] fn from_dhall(v: &Value) -> Result; } - /// Deserialize an instance of type T from a string of Dhall text. + /// Deserialize an instance of type `T` from a string of Dhall text. /// /// This will recursively resolve all imports in the expression, and /// typecheck it before deserialization. Relative imports will be resolved relative to the /// provided file. More control over this process is not yet available /// but will be in a coming version of this crate. + pub fn from_str(s: &str) -> Result + where + T: Deserialize, + { + T::from_dhall(&Value::from_str(s, None)?) + } + + /// Deserialize an instance of type `T` from a string of Dhall text, + /// additionally checking that it matches the supplied type. /// - /// If a type is provided, this additionally checks that the provided - /// expression has that type. - pub fn from_str(s: &str, ty: Option<&Value>) -> Result + /// Like [from_str], but this additionally checks that + /// the type of the provided expression matches the supplied type. + pub fn from_str_check_type(s: &str, ty: &Value) -> Result where T: Deserialize, { - T::from_dhall(&Value::from_str(s, ty)?) + T::from_dhall(&Value::from_str(s, Some(ty))?) } - /// Deserialize an instance of type T from a string of Dhall text, - /// additionally checking that it matches the type of T. + /// Deserialize an instance of type `T` from a string of Dhall text, + /// additionally checking that it matches the type of `T`. /// - /// This will recursively resolve all imports in the expression, and - /// typecheck it before deserialization. Relative imports will be resolved relative to the - /// provided file. More control over this process is not yet available - /// but will be in a coming version of this crate. + /// Like [from_str], but this additionally checks that + /// the type of the provided expression matches the output type `T`. The [StaticType] trait + /// captures Rust types that are valid Dhall types. pub fn from_str_auto_type(s: &str) -> Result where T: Deserialize + StaticType, { - from_str(s, Some(&::static_type())) + from_str_check_type(s, &::static_type()) } } diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 1f639e6..10d5a17 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,4 +1,5 @@ -use crate::de::{Deserialize, Error, Result, Value}; +use crate::de::{Deserialize, Error, Result}; +use crate::Value; use dhall_syntax::{ExprF, SubExpr, X}; use std::borrow::Cow; diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index 40ac1d7..55be63b 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,10 +1,10 @@ #![feature(proc_macro_hygiene)] -use serde_dhall::de::{from_str, StaticType, Value}; +use serde_dhall::{from_str, StaticType, Value}; #[test] fn test_static_type() { fn parse(s: &str) -> Value { - from_str(s, None).unwrap() + from_str(s).unwrap() } assert_eq!(bool::static_type(), parse("Bool")); @@ -15,14 +15,14 @@ fn test_static_type() { parse("{ _1: Bool, _2: List Text }") ); - #[derive(serde_dhall::de::StaticType)] + #[derive(serde_dhall::StaticType)] #[allow(dead_code)] struct A { field1: bool, field2: Option, } assert_eq!( - ::static_type(), + ::static_type(), parse("{ field1: Bool, field2: Optional Bool }") ); -- cgit v1.2.3 From fb0120dffe8e9552c3da7b994ad850f66dc612a3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 17:21:54 +0200 Subject: s/TypeThunk/TypedThunk/g --- serde_dhall/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 19aabec..14d8b47 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -124,7 +124,7 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::core::thunk::{Thunk, TypeThunk}; + use dhall::core::thunk::{Thunk, TypedThunk}; use dhall::core::value::Value as DhallValue; use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; use dhall_syntax::Builtin; @@ -185,7 +185,7 @@ pub mod value { ) -> Self { Self::from_dhall_value(DhallValue::RecordType( kts.map(|(k, t)| { - (k.into(), TypeThunk::from_thunk(t.to_thunk())) + (k.into(), TypedThunk::from_thunk(t.to_thunk())) }) .collect(), )) @@ -196,7 +196,7 @@ pub mod value { ) -> Self { Self::from_dhall_value(DhallValue::UnionType( kts.map(|(k, t)| { - (k.into(), t.map(|t| TypeThunk::from_thunk(t.to_thunk()))) + (k.into(), t.map(|t| TypedThunk::from_thunk(t.to_thunk()))) }) .collect(), )) -- cgit v1.2.3 From 5895c3aa6552f75d7e5202be561f9734fe8945e7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 13 Aug 2019 19:31:23 +0200 Subject: No need to track the absence of `Span`s at the type level --- serde_dhall/src/serde.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 10d5a17..d891127 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,7 +1,10 @@ +use std::borrow::Cow; + +use dhall::phase::NormalizedSubExpr; +use dhall_syntax::ExprF; + use crate::de::{Deserialize, Error, Result}; use crate::Value; -use dhall_syntax::{ExprF, SubExpr, X}; -use std::borrow::Cow; impl<'a, T> Deserialize for T where @@ -12,7 +15,7 @@ where } } -struct Deserializer<'a>(Cow<'a, SubExpr>); +struct Deserializer<'a>(Cow<'a, NormalizedSubExpr>); impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { type Deserializer = Deserializer<'a>; -- cgit v1.2.3 From 816f616479cfa277e19b2e69be6c41bc8210e032 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 15 Aug 2019 22:12:06 +0200 Subject: Disable some unused unstable features --- serde_dhall/tests/traits.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'serde_dhall') diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index 55be63b..15a91ed 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,4 +1,3 @@ -#![feature(proc_macro_hygiene)] use serde_dhall::{from_str, StaticType, Value}; #[test] -- cgit v1.2.3 From 88ebc0f9d561a2541aad84a3152511a0439db8b4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 17:56:19 +0200 Subject: Reduce api surface of dhall crate Helps detect unused code --- serde_dhall/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 14d8b47..71674a9 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -167,16 +167,14 @@ pub mod value { Self::from_dhall_value(DhallValue::from_builtin(b)) } pub(crate) fn make_optional_type(t: Value) -> Self { - Self::from_dhall_value(DhallValue::AppliedBuiltin( - Builtin::Optional, - vec![t.to_thunk()], - )) + Self::from_dhall_value( + DhallValue::from_builtin(Builtin::Optional).app_thunk(t.to_thunk()), + ) } pub(crate) fn make_list_type(t: Value) -> Self { - Self::from_dhall_value(DhallValue::AppliedBuiltin( - Builtin::List, - vec![t.to_thunk()], - )) + Self::from_dhall_value( + DhallValue::from_builtin(Builtin::List).app_thunk(t.to_thunk()), + ) } // Made public for the StaticType derive macro #[doc(hidden)] -- cgit v1.2.3 From 5f0d69671b44ba1dff6becb9ebc7f6e74241e3e2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 18:14:55 +0200 Subject: Remove dead code --- serde_dhall/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 71674a9..f400206 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -168,7 +168,8 @@ pub mod value { } pub(crate) fn make_optional_type(t: Value) -> Self { Self::from_dhall_value( - DhallValue::from_builtin(Builtin::Optional).app_thunk(t.to_thunk()), + DhallValue::from_builtin(Builtin::Optional) + .app_thunk(t.to_thunk()), ) } pub(crate) fn make_list_type(t: Value) -> Self { -- cgit v1.2.3 From 45fb07f74f19919f742be6fe7793dc72d4022f26 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 19:16:40 +0200 Subject: Try to minimize untyped TypedThunks --- serde_dhall/src/lib.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index f400206..a277977 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -160,20 +160,21 @@ pub mod value { self.0.to_type() } - pub(crate) fn from_dhall_value(v: DhallValue) -> Self { - Value(Typed::from_value_untyped(v)) + /// Assumes that the given value has type `Type`. + pub(crate) fn make_simple_type(v: DhallValue) -> Self { + Value(Typed::from_value_and_type(v, Type::const_type())) } pub(crate) fn make_builtin_type(b: Builtin) -> Self { - Self::from_dhall_value(DhallValue::from_builtin(b)) + Self::make_simple_type(DhallValue::from_builtin(b)) } pub(crate) fn make_optional_type(t: Value) -> Self { - Self::from_dhall_value( + Self::make_simple_type( DhallValue::from_builtin(Builtin::Optional) .app_thunk(t.to_thunk()), ) } pub(crate) fn make_list_type(t: Value) -> Self { - Self::from_dhall_value( + Self::make_simple_type( DhallValue::from_builtin(Builtin::List).app_thunk(t.to_thunk()), ) } @@ -182,9 +183,9 @@ pub mod value { pub fn make_record_type( kts: impl Iterator, ) -> Self { - Self::from_dhall_value(DhallValue::RecordType( + Self::make_simple_type(DhallValue::RecordType( kts.map(|(k, t)| { - (k.into(), TypedThunk::from_thunk(t.to_thunk())) + (k.into(), TypedThunk::from_thunk_simple_type(t.to_thunk())) }) .collect(), )) @@ -193,9 +194,14 @@ pub mod value { pub fn make_union_type( kts: impl Iterator)>, ) -> Self { - Self::from_dhall_value(DhallValue::UnionType( + Self::make_simple_type(DhallValue::UnionType( kts.map(|(k, t)| { - (k.into(), t.map(|t| TypedThunk::from_thunk(t.to_thunk()))) + ( + k.into(), + t.map(|t| { + TypedThunk::from_thunk_simple_type(t.to_thunk()) + }), + ) }) .collect(), )) -- cgit v1.2.3 From e0f5216215ccb7a4df85d80e11dd265cdb52a44f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 16 Aug 2019 19:47:36 +0200 Subject: s/Value/ValueF/ --- serde_dhall/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index a277977..49fd40e 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -125,7 +125,7 @@ pub use value::Value; // A Dhall value. pub mod value { use dhall::core::thunk::{Thunk, TypedThunk}; - use dhall::core::value::Value as DhallValue; + use dhall::core::value::ValueF as DhallValue; use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; use dhall_syntax::Builtin; @@ -162,7 +162,7 @@ pub mod value { /// Assumes that the given value has type `Type`. pub(crate) fn make_simple_type(v: DhallValue) -> Self { - Value(Typed::from_value_and_type(v, Type::const_type())) + Value(Typed::from_valuef_and_type(v, Type::const_type())) } pub(crate) fn make_builtin_type(b: Builtin) -> Self { Self::make_simple_type(DhallValue::from_builtin(b)) -- cgit v1.2.3 From 6753a1f97bb674d91dd4d42f2ddb25a8119e070d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 17 Aug 2019 19:00:43 +0200 Subject: s/Thunk/Value/ --- serde_dhall/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 49fd40e..48f311e 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -124,8 +124,9 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::core::thunk::{Thunk, TypedThunk}; - use dhall::core::value::ValueF as DhallValue; + use dhall::core::value::TypedValue as TypedThunk; + use dhall::core::value::Value as Thunk; + use dhall::core::valuef::ValueF as DhallValue; use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; use dhall_syntax::Builtin; @@ -153,8 +154,8 @@ pub mod value { pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - pub(crate) fn to_thunk(&self) -> Thunk { - self.0.to_thunk() + pub(crate) fn to_value(&self) -> Thunk { + self.0.to_value() } pub(crate) fn to_type(&self) -> Type { self.0.to_type() @@ -170,12 +171,12 @@ pub mod value { pub(crate) fn make_optional_type(t: Value) -> Self { Self::make_simple_type( DhallValue::from_builtin(Builtin::Optional) - .app_thunk(t.to_thunk()), + .app_value(t.to_value()), ) } pub(crate) fn make_list_type(t: Value) -> Self { Self::make_simple_type( - DhallValue::from_builtin(Builtin::List).app_thunk(t.to_thunk()), + DhallValue::from_builtin(Builtin::List).app_value(t.to_value()), ) } // Made public for the StaticType derive macro @@ -185,7 +186,7 @@ pub mod value { ) -> Self { Self::make_simple_type(DhallValue::RecordType( kts.map(|(k, t)| { - (k.into(), TypedThunk::from_thunk_simple_type(t.to_thunk())) + (k.into(), TypedThunk::from_value_simple_type(t.to_value())) }) .collect(), )) @@ -199,7 +200,7 @@ pub mod value { ( k.into(), t.map(|t| { - TypedThunk::from_thunk_simple_type(t.to_thunk()) + TypedThunk::from_value_simple_type(t.to_value()) }), ) }) -- cgit v1.2.3 From 26a1fd0f0861038a76a0f9b09eaef16d808d4139 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 21:52:26 +0200 Subject: Use TypedValue instead of Typed in normalize and typecheck Now Typed is only used in dhall::phase, similarly to Parsed/Resolved/Normalized --- serde_dhall/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 48f311e..31643d0 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -127,7 +127,7 @@ pub mod value { use dhall::core::value::TypedValue as TypedThunk; use dhall::core::value::Value as Thunk; use dhall::core::valuef::ValueF as DhallValue; - use dhall::phase::{NormalizedSubExpr, Parsed, Type, Typed}; + use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; use dhall_syntax::Builtin; use super::de::{Error, Result}; @@ -147,7 +147,7 @@ pub mod value { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { None => resolved.typecheck()?, - Some(t) => resolved.typecheck_with(&t.to_type())?, + Some(t) => resolved.typecheck_with(t.as_typed())?, }; Ok(Value(typed)) } @@ -157,13 +157,13 @@ pub mod value { pub(crate) fn to_value(&self) -> Thunk { self.0.to_value() } - pub(crate) fn to_type(&self) -> Type { - self.0.to_type() + pub(crate) fn as_typed(&self) -> &Typed { + &self.0 } /// Assumes that the given value has type `Type`. pub(crate) fn make_simple_type(v: DhallValue) -> Self { - Value(Typed::from_valuef_and_type(v, Type::const_type())) + Value(Typed::from_valuef_and_type(v, Typed::const_type())) } pub(crate) fn make_builtin_type(b: Builtin) -> Self { Self::make_simple_type(DhallValue::from_builtin(b)) -- cgit v1.2.3 From 07a276c1d6ee892b93abbd7a73c78c96d56f4fe7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 22:26:17 +0200 Subject: Reduce untyped construction of Values --- serde_dhall/src/lib.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 31643d0..9d2ec85 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -186,7 +186,7 @@ pub mod value { ) -> Self { Self::make_simple_type(DhallValue::RecordType( kts.map(|(k, t)| { - (k.into(), TypedThunk::from_value_simple_type(t.to_value())) + (k.into(), TypedThunk::from_value(t.to_value())) }) .collect(), )) @@ -197,12 +197,7 @@ pub mod value { ) -> Self { Self::make_simple_type(DhallValue::UnionType( kts.map(|(k, t)| { - ( - k.into(), - t.map(|t| { - TypedThunk::from_value_simple_type(t.to_value()) - }), - ) + (k.into(), t.map(|t| TypedThunk::from_value(t.to_value()))) }) .collect(), )) -- cgit v1.2.3 From 730f2ebb146792994c7492b6c05f7d09d42cbccf Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 19 Aug 2019 23:00:49 +0200 Subject: Merge TypedValue and Value --- serde_dhall/src/lib.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 9d2ec85..cef11dd 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -124,9 +124,8 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::core::value::TypedValue as TypedThunk; - use dhall::core::value::Value as Thunk; - use dhall::core::valuef::ValueF as DhallValue; + use dhall::core::value::Value as DhallValue; + use dhall::core::valuef::ValueF as DhallValueF; use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; use dhall_syntax::Builtin; @@ -154,7 +153,7 @@ pub mod value { pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - pub(crate) fn to_value(&self) -> Thunk { + pub(crate) fn to_value(&self) -> DhallValue { self.0.to_value() } pub(crate) fn as_typed(&self) -> &Typed { @@ -162,21 +161,22 @@ pub mod value { } /// Assumes that the given value has type `Type`. - pub(crate) fn make_simple_type(v: DhallValue) -> Self { + pub(crate) fn make_simple_type(v: DhallValueF) -> Self { Value(Typed::from_valuef_and_type(v, Typed::const_type())) } pub(crate) fn make_builtin_type(b: Builtin) -> Self { - Self::make_simple_type(DhallValue::from_builtin(b)) + Self::make_simple_type(DhallValueF::from_builtin(b)) } pub(crate) fn make_optional_type(t: Value) -> Self { Self::make_simple_type( - DhallValue::from_builtin(Builtin::Optional) + DhallValueF::from_builtin(Builtin::Optional) .app_value(t.to_value()), ) } pub(crate) fn make_list_type(t: Value) -> Self { Self::make_simple_type( - DhallValue::from_builtin(Builtin::List).app_value(t.to_value()), + DhallValueF::from_builtin(Builtin::List) + .app_value(t.to_value()), ) } // Made public for the StaticType derive macro @@ -184,22 +184,17 @@ pub mod value { pub fn make_record_type( kts: impl Iterator, ) -> Self { - Self::make_simple_type(DhallValue::RecordType( - kts.map(|(k, t)| { - (k.into(), TypedThunk::from_value(t.to_value())) - }) - .collect(), + Self::make_simple_type(DhallValueF::RecordType( + kts.map(|(k, t)| (k.into(), t.to_value())).collect(), )) } #[doc(hidden)] pub fn make_union_type( kts: impl Iterator)>, ) -> Self { - Self::make_simple_type(DhallValue::UnionType( - kts.map(|(k, t)| { - (k.into(), t.map(|t| TypedThunk::from_value(t.to_value()))) - }) - .collect(), + Self::make_simple_type(DhallValueF::UnionType( + kts.map(|(k, t)| (k.into(), t.map(|t| t.to_value()))) + .collect(), )) } } -- cgit v1.2.3 From a506632b27b287d1bf898e2f77ae09a56902474c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 17:08:01 +0200 Subject: Naming tweaks --- serde_dhall/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index cef11dd..4171fab 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -169,14 +169,12 @@ pub mod value { } pub(crate) fn make_optional_type(t: Value) -> Self { Self::make_simple_type( - DhallValueF::from_builtin(Builtin::Optional) - .app_value(t.to_value()), + DhallValueF::from_builtin(Builtin::Optional).app(t.to_value()), ) } pub(crate) fn make_list_type(t: Value) -> Self { Self::make_simple_type( - DhallValueF::from_builtin(Builtin::List) - .app_value(t.to_value()), + DhallValueF::from_builtin(Builtin::List).app(t.to_value()), ) } // Made public for the StaticType derive macro -- cgit v1.2.3 From 4f1f37cfc115510500e83d2dfbfa8ed7ddeae74a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 18:03:59 +0200 Subject: Introduce a new enum to store either a Value or a ValueF --- serde_dhall/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 4171fab..e2449de 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -169,12 +169,16 @@ pub mod value { } pub(crate) fn make_optional_type(t: Value) -> Self { Self::make_simple_type( - DhallValueF::from_builtin(Builtin::Optional).app(t.to_value()), + DhallValueF::from_builtin(Builtin::Optional) + .app(t.to_value()) + .into_whnf(), ) } pub(crate) fn make_list_type(t: Value) -> Self { Self::make_simple_type( - DhallValueF::from_builtin(Builtin::List).app(t.to_value()), + DhallValueF::from_builtin(Builtin::List) + .app(t.to_value()) + .into_whnf(), ) } // Made public for the StaticType derive macro -- cgit v1.2.3 From 8c1ffc5b68489be4694fff922ca48afeb0d45fc4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 20 Aug 2019 23:02:56 +0200 Subject: Move type construction fns from serde_dhall to dhall --- serde_dhall/src/lib.rs | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index e2449de..ce3468f 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -124,8 +124,6 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::core::value::Value as DhallValue; - use dhall::core::valuef::ValueF as DhallValueF; use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; use dhall_syntax::Builtin; @@ -153,50 +151,32 @@ pub mod value { pub(crate) fn to_expr(&self) -> NormalizedSubExpr { self.0.to_expr() } - pub(crate) fn to_value(&self) -> DhallValue { - self.0.to_value() - } pub(crate) fn as_typed(&self) -> &Typed { &self.0 } - /// Assumes that the given value has type `Type`. - pub(crate) fn make_simple_type(v: DhallValueF) -> Self { - Value(Typed::from_valuef_and_type(v, Typed::const_type())) - } pub(crate) fn make_builtin_type(b: Builtin) -> Self { - Self::make_simple_type(DhallValueF::from_builtin(b)) + Value(Typed::make_builtin_type(b)) } pub(crate) fn make_optional_type(t: Value) -> Self { - Self::make_simple_type( - DhallValueF::from_builtin(Builtin::Optional) - .app(t.to_value()) - .into_whnf(), - ) + Value(Typed::make_optional_type(t.0)) } pub(crate) fn make_list_type(t: Value) -> Self { - Self::make_simple_type( - DhallValueF::from_builtin(Builtin::List) - .app(t.to_value()) - .into_whnf(), - ) + Value(Typed::make_list_type(t.0)) } // Made public for the StaticType derive macro #[doc(hidden)] pub fn make_record_type( kts: impl Iterator, ) -> Self { - Self::make_simple_type(DhallValueF::RecordType( - kts.map(|(k, t)| (k.into(), t.to_value())).collect(), - )) + Value(Typed::make_record_type(kts.map(|(k, t)| (k, t.0)))) } #[doc(hidden)] pub fn make_union_type( kts: impl Iterator)>, ) -> Self { - Self::make_simple_type(DhallValueF::UnionType( - kts.map(|(k, t)| (k.into(), t.map(|t| t.to_value()))) - .collect(), + Value(Typed::make_union_type( + kts.map(|(k, t)| (k, t.map(|t| t.0))), )) } } -- cgit v1.2.3 From a981afc465f4279a7a4d6ce3ac5844e04846613b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Aug 2019 22:58:20 +0200 Subject: clippy --- serde_dhall/src/serde.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index d891127..94b7e6c 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -33,20 +33,24 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { use std::convert::TryInto; use ExprF::*; match self.0.as_ref().as_ref() { - NaturalLit(n) => match (*n).try_into() { - Ok(n64) => visitor.visit_u64(n64), - Err(_) => match (*n).try_into() { - Ok(n32) => visitor.visit_u32(n32), - Err(_) => unimplemented!(), - }, - }, - IntegerLit(n) => match (*n).try_into() { - Ok(n64) => visitor.visit_i64(n64), - Err(_) => match (*n).try_into() { - Ok(n32) => visitor.visit_i32(n32), - Err(_) => unimplemented!(), - }, - }, + 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) + } 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) + } else { + unimplemented!() + } + } RecordLit(m) => visitor.visit_map( serde::de::value::MapDeserializer::new(m.iter().map( |(k, v)| (k.as_ref(), Deserializer(Cow::Borrowed(v))), -- cgit v1.2.3 From a7363042a16364a6dafdd545f4069dcf04a4197e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 27 Aug 2019 23:18:13 +0200 Subject: Rename SubExpr to Expr, and Expr to RawExpr For clarity, and consistency with Value --- serde_dhall/src/lib.rs | 4 ++-- serde_dhall/src/serde.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index ce3468f..9fce42d 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -124,7 +124,7 @@ pub use value::Value; // A Dhall value. pub mod value { - use dhall::phase::{NormalizedSubExpr, Parsed, Typed}; + use dhall::phase::{NormalizedExpr, Parsed, Typed}; use dhall_syntax::Builtin; use super::de::{Error, Result}; @@ -148,7 +148,7 @@ pub mod value { }; Ok(Value(typed)) } - pub(crate) fn to_expr(&self) -> NormalizedSubExpr { + pub(crate) fn to_expr(&self) -> NormalizedExpr { self.0.to_expr() } pub(crate) fn as_typed(&self) -> &Typed { diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 94b7e6c..26708c1 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use dhall::phase::NormalizedSubExpr; +use dhall::phase::NormalizedExpr; use dhall_syntax::ExprF; use crate::de::{Deserialize, Error, Result}; @@ -15,7 +15,7 @@ where } } -struct Deserializer<'a>(Cow<'a, NormalizedSubExpr>); +struct Deserializer<'a>(Cow<'a, NormalizedExpr>); impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { type Deserializer = Deserializer<'a>; -- cgit v1.2.3 From 55c127e70eb484df486a45b25bcf03479eebda10 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 28 Aug 2019 13:49:27 +0200 Subject: Cleanup conversion of `Value` to `Expr` --- serde_dhall/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'serde_dhall') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 9fce42d..3d07539 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -149,7 +149,7 @@ pub mod value { Ok(Value(typed)) } pub(crate) fn to_expr(&self) -> NormalizedExpr { - self.0.to_expr() + self.0.normalize_to_expr() } pub(crate) fn as_typed(&self) -> &Typed { &self.0 -- cgit v1.2.3