From 84796fd247eb1a13fcd092a7cd7ec2d587b261bd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 8 Mar 2020 17:11:34 +0000 Subject: Add SimpleValue type to facilitate deserialization --- serde_dhall/tests/de.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'serde_dhall/tests') diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 74912dd..4042611 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -51,6 +51,8 @@ fn test_de_typed() { Y(i64), } assert_eq!(parse::("< X | Y: Integer >.X"), Baz::X); + + assert!(from_str_auto_type::("< X | Y: Integer >.Y").is_err()); } #[test] -- cgit v1.3.1 From 4e11e882b7d064e9ddf997f9a465206cf6e471aa Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 8 Mar 2020 17:36:51 +0000 Subject: Split serde_dhall::Value to separate values from types --- README.md | 4 ++ dhall_proc_macros/src/derive.rs | 6 +-- serde_dhall/src/lib.rs | 86 +++++++++++++++++++++++++++++------------ serde_dhall/src/static_type.rs | 26 ++++++------- serde_dhall/tests/traits.rs | 4 +- test.dhall | 4 ++ 6 files changed, 88 insertions(+), 42 deletions(-) create mode 100644 test.dhall (limited to 'serde_dhall/tests') diff --git a/README.md b/README.md index ffd55ef..1bcf558 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,10 @@ same name as the corresponding test. ## Changelog +#### [???] + +- Breaking change: use `serde_dhall::Type` type for type-checking instead of `serde_dhall::Value` + #### [0.4.0] - `dhall` now uses the stable Rust toolchain ! diff --git a/dhall_proc_macros/src/derive.rs b/dhall_proc_macros/src/derive.rs index 48626a0..3a4f1aa 100644 --- a/dhall_proc_macros/src/derive.rs +++ b/dhall_proc_macros/src/derive.rs @@ -52,7 +52,7 @@ fn derive_for_struct( let ty = static_type(ty); quote!( (#name.to_owned(), #ty) ) }); - Ok(quote! { ::serde_dhall::value::Value::make_record_type( + Ok(quote! { ::serde_dhall::Type::make_record_type( vec![ #(#entries),* ].into_iter() ) }) } @@ -89,7 +89,7 @@ fn derive_for_enum( }) .collect::>()?; - Ok(quote! { ::serde_dhall::value::Value::make_union_type( + Ok(quote! { ::serde_dhall::Type::make_union_type( vec![ #(#entries),* ].into_iter() ) }) } @@ -165,7 +165,7 @@ pub fn derive_static_type_inner( for #ident #ty_generics #where_clause { fn static_type() -> - ::serde_dhall::value::Value { + ::serde_dhall::Type { #(#assertions)* #get_type } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 55e098c..5f386e3 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -106,17 +106,17 @@ //! There are two ways to typecheck a Dhall value: you can provide the type as Dhall text or you //! can let Rust infer it for you. //! -//! To provide a type written in Dhall, first parse it into a [`serde_dhall::Value`][Value], then +//! To provide a type written in Dhall, first parse it into a [`serde_dhall::Type`][Type], then //! pass it to [`from_str_check_type`][from_str_check_type]. //! //! ```rust //! # fn main() -> serde_dhall::de::Result<()> { -//! use serde_dhall::Value; +//! use serde_dhall::Type; //! use std::collections::HashMap; //! //! // Parse a Dhall type //! let point_type_str = "{ x: Natural, y: Natural }"; -//! let point_type: Value = serde_dhall::from_str(point_type_str)?; +//! let point_type: Type = serde_dhall::from_str(point_type_str)?; //! //! // Some Dhall data //! let point_data = "{ x = 1, y = 1 + 1 }"; @@ -176,30 +176,29 @@ pub use de::{from_str, from_str_auto_type, from_str_check_type}; pub use dhall_proc_macros::StaticType; pub use static_type::StaticType; #[doc(inline)] +pub use ty::Type; +#[doc(inline)] pub use value::Value; // A Dhall value. #[doc(hidden)] pub mod value { - use dhall::syntax::Builtin; use dhall::{Normalized, NormalizedExpr, Parsed, SimpleValue}; use super::de::Error; + use super::Type; /// A Dhall value #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Value(Normalized); + pub struct Value(pub(crate) Normalized); impl Value { - pub fn from_str( - s: &str, - ty: Option<&Value>, - ) -> super::de::Result { + pub fn from_str(s: &str, ty: Option<&Type>) -> super::de::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<&Value>, + ty: Option<&Type>, ) -> dhall::error::Result { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { @@ -213,41 +212,79 @@ pub mod value { ) -> Result { self.0.to_simple_value() } + } + + impl super::de::sealed::Sealed for Value {} + + impl super::de::Deserialize for Value { + fn from_dhall(v: &Value) -> super::de::Result { + Ok(v.clone()) + } + } +} + +// A Dhall type. +#[doc(hidden)] +pub mod ty { + use dhall::syntax::Builtin; + use dhall::{Normalized, Parsed}; + + use super::de::Error; + + /// A Dhall value + #[derive(Debug, Clone, PartialEq, Eq)] + pub struct Type(Normalized); + + impl Type { + pub fn from_str(s: &str, ty: Option<&Type>) -> super::de::Result { + Type::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()?, + Some(t) => resolved.typecheck_with(t.as_normalized())?, + }; + Ok(Type(typed.normalize())) + } pub(crate) fn as_normalized(&self) -> &Normalized { &self.0 } pub(crate) fn make_builtin_type(b: Builtin) -> Self { - Value(Normalized::make_builtin_type(b)) + Type(Normalized::make_builtin_type(b)) } - pub(crate) fn make_optional_type(t: Value) -> Self { - Value(Normalized::make_optional_type(t.0)) + pub(crate) fn make_optional_type(t: Type) -> Self { + Type(Normalized::make_optional_type(t.0)) } - pub(crate) fn make_list_type(t: Value) -> Self { - Value(Normalized::make_list_type(t.0)) + pub(crate) fn make_list_type(t: Type) -> Self { + Type(Normalized::make_list_type(t.0)) } // Made public for the StaticType derive macro #[doc(hidden)] pub fn make_record_type( - kts: impl Iterator, + kts: impl Iterator, ) -> Self { - Value(Normalized::make_record_type(kts.map(|(k, t)| (k, t.0)))) + Type(Normalized::make_record_type(kts.map(|(k, t)| (k, t.0)))) } #[doc(hidden)] pub fn make_union_type( - kts: impl Iterator)>, + kts: impl Iterator)>, ) -> Self { - Value(Normalized::make_union_type( + Type(Normalized::make_union_type( kts.map(|(k, t)| (k, t.map(|t| t.0))), )) } } - impl super::de::sealed::Sealed for Value {} + impl super::de::sealed::Sealed for Type {} - impl super::de::Deserialize for Value { - fn from_dhall(v: &Value) -> super::de::Result { - Ok(v.clone()) + impl super::de::Deserialize for Type { + fn from_dhall(v: &super::Value) -> super::de::Result { + Ok(Type(v.0.clone())) } } } @@ -255,6 +292,7 @@ pub mod value { /// Deserialize Dhall data to a Rust data structure. pub mod de { use super::StaticType; + use super::Type; use super::Value; pub use error::{Error, Result}; @@ -324,7 +362,7 @@ pub mod de { /// /// 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 + pub fn from_str_check_type(s: &str, ty: &Type) -> Result where T: Deserialize, { diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 1eb9150..921b296 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,6 +1,6 @@ use dhall::syntax::Builtin; -use crate::Value; +use crate::Type; /// A Rust type that can be represented as a Dhall type. /// @@ -14,14 +14,14 @@ use crate::Value; /// [StaticType] because each different value would /// have a different Dhall record type. pub trait StaticType { - fn static_type() -> Value; + fn static_type() -> Type; } macro_rules! derive_builtin { ($ty:ty, $builtin:ident) => { impl StaticType for $ty { - fn static_type() -> Value { - Value::make_builtin_type(Builtin::$builtin) + fn static_type() -> Type { + Type::make_builtin_type(Builtin::$builtin) } } }; @@ -43,8 +43,8 @@ where A: StaticType, B: StaticType, { - fn static_type() -> Value { - Value::make_record_type( + fn static_type() -> Type { + Type::make_record_type( vec![ ("_1".to_owned(), A::static_type()), ("_2".to_owned(), B::static_type()), @@ -59,8 +59,8 @@ where T: StaticType, E: StaticType, { - fn static_type() -> Value { - Value::make_union_type( + fn static_type() -> Type { + Type::make_union_type( vec![ ("Ok".to_owned(), Some(T::static_type())), ("Err".to_owned(), Some(E::static_type())), @@ -74,8 +74,8 @@ impl StaticType for Option where T: StaticType, { - fn static_type() -> Value { - Value::make_optional_type(T::static_type()) + fn static_type() -> Type { + Type::make_optional_type(T::static_type()) } } @@ -83,8 +83,8 @@ impl StaticType for Vec where T: StaticType, { - fn static_type() -> Value { - Value::make_list_type(T::static_type()) + fn static_type() -> Type { + Type::make_list_type(T::static_type()) } } @@ -92,7 +92,7 @@ impl<'a, T> StaticType for &'a T where T: StaticType, { - fn static_type() -> Value { + fn static_type() -> Type { T::static_type() } } diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index 15a91ed..b2fe6e5 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,8 +1,8 @@ -use serde_dhall::{from_str, StaticType, Value}; +use serde_dhall::{from_str, StaticType, Type}; #[test] fn test_static_type() { - fn parse(s: &str) -> Value { + fn parse(s: &str) -> Type { from_str(s).unwrap() } diff --git a/test.dhall b/test.dhall new file mode 100644 index 0000000..641c219 --- /dev/null +++ b/test.dhall @@ -0,0 +1,4 @@ +let Prelude = + https://prelude.dhall-lang.org/package.dhall sha256:c1b3fc613aabfb64a9e17f6c0d70fe82016a030beedd79851730993e9083fde2 + +in Prelude -- cgit v1.3.1 From 1a0929b52af57d5963dd9da9e5cf85ffbed3a8f7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 13 Mar 2020 20:53:23 +0000 Subject: Reorganize serde modules --- dhall_proc_macros/src/derive.rs | 6 +- serde_dhall/src/error.rs | 30 +++++ serde_dhall/src/lib.rs | 264 ++++++++++------------------------------ serde_dhall/src/serde.rs | 4 +- serde_dhall/src/simple.rs | 81 ++++++++++++ serde_dhall/tests/de.rs | 4 +- serde_dhall/tests/traits.rs | 2 +- 7 files changed, 182 insertions(+), 209 deletions(-) create mode 100644 serde_dhall/src/error.rs create mode 100644 serde_dhall/src/simple.rs (limited to 'serde_dhall/tests') diff --git a/dhall_proc_macros/src/derive.rs b/dhall_proc_macros/src/derive.rs index 3a4f1aa..4885b49 100644 --- a/dhall_proc_macros/src/derive.rs +++ b/dhall_proc_macros/src/derive.rs @@ -52,7 +52,7 @@ fn derive_for_struct( let ty = static_type(ty); quote!( (#name.to_owned(), #ty) ) }); - Ok(quote! { ::serde_dhall::Type::make_record_type( + Ok(quote! { ::serde_dhall::simple::Type::make_record_type( vec![ #(#entries),* ].into_iter() ) }) } @@ -89,7 +89,7 @@ fn derive_for_enum( }) .collect::>()?; - Ok(quote! { ::serde_dhall::Type::make_union_type( + Ok(quote! { ::serde_dhall::simple::Type::make_union_type( vec![ #(#entries),* ].into_iter() ) }) } @@ -165,7 +165,7 @@ pub fn derive_static_type_inner( for #ident #ty_generics #where_clause { fn static_type() -> - ::serde_dhall::Type { + ::serde_dhall::simple::Type { #(#assertions)* #get_type } diff --git a/serde_dhall/src/error.rs b/serde_dhall/src/error.rs new file mode 100644 index 0000000..91a0b94 --- /dev/null +++ b/serde_dhall/src/error.rs @@ -0,0 +1,30 @@ +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()) + } +} diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 134528c..15f45ce 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -22,7 +22,7 @@ //! This could mean a common Rust type like `HashMap`: //! //! ```rust -//! # fn main() -> serde_dhall::de::Result<()> { +//! # fn main() -> serde_dhall::Result<()> { //! use std::collections::HashMap; //! //! // Some Dhall data @@ -43,7 +43,7 @@ //! or a custom datatype, using serde's `derive` mechanism: //! //! ```rust -//! # fn main() -> serde_dhall::de::Result<()> { +//! # fn main() -> serde_dhall::Result<()> { //! use serde::Deserialize; //! //! #[derive(Debug, Deserialize)] @@ -110,8 +110,8 @@ //! pass it to [`from_str_check_type`][from_str_check_type]. //! //! ```rust -//! # fn main() -> serde_dhall::de::Result<()> { -//! use serde_dhall::Type; +//! # fn main() -> serde_dhall::Result<()> { +//! use serde_dhall::simple::Type; //! use std::collections::HashMap; //! //! // Parse a Dhall type @@ -138,7 +138,7 @@ //! You can also let Rust infer the appropriate Dhall type, using the [StaticType] trait. //! //! ```rust -//! # fn main() -> serde_dhall::de::Result<()> { +//! # fn main() -> serde_dhall::Result<()> { //! use serde::Deserialize; //! use serde_dhall::StaticType; //! @@ -167,215 +167,77 @@ //! [serde]: https://docs.serde.rs/serde/ //! [serde::Deserialize]: https://docs.serde.rs/serde/trait.Deserialize.html +mod error; mod serde; +pub mod simple; 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 error::{Error, Result}; pub use static_type::StaticType; -#[doc(inline)] -pub use ty::Type; -#[doc(inline)] -pub use value::Value; -// A Dhall value. -#[doc(hidden)] -pub mod value { - use dhall::SimpleValue; - - use super::de::Error; - - /// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. - #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Value(SimpleValue); +use simple::Type; - impl Value { - pub fn into_simple_value(self) -> SimpleValue { - self.0 - } - } - - impl super::de::sealed::Sealed for Value {} - - impl super::de::Deserialize for Value { - fn from_dhall(v: &dhall::Value) -> super::de::Result { - let sval = v.to_simple_value().ok_or_else(|| { - Error::Deserialize(format!( - "this cannot be deserialized into a simple type: {}", - v - )) - })?; - Ok(Value(sval)) - } - } +pub(crate) mod sealed { + pub trait Sealed {} } -// A Dhall type. -#[doc(hidden)] -pub mod ty { - use dhall::{STyKind, SimpleType}; - - use super::de::Error; - - /// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. - #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Type(SimpleType); - - impl Type { - pub fn into_simple_type(self) -> SimpleType { - self.0 - } - pub fn to_dhall_value(&self) -> dhall::Value { - self.0.to_value() - } - - pub(crate) fn from_simple_type(ty: SimpleType) -> Self { - Type(ty) - } - pub(crate) fn from_stykind(k: STyKind) -> Self { - Type(SimpleType::new(k)) - } - pub(crate) fn make_optional_type(t: Type) -> Self { - Type::from_stykind(STyKind::Optional(t.0)) - } - pub(crate) fn make_list_type(t: Type) -> Self { - Type::from_stykind(STyKind::List(t.0)) - } - // Made public for the StaticType derive macro - #[doc(hidden)] - pub fn make_record_type( - kts: impl Iterator, - ) -> Self { - Type::from_stykind(STyKind::Record( - kts.map(|(k, t)| (k, t.0)).collect(), - )) - } - #[doc(hidden)] - pub fn make_union_type( - kts: impl Iterator)>, - ) -> Self { - Type::from_stykind(STyKind::Union( - kts.map(|(k, t)| (k, t.map(|t| t.0))).collect(), - )) - } - } - - impl super::de::sealed::Sealed for Type {} - - impl super::de::Deserialize for Type { - fn from_dhall(v: &dhall::Value) -> super::de::Result { - let sty = v.to_simple_type().ok_or_else(|| { - Error::Deserialize(format!( - "this cannot be deserialized into a simple type: {}", - v - )) - })?; - Ok(Type(sty)) - } - } +/// 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. +pub trait Deserialize: sealed::Sealed + Sized { + /// See [serde_dhall::from_str][crate::from_str] + fn from_dhall(v: &dhall::Value) -> Result; } -/// Deserialize Dhall data to a Rust data structure. -pub mod de { - use super::StaticType; - use super::Type; - pub use error::{Error, Result}; - - 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()) - } - } - } - - pub(crate) mod sealed { - pub trait Sealed {} - } - - /// 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. - pub trait Deserialize: sealed::Sealed + Sized { - /// See [serde_dhall::from_str][crate::from_str] - fn from_dhall(v: &dhall::Value) -> Result; - } - - fn from_str_with_annot(s: &str, ty: Option<&Type>) -> Result - where - T: Deserialize, - { - let ty = ty.map(|ty| ty.to_dhall_value()); - let val = dhall::Value::from_str_with_annot(s, ty.as_ref()) - .map_err(Error::Dhall)?; - T::from_dhall(&val) - } +fn from_str_with_annot(s: &str, ty: Option<&Type>) -> Result +where + T: Deserialize, +{ + let ty = ty.map(|ty| ty.to_dhall_value()); + let val = dhall::Value::from_str_with_annot(s, ty.as_ref()) + .map_err(Error::Dhall)?; + T::from_dhall(&val) +} - /// 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, - { - from_str_with_annot(s, None) - } +/// 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, +{ + from_str_with_annot(s, None) +} - /// Deserialize an instance of type `T` from a string of Dhall text, - /// additionally checking that it matches the supplied type. - /// - /// 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: &Type) -> Result - where - T: Deserialize, - { - from_str_with_annot(s, Some(ty)) - } +/// Deserialize an instance of type `T` from a string of Dhall text, +/// additionally checking that it matches the supplied type. +/// +/// 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: &Type) -> Result +where + T: Deserialize, +{ + from_str_with_annot(s, Some(ty)) +} - /// Deserialize an instance of type `T` from a string of Dhall text, - /// additionally checking that it matches the type of `T`. - /// - /// 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_check_type(s, &::static_type()) - } +/// Deserialize an instance of type `T` from a string of Dhall text, +/// additionally checking that it matches the type of `T`. +/// +/// 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_check_type(s, &::static_type()) } diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index e06fb3d..d144abf 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -7,9 +7,9 @@ use serde::de::value::{ use dhall::syntax::NumKind; use dhall::{SValKind, SimpleValue}; -use crate::de::{Deserialize, Error, Result}; +use crate::{Deserialize, Error, Result}; -impl<'a, T> crate::de::sealed::Sealed for T where T: serde::Deserialize<'a> {} +impl<'a, T> crate::sealed::Sealed for T where T: serde::Deserialize<'a> {} struct Deserializer<'a>(Cow<'a, SimpleValue>); diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs new file mode 100644 index 0000000..93364a0 --- /dev/null +++ b/serde_dhall/src/simple.rs @@ -0,0 +1,81 @@ +use super::Error; +use dhall::{STyKind, SimpleType, SimpleValue}; + +/// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Value(SimpleValue); + +impl Value { + pub fn into_simple_value(self) -> SimpleValue { + self.0 + } +} + +/// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Type(SimpleType); + +impl Type { + pub fn into_simple_type(self) -> SimpleType { + self.0 + } + pub fn to_dhall_value(&self) -> dhall::Value { + self.0.to_value() + } + + pub(crate) fn from_simple_type(ty: SimpleType) -> Self { + Type(ty) + } + pub(crate) fn from_stykind(k: STyKind) -> Self { + Type(SimpleType::new(k)) + } + pub(crate) fn make_optional_type(t: Type) -> Self { + Type::from_stykind(STyKind::Optional(t.0)) + } + pub(crate) fn make_list_type(t: Type) -> Self { + Type::from_stykind(STyKind::List(t.0)) + } + // Made public for the StaticType derive macro + #[doc(hidden)] + pub fn make_record_type(kts: impl Iterator) -> Self { + Type::from_stykind(STyKind::Record( + kts.map(|(k, t)| (k, t.0)).collect(), + )) + } + #[doc(hidden)] + pub fn make_union_type( + kts: impl Iterator)>, + ) -> Self { + Type::from_stykind(STyKind::Union( + kts.map(|(k, t)| (k, t.map(|t| t.0))).collect(), + )) + } +} + +impl super::sealed::Sealed for Value {} + +impl super::Deserialize for Value { + fn from_dhall(v: &dhall::Value) -> super::Result { + let sval = v.to_simple_value().ok_or_else(|| { + Error::Deserialize(format!( + "this cannot be deserialized into a simple type: {}", + v + )) + })?; + Ok(Value(sval)) + } +} + +impl super::sealed::Sealed for Type {} + +impl super::Deserialize for Type { + fn from_dhall(v: &dhall::Value) -> super::Result { + let sty = v.to_simple_type().ok_or_else(|| { + Error::Deserialize(format!( + "this cannot be deserialized into a simple type: {}", + v + )) + })?; + Ok(Type(sty)) + } +} diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 4042611..b201e4f 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -3,7 +3,7 @@ use serde_dhall::{from_str, from_str_auto_type, StaticType}; #[test] fn test_de_typed() { - fn parse(s: &str) -> T { + fn parse(s: &str) -> T { from_str_auto_type(s).unwrap() } @@ -57,7 +57,7 @@ fn test_de_typed() { #[test] fn test_de_untyped() { - fn parse(s: &str) -> T { + fn parse(s: &str) -> T { from_str(s).unwrap() } diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index b2fe6e5..f3c6f05 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,4 +1,4 @@ -use serde_dhall::{from_str, StaticType, Type}; +use serde_dhall::{from_str, simple::Type, StaticType}; #[test] fn test_static_type() { -- cgit v1.3.1 From 196491a37a9ab2869ab6d76e1417a85a9e033dd4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 21 Mar 2020 21:56:09 +0000 Subject: Ensure version numbers are kept in sync --- Cargo.lock | 144 +++++++++++++++++++++++++++++ dhall/Cargo.toml | 1 + dhall/tests/version_numbers.rs | 4 + dhall_proc_macros/Cargo.toml | 3 + dhall_proc_macros/tests/version_numbers.rs | 4 + serde_dhall/Cargo.toml | 1 + serde_dhall/tests/version_numbers.rs | 14 +++ 7 files changed, 171 insertions(+) create mode 100644 dhall/tests/version_numbers.rs create mode 100644 dhall_proc_macros/tests/version_numbers.rs create mode 100644 serde_dhall/tests/version_numbers.rs (limited to 'serde_dhall/tests') diff --git a/Cargo.lock b/Cargo.lock index 4b80022..f5cb0cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,14 @@ dependencies = [ "pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "annotate-snippets" version = "0.7.0" @@ -147,6 +155,7 @@ dependencies = [ "serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version-sync 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -158,6 +167,7 @@ dependencies = [ "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "version-sync 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -387,6 +397,16 @@ dependencies = [ "tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.2.0" @@ -639,6 +659,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -772,6 +797,14 @@ dependencies = [ "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "1.0.9" @@ -780,6 +813,24 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pulldown-cmark" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.3" @@ -830,6 +881,22 @@ name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "regex" +version = "1.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "remove_dir_all" version = "0.5.2" @@ -935,6 +1002,11 @@ name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "semver-parser" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.104" @@ -973,6 +1045,7 @@ dependencies = [ "reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version-sync 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1022,6 +1095,16 @@ name = "static_assertions" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "1.0.16" @@ -1045,6 +1128,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.42" @@ -1093,6 +1184,14 @@ dependencies = [ "tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tower-service" version = "0.3.0" @@ -1142,11 +1241,26 @@ dependencies = [ "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "url" version = "2.1.1" @@ -1162,6 +1276,21 @@ name = "vcpkg" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version-sync" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "version_check" version = "0.9.1" @@ -1318,6 +1447,7 @@ dependencies = [ [metadata] "checksum abnf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47feb9fbcef700639ef28e04ca2a87eab8161a01a075ee227b15c90143805462" +"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" "checksum annotate-snippets 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aba2d96b8c8b5e656ad7ffb0d09f57772f10a1db74c8d23fca0ec695b38a4047" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" @@ -1364,6 +1494,7 @@ dependencies = [ "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e7b15203263d1faa615f9337d79c1d37959439dc46c2b4faab33286fadc2a1c5" "checksum hyper-tls 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3adcd308402b9553630734e9c36b77a7e48b3821251ca2493e8cd596763aafaa" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" @@ -1394,6 +1525,7 @@ dependencies = [ "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)" = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" "checksum pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" "checksum pest_consume 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3f016ccda869edc16802ba5feb6c4467038132067fbf914117f851ec6ac5e3a1" @@ -1410,13 +1542,18 @@ dependencies = [ "checksum pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f60c0d9f6fc88ecdd245d90c1920ff76a430ab34303fc778d33b1d0a4c3bf6d3" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum proc-macro-hack 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f918f2b601f93baa836c1c2945faef682ba5b6d4828ecb45eeb7cc3c71b811b4" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum pulldown-cmark 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d1b74cc784b038a9921fd1a48310cc2e238101aa8ae0b94201e2d85121dd68b5" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum reqwest 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b81e49ddec5109a9dcfc5f2a317ff53377c915e9ae9d4f2fb50914b85614e2" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1427,6 +1564,7 @@ dependencies = [ "checksum security-framework-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "06fd2f23e31ef68dd2328cc383bd493142e46107a3a0e24f7d734e3f3b80fe4c" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum semver-parser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b46e1121e8180c12ff69a742aabc4f310542b6ccb69f1691689ac17fdf8618aa" "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45cd6d95391b16cd57e88b68be41d504183b7faae22030c0cc3b3f73dd57b2fd" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" @@ -1436,12 +1574,15 @@ dependencies = [ "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "0fa5e81d6bc4e67fe889d5783bd2a128ab2e0cfa487e0be16b6a8d177b101616" "checksum tokio-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7bde02a3a5291395f59b06ec6945a3077602fac2b07eeeaf0dee2122f3619828" "checksum tokio-util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum typed-arena 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d" @@ -1450,9 +1591,12 @@ dependencies = [ "checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" "checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" +"checksum version-sync 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "844f3d3a2467f15cb999f5af7775f6e108ac546d4f42365832ed4c755404f806" "checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" "checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" diff --git a/dhall/Cargo.toml b/dhall/Cargo.toml index 02ec1e7..bb60d9e 100644 --- a/dhall/Cargo.toml +++ b/dhall/Cargo.toml @@ -26,6 +26,7 @@ url = "2.1" [dev-dependencies] pretty_assertions = "0.6.1" +version-sync = "0.8" [build-dependencies] walkdir = "2" diff --git a/dhall/tests/version_numbers.rs b/dhall/tests/version_numbers.rs new file mode 100644 index 0000000..9f1d04a --- /dev/null +++ b/dhall/tests/version_numbers.rs @@ -0,0 +1,4 @@ +#[test] +fn test_html_root_url() { + version_sync::assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/dhall_proc_macros/Cargo.toml b/dhall_proc_macros/Cargo.toml index 6de2850..48b55e8 100644 --- a/dhall_proc_macros/Cargo.toml +++ b/dhall_proc_macros/Cargo.toml @@ -17,3 +17,6 @@ itertools = "0.9.0" quote = "1.0" proc-macro2 = "1.0" syn = "1.0" + +[dev-dependencies] +version-sync = "0.8" diff --git a/dhall_proc_macros/tests/version_numbers.rs b/dhall_proc_macros/tests/version_numbers.rs new file mode 100644 index 0000000..9f1d04a --- /dev/null +++ b/dhall_proc_macros/tests/version_numbers.rs @@ -0,0 +1,4 @@ +#[test] +fn test_html_root_url() { + version_sync::assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/serde_dhall/Cargo.toml b/serde_dhall/Cargo.toml index 4e3cce7..7fd7b3e 100644 --- a/serde_dhall/Cargo.toml +++ b/serde_dhall/Cargo.toml @@ -18,3 +18,4 @@ url = "2.1" [dev-dependencies] doc-comment = "0.3" +version-sync = "0.8" diff --git a/serde_dhall/tests/version_numbers.rs b/serde_dhall/tests/version_numbers.rs new file mode 100644 index 0000000..97254a9 --- /dev/null +++ b/serde_dhall/tests/version_numbers.rs @@ -0,0 +1,14 @@ +#[test] +fn test_readme_deps() { + version_sync::assert_markdown_deps_updated!("../README.md"); +} + +#[test] +fn test_html_root_url() { + version_sync::assert_html_root_url_updated!("src/lib.rs"); +} + +#[test] +fn test_readme_mentions_version() { + version_sync::assert_contains_regex!("../README.md", "^#### \\[{version}\\]"); +} -- cgit v1.3.1 From 1a98b506055779e1a60558d9c5a56b071b3d61a0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 21:20:58 +0000 Subject: Reorganize API and internals of serde_dhall a bit --- Cargo.lock | 2 +- README.md | 2 +- abnf_to_pest/Cargo.toml | 2 +- dhall/src/semantics/resolve/resolve.rs | 2 +- serde_dhall/src/deserialize.rs | 124 +++++++++++++++++++++++++++++++++ serde_dhall/src/lib.rs | 80 +++++---------------- serde_dhall/src/serde.rs | 111 ----------------------------- serde_dhall/src/shortcuts.rs | 100 ++++++++++++++++++++++++++ serde_dhall/src/simple.rs | 2 +- serde_dhall/src/value.rs | 2 +- serde_dhall/tests/de.rs | 6 +- serde_dhall/tests/version_numbers.rs | 5 +- tests_buffer | 4 ++ 13 files changed, 259 insertions(+), 183 deletions(-) create mode 100644 serde_dhall/src/deserialize.rs delete mode 100644 serde_dhall/src/serde.rs create mode 100644 serde_dhall/src/shortcuts.rs (limited to 'serde_dhall/tests') diff --git a/Cargo.lock b/Cargo.lock index f5cb0cc..e5a25e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ version = "0.2.0" dependencies = [ "abnf 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/README.md b/README.md index 8afcac6..efe4c91 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ same name as the corresponding test. #### [???] - Add `serde_dhall::options` for finer control over Dhall behavior -- Breaking change: use `serde_dhall::simple::Type` type for type-checking instead of `serde_dhall::Value` +- Breaking change: reworked most of the `serde_dhall` api #### [0.4.0] diff --git a/abnf_to_pest/Cargo.toml b/abnf_to_pest/Cargo.toml index 780010e..1567512 100644 --- a/abnf_to_pest/Cargo.toml +++ b/abnf_to_pest/Cargo.toml @@ -14,5 +14,5 @@ doctest = false [dependencies] abnf = "0.6.0" indexmap = "1.0.2" -itertools = "0.8.0" +itertools = "0.9.0" pretty = "0.5.2" diff --git a/dhall/src/semantics/resolve/resolve.rs b/dhall/src/semantics/resolve/resolve.rs index fe3f3a9..7745e0b 100644 --- a/dhall/src/semantics/resolve/resolve.rs +++ b/dhall/src/semantics/resolve/resolve.rs @@ -341,7 +341,7 @@ pub fn skip_resolve_expr(expr: &Expr) -> Result { pub fn skip_resolve(parsed: Parsed) -> Result { let Parsed(expr, _) = parsed; - let resolved =skip_resolve_expr(&expr)?; + let resolved = skip_resolve_expr(&expr)?; Ok(Resolved(resolved)) } diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs new file mode 100644 index 0000000..75a08a9 --- /dev/null +++ b/serde_dhall/src/deserialize.rs @@ -0,0 +1,124 @@ +use serde::de::value::{ + MapAccessDeserializer, MapDeserializer, SeqDeserializer, +}; +use std::borrow::Cow; + +use dhall::syntax::NumKind; + +use crate::simple::{ValKind, Value as SimpleValue}; +use crate::{Error, 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][serde] +/// can deserialize. +/// +/// This trait cannot be implemented manually. +pub trait Deserialize: Sealed + Sized { + #[doc(hidden)] + /// See [serde_dhall::from_str][crate::from_str] + fn from_dhall(v: &Value) -> Result; +} + +impl<'a, T> Sealed for T where T: serde::Deserialize<'a> {} + +struct Deserializer<'a>(Cow<'a, SimpleValue>); + +impl<'a, T> Deserialize for T +where + T: serde::Deserialize<'a>, +{ + fn from_dhall(v: &Value) -> Result { + let sval = v.to_simple_value().ok_or_else(|| { + Error::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(self, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + use std::convert::TryInto; + use NumKind::*; + use ValKind::*; + + let val = |x| Deserializer(Cow::Borrowed(x)); + match self.0.kind() { + 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(self, _: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + let val = |x| Deserializer(Cow::Borrowed(x)); + match self.0.kind() { + // Blindly takes keys in sorted order. + ValKind::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 + } +} diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 4250882..5ee1cf6 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -1,4 +1,6 @@ #![doc(html_root_url = "https://docs.rs/serde_dhall/0.4.0")] +// #![warn(missing_docs)] +// #![warn(missing_doc_code_examples)] //! [Dhall][dhall] is a programmable configuration language that provides a non-repetitive //! alternative to JSON and YAML. //! @@ -107,7 +109,7 @@ //! can let Rust infer it for you. //! //! To provide a type written in Dhall, first parse it into a [`simple::Type`](simple/struct.Type.html), then -//! pass it to [`from_str_check_type`](fn.from_str_check_type.html). +//! pass it to [`from_str_manual_type`](fn.from_str_manual_type.html). //! //! ```rust //! # fn main() -> serde_dhall::Result<()> { @@ -124,7 +126,7 @@ //! // Deserialize the data to a Rust type. This checks that //! // the data matches the provided type. //! let deserialized_map: HashMap = -//! serde_dhall::from_str_check_type(point_data, &point_type)?; +//! serde_dhall::from_str_manual_type(point_data, &point_type)?; //! //! let mut expected_map = HashMap::new(); //! expected_map.insert("x".to_string(), 1); @@ -153,13 +155,13 @@ //! let data = "{ x = 1, y = 1 + 1 }"; //! //! // Convert the Dhall string to a Point. -//! let point: Point = serde_dhall::from_str_auto_type(data)?; +//! let point: Point = serde_dhall::from_str_static_type(data)?; //! assert_eq!(point.x, 1); //! assert_eq!(point.y, 2); //! //! // 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()); +//! assert!(serde_dhall::from_str_static_type::(invalid_data).is_err()); //! # Ok(()) //! # } //! ``` @@ -171,72 +173,26 @@ #[cfg(doctest)] doc_comment::doctest!("../../README.md"); -mod error; /// Finer-grained control over deserializing Dhall pub mod options; -mod serde; -/// Serde-compatible values and their type +/// Serde-compatible Dhall values and their type pub mod simple; -mod static_type; /// Arbitrary Dhall values pub mod value; -pub use crate::simple::{Type as SimpleType, Value as SimpleValue}; +mod deserialize; +mod error; +/// Common patterns made easier +mod shortcuts; +mod static_type; + #[doc(hidden)] pub use dhall_proc_macros::StaticType; + +pub use deserialize::Deserialize; +pub(crate) use deserialize::Sealed; pub use error::{Error, Result}; +pub use shortcuts::{from_str, from_str_manual_type, from_str_static_type}; +pub use simple::{Type as SimpleType, Value as SimpleValue}; pub use static_type::StaticType; pub use value::Value; - -pub(crate) mod sealed { - pub trait Sealed {} -} - -/// 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. -pub trait Deserialize: sealed::Sealed + Sized { - /// 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. -/// -/// 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, -{ - options::from_str(s).parse() -} - -/// Deserialize an instance of type `T` from a string of Dhall text, -/// additionally checking that it matches the supplied type. -/// -/// 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: &simple::Type) -> Result -where - T: Deserialize, -{ - options::from_str(s).type_annotation(ty).parse() -} - -/// Deserialize an instance of type `T` from a string of Dhall text, -/// additionally checking that it matches the type of `T`. -/// -/// 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, -{ - options::from_str(s).static_type_annotation().parse() -} diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs deleted file mode 100644 index 717450a..0000000 --- a/serde_dhall/src/serde.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::borrow::Cow; - -use serde::de::value::{ - MapAccessDeserializer, MapDeserializer, SeqDeserializer, -}; - -use dhall::syntax::NumKind; - -use crate::simple::{ValKind, Value as SimpleValue}; -use crate::{Deserialize, Error, Result, Value}; - -impl<'a, T> crate::sealed::Sealed for T where T: serde::Deserialize<'a> {} - -struct Deserializer<'a>(Cow<'a, SimpleValue>); - -impl<'a, T> Deserialize for T -where - T: serde::Deserialize<'a>, -{ - fn from_dhall(v: &Value) -> Result { - let sval = v.to_simple_value().ok_or_else(|| { - Error::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(self, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - use std::convert::TryInto; - use NumKind::*; - use ValKind::*; - - let val = |x| Deserializer(Cow::Borrowed(x)); - match self.0.kind() { - 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(self, _: usize, visitor: V) -> Result - where - V: serde::de::Visitor<'de>, - { - let val = |x| Deserializer(Cow::Borrowed(x)); - match self.0.kind() { - // Blindly takes keys in sorted order. - ValKind::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 - } -} diff --git a/serde_dhall/src/shortcuts.rs b/serde_dhall/src/shortcuts.rs new file mode 100644 index 0000000..1fb1032 --- /dev/null +++ b/serde_dhall/src/shortcuts.rs @@ -0,0 +1,100 @@ +use crate::error::Result; +use crate::options; +use crate::simple::Type as SimpleType; +use crate::static_type::StaticType; +use crate::Deserialize; + +/// 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 current directory. +/// See [`options`][`options`] for more control over this process. +/// +/// For additional type safety, prefer [`from_str_static_type`][`from_str_static_type`] or +/// [`from_str_manual_type`][`from_str_manual_type`]. +/// +/// +/// # Example +/// +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use serde::Deserialize; +/// +/// #[derive(Debug, Deserialize)] +/// struct Point { +/// x: u64, +/// y: u64, +/// } +/// +/// // Some Dhall data +/// let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; +/// +/// // Convert the Dhall string to a Point. +/// let point: Point = serde_dhall::from_str(data)?; +/// assert_eq!(point.x, 1); +/// assert_eq!(point.y, 2); +/// +/// # Ok(()) +/// # } +/// ``` +/// +/// [`options`]: options/index.html +/// [`from_str_manual_type`]: fn.from_str_manual_type.html +/// [`from_str_static_type`]: fn.from_str_static_type.html +pub fn from_str(s: &str) -> Result +where + T: Deserialize, +{ + options::from_str(s).parse() +} + +/// Deserialize an instance of type `T` from a string of Dhall text, +/// additionally checking that it matches the supplied type. +/// +/// Like [`from_str`], but this additionally checks that +/// the type of the provided expression matches the supplied type. +/// +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use serde_dhall::simple::Type; +/// use std::collections::HashMap; +/// +/// // Parse a Dhall type +/// let point_type_str = "{ x: Natural, y: Natural }"; +/// let point_type: Type = serde_dhall::from_str(point_type_str)?; +/// +/// // Some Dhall data +/// let point_data = "{ x = 1, y = 1 + 1 }"; +/// +/// // Deserialize the data to a Rust type. This checks that +/// // the data matches the provided type. +/// let deserialized_map: HashMap = +/// serde_dhall::from_str_manual_type(point_data, &point_type)?; +/// +/// let mut expected_map = HashMap::new(); +/// expected_map.insert("x".to_string(), 1); +/// expected_map.insert("y".to_string(), 2); +/// +/// assert_eq!(deserialized_map, expected_map); +/// # Ok(()) +/// # } +/// ``` +pub fn from_str_manual_type(s: &str, ty: &SimpleType) -> Result +where + T: Deserialize, +{ + options::from_str(s).type_annotation(ty).parse() +} + +/// Deserialize an instance of type `T` from a string of Dhall text, +/// additionally checking that it matches the type of `T`. +/// +/// 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_static_type(s: &str) -> Result +where + T: Deserialize + StaticType, +{ + options::from_str(s).static_type_annotation().parse() +} diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs index 4cd4ab7..95642bd 100644 --- a/serde_dhall/src/simple.rs +++ b/serde_dhall/src/simple.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; -use crate::{sealed::Sealed, Deserialize, Error, Result}; +use crate::{Deserialize, Error, Result, Sealed}; /// A simple value of the kind that can be encoded/decoded with serde #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index d4ded90..a119028 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -2,7 +2,7 @@ use dhall::semantics::{Hir, Nir}; use dhall::syntax::Expr; use crate::simple::{Type as SimpleType, Value as SimpleValue}; -use crate::{sealed::Sealed, Deserialize, Error}; +use crate::{Deserialize, Error, Sealed}; /// An arbitrary Dhall value. #[derive(Debug, Clone)] diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index b201e4f..f28b265 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -1,10 +1,10 @@ use serde::Deserialize; -use serde_dhall::{from_str, from_str_auto_type, StaticType}; +use serde_dhall::{from_str, from_str_static_type, StaticType}; #[test] fn test_de_typed() { fn parse(s: &str) -> T { - from_str_auto_type(s).unwrap() + from_str_static_type(s).unwrap() } assert_eq!(parse::("True"), true); @@ -52,7 +52,7 @@ fn test_de_typed() { } assert_eq!(parse::("< X | Y: Integer >.X"), Baz::X); - assert!(from_str_auto_type::("< X | Y: Integer >.Y").is_err()); + assert!(from_str_static_type::("< X | Y: Integer >.Y").is_err()); } #[test] diff --git a/serde_dhall/tests/version_numbers.rs b/serde_dhall/tests/version_numbers.rs index 97254a9..8307e47 100644 --- a/serde_dhall/tests/version_numbers.rs +++ b/serde_dhall/tests/version_numbers.rs @@ -10,5 +10,8 @@ fn test_html_root_url() { #[test] fn test_readme_mentions_version() { - version_sync::assert_contains_regex!("../README.md", "^#### \\[{version}\\]"); + version_sync::assert_contains_regex!( + "../README.md", + "^#### \\[{version}\\]" + ); } diff --git a/tests_buffer b/tests_buffer index 74e76bc..d07ddbd 100644 --- a/tests_buffer +++ b/tests_buffer @@ -7,6 +7,10 @@ x.({ a : Bool, b }) x.({ a }) x.{ a : Bool } s/QuotedVariable/VariableQuoted/ +From https://github.com/dhall-lang/dhall-lang/issues/280 : + "${ not_really_an_expression ;-) }" + ''${ not_an_expression ;-) }'' + {- {- -} 1 import: failure/ -- cgit v1.3.1 From a70922c6c6beb58a45da80f15576b54fb915ec28 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 22:11:00 +0000 Subject: Rework SimpleType --- dhall_proc_macros/src/derive.rs | 10 +-- serde_dhall/src/lib.rs | 12 ++-- serde_dhall/src/options.rs | 5 +- serde_dhall/src/shortcuts.rs | 10 +-- serde_dhall/src/simple.rs | 145 +++++++++++++++++++++++++--------------- serde_dhall/src/static_type.rs | 26 +++---- serde_dhall/src/value.rs | 2 +- serde_dhall/tests/traits.rs | 4 +- 8 files changed, 125 insertions(+), 89 deletions(-) (limited to 'serde_dhall/tests') diff --git a/dhall_proc_macros/src/derive.rs b/dhall_proc_macros/src/derive.rs index f7edf3a..e484ec6 100644 --- a/dhall_proc_macros/src/derive.rs +++ b/dhall_proc_macros/src/derive.rs @@ -53,9 +53,9 @@ fn derive_for_struct( quote!( (#name.to_owned(), #ty) ) }); Ok(quote! { - ::serde_dhall::simple::TyKind::Record( + ::serde_dhall::SimpleType::Record( vec![ #(#entries),* ].into_iter().collect() - ).into() + ) }) } @@ -92,9 +92,9 @@ fn derive_for_enum( .collect::>()?; Ok(quote! { - ::serde_dhall::simple::TyKind::Union( + ::serde_dhall::SimpleType::Union( vec![ #(#entries),* ].into_iter().collect() - ).into() + ) }) } @@ -168,7 +168,7 @@ pub fn derive_static_type_inner( impl #impl_generics ::serde_dhall::StaticType for #ident #ty_generics #where_clause { - fn static_type() -> ::serde_dhall::simple::Type { + fn static_type() -> ::serde_dhall::SimpleType { #(#assertions)* #get_type } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 19d3f7e..8780682 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -107,17 +107,17 @@ //! There are two ways to typecheck a Dhall value: you can provide the type as Dhall text or you //! can let Rust infer it for you. //! -//! To provide a type written in Dhall, first parse it into a [`simple::Type`](simple/struct.Type.html), then +//! To provide a type written in Dhall, first parse it into a [`SimpleType`](enum.SimpleType.html), then //! pass it to [`from_str_manual_type`](fn.from_str_manual_type.html). //! //! ```rust //! # fn main() -> serde_dhall::Result<()> { -//! use serde_dhall::simple::Type; +//! use serde_dhall::SimpleType; //! use std::collections::HashMap; //! //! // Parse a Dhall type //! let point_type_str = "{ x: Natural, y: Natural }"; -//! let point_type: Type = serde_dhall::from_str(point_type_str)?; +//! let point_type: SimpleType = serde_dhall::from_str(point_type_str)?; //! //! // Some Dhall data //! let point_data = "{ x = 1, y = 1 + 1 }"; @@ -174,8 +174,6 @@ doc_comment::doctest!("../../README.md"); /// Finer-grained control over deserializing Dhall values pub mod options; -/// Serde-compatible Dhall types -pub mod simple; /// Arbitrary Dhall values pub mod value; @@ -183,6 +181,8 @@ mod deserialize; mod error; /// Common patterns made easier mod shortcuts; +/// Serde-compatible Dhall types +mod simple; mod static_type; #[doc(hidden)] @@ -192,6 +192,6 @@ pub use deserialize::Deserialize; pub(crate) use deserialize::Sealed; pub use error::{Error, Result}; pub use shortcuts::{from_str, from_str_manual_type, from_str_static_type}; -pub use simple::{Type as SimpleType}; +pub use simple::SimpleType; pub use static_type::StaticType; pub use value::Value; diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index 19b8587..0072393 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use dhall::Parsed; -use crate::simple::Type as SimpleType; +use crate::SimpleType; use crate::{Deserialize, Error, Result, StaticType, Value}; #[derive(Debug, Clone)] @@ -94,7 +94,8 @@ impl<'a, T> Options<'a, T> { // } // self // } - // /// TODO + // + /// TODO pub fn type_annotation(&mut self, ty: &SimpleType) -> &mut Self { self.annot = Some(ty.clone()); self diff --git a/serde_dhall/src/shortcuts.rs b/serde_dhall/src/shortcuts.rs index ddb738c..d88b9ac 100644 --- a/serde_dhall/src/shortcuts.rs +++ b/serde_dhall/src/shortcuts.rs @@ -1,8 +1,4 @@ -use crate::error::Result; -use crate::options; -use crate::simple::Type as SimpleType; -use crate::static_type::StaticType; -use crate::Deserialize; +use crate::{options, Deserialize, Result, SimpleType, StaticType}; /// Deserialize an instance of type `T` from a string of Dhall text. /// @@ -56,12 +52,12 @@ where /// /// ```rust /// # fn main() -> serde_dhall::Result<()> { -/// use serde_dhall::simple::Type; +/// use serde_dhall::SimpleType; /// use std::collections::HashMap; /// /// // Parse a Dhall type /// let point_type_str = "{ x: Natural, y: Natural }"; -/// let point_type: Type = serde_dhall::from_str(point_type_str)?; +/// let point_type: SimpleType = serde_dhall::from_str(point_type_str)?; /// /// // Some Dhall data /// let point_data = "{ x = 1, y = 1 + 1 }"; diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs index 6f3dc93..fc640b6 100644 --- a/serde_dhall/src/simple.rs +++ b/serde_dhall/src/simple.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; @@ -13,33 +13,82 @@ pub(crate) struct Value { #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum ValKind { - // TODO: redefine NumKind locally Num(NumKind), Text(String), Optional(Option), List(Vec), - // TODO: HashMap ? Record(BTreeMap), Union(String, Option), } -/// The type of a value that can be decoded by Serde. For example, `{ x: Bool, y: List Natural }`. +/// The type of a value that can be decoded by Serde, like `{ x: Bool, y: List Natural }`. +/// +/// A `SimpleType` is used when deserializing values to ensure they are of the expected type. +/// Rather than letting `serde` handle potential type mismatches, this uses the type-checking +/// capabilities of Dhall to catch errors early and cleanly indicate in the user's code where the +/// mismatch happened. +/// +/// You would typically not manipulate `SimpleType`s by hand but rather let Rust infer it for your +/// datatype using the [`StaticType`][TODO] trait, and methods that require it like +/// [`from_file_static_type`][TODO] and [`Options::static_type_annotation`][TODO]. If you need to supply a +/// `SimpleType` manually however, you can deserialize it like any other Dhall value using the +/// functions provided by this crate. +/// +/// # Examples +/// +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use std::collections::HashMap; +/// use serde_dhall::SimpleType; +/// +/// let ty: SimpleType = +/// serde_dhall::from_str("{ x: Natural, y: Natural }")?; +/// +/// let mut map = HashMap::new(); +/// map.insert("x".to_string(), SimpleType::Natural); +/// map.insert("y".to_string(), SimpleType::Natural); +/// assert_eq!(ty, SimpleType::Record(map)); +/// # Ok(()) +/// # } +/// ``` +/// +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use serde_dhall::{SimpleType, StaticType}; +/// +/// #[derive(StaticType)] +/// struct Foo { +/// x: bool, +/// y: Vec, +/// } +/// +/// let ty: SimpleType = +/// serde_dhall::from_str("{ x: Bool, y: List Natural }")?; +/// +/// assert_eq!(ty, Foo::static_type()); +/// # Ok(()) +/// # } +/// ``` #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Type { - kind: Box, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum TyKind { +pub enum SimpleType { + /// Corresponds to the Dhall type `Bool` Bool, + /// Corresponds to the Dhall type `Natural` Natural, + /// Corresponds to the Dhall type `Integer` Integer, + /// Corresponds to the Dhall type `Double` Double, + /// Corresponds to the Dhall type `Text` Text, - Optional(Type), - List(Type), - Record(BTreeMap), - Union(BTreeMap>), + /// Corresponds to the Dhall type `Optional T` + Optional(Box), + /// Corresponds to the Dhall type `List T` + List(Box), + /// Corresponds to the Dhall type `{ x : T, y : U }` + Record(HashMap), + /// Corresponds to the Dhall type `< x : T | y : U >` + Union(HashMap>), } impl Value { @@ -87,30 +136,29 @@ impl Value { } } -impl Type { - pub fn new(kind: TyKind) -> Self { - Type { - kind: Box::new(kind), - } - } +impl SimpleType { pub(crate) fn from_nir(nir: &Nir) -> Option { - Some(Type::new(match nir.kind() { + Some(match nir.kind() { NirKind::BuiltinType(b) => match b { - Builtin::Bool => TyKind::Bool, - Builtin::Natural => TyKind::Natural, - Builtin::Integer => TyKind::Integer, - Builtin::Double => TyKind::Double, - Builtin::Text => TyKind::Text, + Builtin::Bool => SimpleType::Bool, + Builtin::Natural => SimpleType::Natural, + Builtin::Integer => SimpleType::Integer, + Builtin::Double => SimpleType::Double, + Builtin::Text => SimpleType::Text, _ => unreachable!(), }, - NirKind::OptionalType(t) => TyKind::Optional(Self::from_nir(t)?), - NirKind::ListType(t) => TyKind::List(Self::from_nir(t)?), - NirKind::RecordType(kts) => TyKind::Record( + NirKind::OptionalType(t) => { + SimpleType::Optional(Box::new(Self::from_nir(t)?)) + } + NirKind::ListType(t) => { + SimpleType::List(Box::new(Self::from_nir(t)?)) + } + NirKind::RecordType(kts) => SimpleType::Record( kts.iter() .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) .collect::>()?, ), - NirKind::UnionType(kts) => TyKind::Union( + NirKind::UnionType(kts) => SimpleType::Union( kts.iter() .map(|(k, v)| { Some(( @@ -123,13 +171,10 @@ impl Type { .collect::>()?, ), _ => return None, - })) + }) } - pub fn kind(&self) -> &TyKind { - self.kind.as_ref() - } - pub fn to_value(&self) -> crate::value::Value { + pub(crate) fn to_value(&self) -> crate::value::Value { crate::value::Value { hir: self.to_hir(), as_simple_val: None, @@ -138,25 +183,25 @@ impl Type { } pub(crate) fn to_hir(&self) -> Hir { let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); - hir(match self.kind() { - TyKind::Bool => ExprKind::Builtin(Builtin::Bool), - TyKind::Natural => ExprKind::Builtin(Builtin::Natural), - TyKind::Integer => ExprKind::Builtin(Builtin::Integer), - TyKind::Double => ExprKind::Builtin(Builtin::Double), - TyKind::Text => ExprKind::Builtin(Builtin::Text), - TyKind::Optional(t) => ExprKind::App( + hir(match self { + SimpleType::Bool => ExprKind::Builtin(Builtin::Bool), + SimpleType::Natural => ExprKind::Builtin(Builtin::Natural), + SimpleType::Integer => ExprKind::Builtin(Builtin::Integer), + SimpleType::Double => ExprKind::Builtin(Builtin::Double), + SimpleType::Text => ExprKind::Builtin(Builtin::Text), + SimpleType::Optional(t) => ExprKind::App( hir(ExprKind::Builtin(Builtin::Optional)), t.to_hir(), ), - TyKind::List(t) => { + SimpleType::List(t) => { ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) } - TyKind::Record(kts) => ExprKind::RecordType( + SimpleType::Record(kts) => ExprKind::RecordType( kts.into_iter() .map(|(k, t)| (k.as_str().into(), t.to_hir())) .collect(), ), - TyKind::Union(kts) => ExprKind::UnionType( + SimpleType::Union(kts) => ExprKind::UnionType( kts.into_iter() .map(|(k, t)| { (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) @@ -180,9 +225,9 @@ impl Deserialize for Value { } } -impl Sealed for Type {} +impl Sealed for SimpleType {} -impl Deserialize for Type { +impl Deserialize for SimpleType { fn from_dhall(v: &crate::value::Value) -> Result { v.to_simple_type().ok_or_else(|| { Error::Deserialize(format!( @@ -192,9 +237,3 @@ impl Deserialize for Type { }) } } - -impl From for Type { - fn from(x: TyKind) -> Type { - Type::new(x) - } -} diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 3fdff39..ffbc3ad 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,4 +1,4 @@ -use crate::simple::{TyKind, Type}; +use crate::SimpleType; /// A Rust type that can be represented as a Dhall type. /// @@ -13,14 +13,14 @@ use crate::simple::{TyKind, Type}; /// have a different Dhall record type. /// TODO pub trait StaticType { - fn static_type() -> Type; + fn static_type() -> SimpleType; } macro_rules! derive_builtin { ($rust_ty:ty, $dhall_ty:ident) => { impl StaticType for $rust_ty { - fn static_type() -> Type { - Type::new(TyKind::$dhall_ty) + fn static_type() -> SimpleType { + SimpleType::$dhall_ty } } }; @@ -42,8 +42,8 @@ where A: StaticType, B: StaticType, { - fn static_type() -> Type { - TyKind::Record( + fn static_type() -> SimpleType { + SimpleType::Record( vec![ ("_1".to_owned(), A::static_type()), ("_2".to_owned(), B::static_type()), @@ -60,8 +60,8 @@ where T: StaticType, E: StaticType, { - fn static_type() -> Type { - TyKind::Union( + fn static_type() -> SimpleType { + SimpleType::Union( vec![ ("Ok".to_owned(), Some(T::static_type())), ("Err".to_owned(), Some(E::static_type())), @@ -77,8 +77,8 @@ impl StaticType for Option where T: StaticType, { - fn static_type() -> Type { - TyKind::Optional(T::static_type()).into() + fn static_type() -> SimpleType { + SimpleType::Optional(Box::new(T::static_type())).into() } } @@ -86,8 +86,8 @@ impl StaticType for Vec where T: StaticType, { - fn static_type() -> Type { - TyKind::List(T::static_type()).into() + fn static_type() -> SimpleType { + SimpleType::List(Box::new(T::static_type())).into() } } @@ -95,7 +95,7 @@ impl<'a, T> StaticType for &'a T where T: StaticType, { - fn static_type() -> Type { + fn static_type() -> SimpleType { T::static_type() } } diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index 41a96ea..e8aae49 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -1,7 +1,7 @@ use dhall::semantics::{Hir, Nir}; use dhall::syntax::Expr; -use crate::simple::{Type as SimpleType, Value as SimpleValue}; +use crate::simple::{SimpleType, Value as SimpleValue}; use crate::{Deserialize, Error, Sealed}; /// An arbitrary Dhall value. diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index f3c6f05..608e6ed 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -1,8 +1,8 @@ -use serde_dhall::{from_str, simple::Type, StaticType}; +use serde_dhall::{from_str, SimpleType, StaticType}; #[test] fn test_static_type() { - fn parse(s: &str) -> Type { + fn parse(s: &str) -> SimpleType { from_str(s).unwrap() } -- cgit v1.3.1 From 46cb68809cdda92114adb2593b13a43687306786 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 11:38:10 +0100 Subject: Add a test --- serde_dhall/tests/de.rs | 8 ++++++++ test.dhall | 5 +---- tests_buffer | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'serde_dhall/tests') diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index f28b265..653613a 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -85,6 +85,14 @@ fn test_de_untyped() { expected_map ); + #[derive(Debug, PartialEq, Eq, Deserialize)] + struct Foo { + x: u64, + y: Option, + } + // Omit optional field + assert_eq!(parse::("{ x = 1 }"), Foo { x: 1, y: None }); + // https://github.com/Nadrieril/dhall-rust/issues/155 assert!(from_str::("List/length [True, 42]").is_err()); } diff --git a/test.dhall b/test.dhall index 641c219..c91ac54 100644 --- a/test.dhall +++ b/test.dhall @@ -1,4 +1 @@ -let Prelude = - https://prelude.dhall-lang.org/package.dhall sha256:c1b3fc613aabfb64a9e17f6c0d70fe82016a030beedd79851730993e9083fde2 - -in Prelude +{ x = 0 } with x = (1 + 1) diff --git a/tests_buffer b/tests_buffer index d07ddbd..6f5aae5 100644 --- a/tests_buffer +++ b/tests_buffer @@ -11,6 +11,7 @@ From https://github.com/dhall-lang/dhall-lang/issues/280 : "${ not_really_an_expression ;-) }" ''${ not_an_expression ;-) }'' {- {- -} 1 +{ x = 0 } with x = 1 + 1 import: failure/ -- cgit v1.3.1 From 15a0902b50ff6d1b36dbf7a220b6ff42ceefada6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 11:43:22 +0100 Subject: Rename Deserialize trait to FromDhall --- serde_dhall/src/deserialize.rs | 4 ++-- serde_dhall/src/lib.rs | 2 +- serde_dhall/src/options.rs | 4 ++-- serde_dhall/src/shortcuts.rs | 4 ++-- serde_dhall/src/value.rs | 8 ++++---- serde_dhall/tests/de.rs | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) (limited to 'serde_dhall/tests') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index b9b711c..1be68c4 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -36,7 +36,7 @@ pub trait Sealed {} /// ``` /// /// [serde]: https://serde.rs -pub trait Deserialize: Sealed + Sized { +pub trait FromDhall: Sealed + Sized { #[doc(hidden)] fn from_dhall(v: &Value) -> Result; } @@ -45,7 +45,7 @@ impl Sealed for T where T: serde::de::DeserializeOwned {} struct Deserializer<'a>(Cow<'a, SimpleValue>); -impl Deserialize for T +impl FromDhall for T where T: serde::de::DeserializeOwned, { diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 71274b6..9f99adb 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -172,7 +172,7 @@ mod value; #[doc(hidden)] pub use dhall_proc_macros::StaticType; -pub use deserialize::Deserialize; +pub use deserialize::FromDhall; pub(crate) use deserialize::Sealed; pub(crate) use error::ErrorKind; pub use error::{Error, Result}; diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index 237647f..d7a91a2 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use dhall::Parsed; use crate::SimpleType; -use crate::{Deserialize, Error, ErrorKind, Result, StaticType, Value}; +use crate::{FromDhall, Error, ErrorKind, Result, StaticType, Value}; #[derive(Debug, Clone)] enum Source<'a> { @@ -128,7 +128,7 @@ impl<'a, T> Deserializer<'a, T> { /// TODO pub fn parse(&self) -> Result where - T: Deserialize, + T: FromDhall, { let val = self._parse().map_err(ErrorKind::Dhall).map_err(Error)?; T::from_dhall(&val) diff --git a/serde_dhall/src/shortcuts.rs b/serde_dhall/src/shortcuts.rs index cd31402..9c9ce9f 100644 --- a/serde_dhall/src/shortcuts.rs +++ b/serde_dhall/src/shortcuts.rs @@ -1,7 +1,7 @@ use doc_comment::doc_comment; use std::path::Path; -use crate::{options, Deserialize, Result, SimpleType, StaticType}; +use crate::{options, FromDhall, Result, SimpleType, StaticType}; // Avoid copy-pasting documentation @@ -252,7 +252,7 @@ macro_rules! generate_fn { gen_doc!($src, $ty), pub fn $name ($($input_args)*) -> Result where - T: Deserialize $($extra_bounds)*, + T: FromDhall $($extra_bounds)*, { $($create_options)* .parse() } diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index 3543f4d..fee9d73 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap}; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; use dhall::syntax::{Builtin, Expr, ExprKind, NumKind, Span}; -use crate::{Deserialize, Error, ErrorKind, Result, Sealed}; +use crate::{FromDhall, Error, ErrorKind, Result, Sealed}; #[doc(hidden)] /// An arbitrary Dhall value. @@ -246,12 +246,12 @@ impl Sealed for Value {} impl Sealed for SimpleValue {} impl Sealed for SimpleType {} -impl Deserialize for Value { +impl FromDhall for Value { fn from_dhall(v: &Value) -> Result { Ok(v.clone()) } } -impl Deserialize for SimpleValue { +impl FromDhall for SimpleValue { fn from_dhall(v: &Value) -> Result { v.to_simple_value().ok_or_else(|| { Error(ErrorKind::Deserialize(format!( @@ -261,7 +261,7 @@ impl Deserialize for SimpleValue { }) } } -impl Deserialize for SimpleType { +impl FromDhall for SimpleType { fn from_dhall(v: &Value) -> Result { v.to_simple_type().ok_or_else(|| { Error(ErrorKind::Deserialize(format!( diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 653613a..8afba6e 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -1,9 +1,9 @@ use serde::Deserialize; -use serde_dhall::{from_str, from_str_static_type, StaticType}; +use serde_dhall::{from_str, FromDhall, from_str_static_type, StaticType}; #[test] fn test_de_typed() { - fn parse(s: &str) -> T { + fn parse(s: &str) -> T { from_str_static_type(s).unwrap() } @@ -57,7 +57,7 @@ fn test_de_typed() { #[test] fn test_de_untyped() { - fn parse(s: &str) -> T { + fn parse(s: &str) -> T { from_str(s).unwrap() } -- cgit v1.3.1 From 6dab8cb06e52efdb18b9dcf975e0a2d50454d704 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 15:42:45 +0100 Subject: Document Deserializer methods --- serde_dhall/src/options.rs | 213 +++++++++++++++++++++++++++++++++++++++++---- serde_dhall/src/value.rs | 2 +- serde_dhall/tests/de.rs | 2 +- 3 files changed, 199 insertions(+), 18 deletions(-) (limited to 'serde_dhall/tests') diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index d7a91a2..f3797ee 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; use dhall::Parsed; use crate::SimpleType; -use crate::{FromDhall, Error, ErrorKind, Result, StaticType, Value}; +use crate::{Error, ErrorKind, FromDhall, Result, StaticType, Value}; #[derive(Debug, Clone)] enum Source<'a> { @@ -15,12 +15,11 @@ enum Source<'a> { /// Controls how a dhall value is read. /// /// This builder exposes the ability to configure how a value is deserialized and what operations -/// are permitted during evaluation. The functions in the crate root are aliases for -/// commonly used options using this builder. +/// are permitted during evaluation. /// /// Generally speaking, when using `Deserializer`, you'll create it with `from_str` or `from_file`, then /// chain calls to methods to set each option, then call `parse`. This will give you a -/// `serde_dhall::Result` where `T` a deserializable type of your choice. +/// `serde_dhall::Result` where `T` is a deserializable type of your choice. /// /// # Examples /// @@ -48,8 +47,7 @@ enum Source<'a> { /// # Ok(()) /// # } /// ``` -/// TODO -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Deserializer<'a, T> { source: Source<'a>, annot: Option, @@ -70,11 +68,9 @@ impl<'a, T> Deserializer<'a, T> { target_type: std::marker::PhantomData, } } - /// TODO fn from_str(s: &'a str) -> Self { Self::default_with_source(Source::Str(s)) } - /// TODO fn from_file>(path: P) -> Self { Self::default_with_source(Source::File(path.as_ref().to_owned())) } @@ -82,11 +78,36 @@ impl<'a, T> Deserializer<'a, T> { // Self::default_with_source(Source::Url(url)) // } - /// TODO + /// Sets whether to enable imports. + /// + /// By default, imports are enabled. + /// + /// # Examples + /// + /// ``` + /// # fn main() -> serde_dhall::Result<()> { + /// use serde::Deserialize; + /// use serde_dhall::SimpleType; + /// + /// let data = "12 + ./other_file.dhall : Natural"; + /// assert!( + /// serde_dhall::options::from_str::(data) + /// .imports(false) + /// .parse() + /// .is_err() + /// ); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation + /// [`StaticType`]: trait.StaticType.html pub fn imports(&mut self, imports: bool) -> &mut Self { self.allow_imports = imports; self } + + // /// TODO // pub fn remote_imports(&mut self, imports: bool) -> &mut Self { // self.allow_remote_imports = imports; // if imports { @@ -94,13 +115,98 @@ impl<'a, T> Deserializer<'a, T> { // } // self // } - // - /// TODO + + /// Ensures that the parsed value matches the provided type. + /// + /// In many cases the Dhall type that corresponds to a Rust type can be inferred automatically. + /// See the [`StaticType`] trait and the [`static_type_annotation`] method. + /// + /// # Examples + /// + /// ``` + /// # fn main() -> serde_dhall::Result<()> { + /// use serde::Deserialize; + /// use serde_dhall::SimpleType; + /// + /// #[derive(Deserialize)] + /// struct Point { + /// x: u64, + /// y: Option, + /// } + /// + /// // Parse a Dhall type + /// let point_type_str = "{ x: Natural, y: Optional Natural }"; + /// let point_type: SimpleType = serde_dhall::options::from_str(point_type_str).parse()?; + /// + /// // Parse some Dhall data to a Point. + /// let data = "{ x = 1, y = Some (1 + 1) }"; + /// let point: Point = serde_dhall::options::from_str(data) + /// .type_annotation(&point_type) + /// .parse()?; + /// assert_eq!(point.x, 1); + /// assert_eq!(point.y, Some(2)); + /// + /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. + /// let invalid_data = "{ x = 1 }"; + /// assert!( + /// serde_dhall::options::from_str::(invalid_data) + /// .type_annotation(&point_type) + /// .parse() + /// .is_err() + /// ); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation + /// [`StaticType`]: trait.StaticType.html pub fn type_annotation(&mut self, ty: &SimpleType) -> &mut Self { self.annot = Some(ty.clone()); self } - /// TODO + + /// Ensures that the parsed value matches the type of `T`. + /// + /// `T` must implement the [`StaticType`] trait. If it doesn't, you can use [`type_annotation`] + /// to provide a type manually. + /// + /// # Examples + /// + /// ``` + /// # fn main() -> serde_dhall::Result<()> { + /// use serde::Deserialize; + /// use serde_dhall::StaticType; + /// + /// #[derive(Deserialize, StaticType)] + /// struct Point { + /// x: u64, + /// y: Option, + /// } + /// + /// // Some Dhall data + /// let data = "{ x = 1, y = Some (1 + 1) }"; + /// + /// // Convert the Dhall string to a Point. + /// let point: Point = serde_dhall::options::from_str(data) + /// .static_type_annotation() + /// .parse()?; + /// assert_eq!(point.x, 1); + /// assert_eq!(point.y, Some(2)); + /// + /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. + /// let invalid_data = "{ x = 1 }"; + /// assert!( + /// serde_dhall::options::from_str::(invalid_data) + /// .static_type_annotation() + /// .parse() + /// .is_err() + /// ); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`type_annotation`]: struct.Deserializer.html#method.type_annotation + /// [`StaticType`]: trait.StaticType.html pub fn static_type_annotation(&mut self) -> &mut Self where T: StaticType, @@ -125,7 +231,20 @@ impl<'a, T> Deserializer<'a, T> { }; Ok(Value::from_nir(typed.normalize().as_nir())) } - /// TODO + + /// Parses the chosen dhall value with the options provided. + /// + /// # Examples + /// + /// Reading from a file: + /// + /// ```no_run + /// # fn main() -> serde_dhall::Result<()> { + /// use serde_dhall::options; + /// let data = options::from_file("foo.dhall").parse()?; + /// # Ok(()) + /// # } + /// ``` pub fn parse(&self) -> Result where T: FromDhall, @@ -138,15 +257,65 @@ impl<'a, T> Deserializer<'a, T> { /// Deserialize an instance of type `T` from a string of Dhall text. /// /// This returns a [`Deserializer`] object. Call the [`parse`] method to get the deserialized value, or -/// use other [`Deserializer`] methods to add type annotations or control import behavior beforehand. +/// use other [`Deserializer`] methods to e.g. add type annotations beforehand. +/// +/// # Example +/// +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use serde::Deserialize; +/// +/// // We use serde's derive feature +/// #[derive(Deserialize)] +/// struct Point { +/// x: u64, +/// y: u64, +/// } +/// +/// // Some Dhall data +/// let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; +/// +/// // Parse the Dhall string as a Point. +/// let point: Point = serde_dhall::options::from_str(data).parse()?; +/// +/// assert_eq!(point.x, 1); +/// assert_eq!(point.y, 2); +/// # Ok(()) +/// # } +/// ``` /// /// [`Deserializer`]: struct.Deserializer.html /// [`parse`]: struct.Deserializer.html#method.parse -pub fn from_str<'a, T>(s: &'a str) -> Deserializer<'a, T> { +pub fn from_str(s: &str) -> Deserializer<'_, T> { Deserializer::from_str(s) } -/// TODO +/// Deserialize an instance of type `T` from a Dhall file. +/// +/// This returns a [`Deserializer`] object. Call the [`parse`] method to get the deserialized value, or +/// use other [`Deserializer`] methods to e.g. add type annotations beforehand. +/// +/// # Example +/// +/// ```no_run +/// # fn main() -> serde_dhall::Result<()> { +/// use serde::Deserialize; +/// +/// // We use serde's derive feature +/// #[derive(Deserialize)] +/// struct Point { +/// x: u64, +/// y: u64, +/// } +/// +/// // Parse the Dhall file as a Point. +/// let point: Point = serde_dhall::options::from_file("foo.dhall").parse()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [`Deserializer`]: struct.Deserializer.html +/// [`parse`]: struct.Deserializer.html#method.parse pub fn from_file<'a, T, P: AsRef>(path: P) -> Deserializer<'a, T> { Deserializer::from_file(path) } @@ -154,3 +323,15 @@ pub fn from_file<'a, T, P: AsRef>(path: P) -> Deserializer<'a, T> { // pub fn from_url<'a, T>(url: &'a str) -> Deserializer<'a, T> { // Deserializer::from_url(url) // } + +// Custom impl to not get a Clone bound on T +impl<'a, T> Clone for Deserializer<'a, T> { + fn clone(&self) -> Self { + Deserializer { + source: self.source.clone(), + annot: self.annot.clone(), + allow_imports: self.allow_imports.clone(), + target_type: std::marker::PhantomData, + } + } +} diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index fee9d73..ea7c20a 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap}; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; use dhall::syntax::{Builtin, Expr, ExprKind, NumKind, Span}; -use crate::{FromDhall, Error, ErrorKind, Result, Sealed}; +use crate::{Error, ErrorKind, FromDhall, Result, Sealed}; #[doc(hidden)] /// An arbitrary Dhall value. diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 8afba6e..b9a504a 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -1,5 +1,5 @@ use serde::Deserialize; -use serde_dhall::{from_str, FromDhall, from_str_static_type, StaticType}; +use serde_dhall::{from_str, from_str_static_type, FromDhall, StaticType}; #[test] fn test_de_typed() { -- cgit v1.3.1 From 678d254a06dbb75f5398abaacee41d1712bf7194 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 15:53:15 +0100 Subject: Make Deserializer functions the only functions --- README.md | 2 +- serde_dhall/src/deserialize.rs | 2 +- serde_dhall/src/lib.rs | 25 ++-- serde_dhall/src/options.rs | 29 +++-- serde_dhall/src/shortcuts.rs | 272 ----------------------------------------- serde_dhall/src/static_type.rs | 4 +- serde_dhall/src/value.rs | 6 +- serde_dhall/tests/de.rs | 10 +- serde_dhall/tests/traits.rs | 2 +- 9 files changed, 37 insertions(+), 315 deletions(-) delete mode 100644 serde_dhall/src/shortcuts.rs (limited to 'serde_dhall/tests') diff --git a/README.md b/README.md index efe4c91..ceb33cd 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ use std::collections::BTreeMap; let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; // Deserialize it to a Rust type. -let deserialized_map: BTreeMap = serde_dhall::from_str(data).unwrap(); +let deserialized_map: BTreeMap = serde_dhall::from_str(data).parse().unwrap(); let mut expected_map = BTreeMap::new(); expected_map.insert("x".to_string(), 1); diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 1be68c4..92be2e9 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -30,7 +30,7 @@ pub trait Sealed {} /// } /// /// // Convert a Dhall string to a Point. -/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }")?; +/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }").parse()?; /// # Ok(()) /// # } /// ``` diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 9f99adb..8ad7cb3 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -30,7 +30,7 @@ //! let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; //! //! // Deserialize it to a Rust type. -//! let deserialized_map: HashMap = serde_dhall::from_str(data)?; +//! let deserialized_map: HashMap = serde_dhall::from_str(data).parse()?; //! //! let mut expected_map = HashMap::new(); //! expected_map.insert("x".to_string(), 1); @@ -57,7 +57,7 @@ //! let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; //! //! // Convert the Dhall string to a Point. -//! let point: Point = serde_dhall::from_str(data)?; +//! let point: Point = serde_dhall::from_str(data).parse()?; //! assert_eq!(point.x, 1); //! assert_eq!(point.y, 2); //! @@ -68,7 +68,7 @@ //! # Replacing `serde_json` or `serde_yaml` //! //! If you used to consume JSON or YAML, you only need to replace [`serde_json::from_str`] or -//! [`serde_yaml::from_str`] with [`serde_dhall::from_str`](fn.from_str.html). +//! [`serde_yaml::from_str`] with [`serde_dhall::from_str(…).parse()`](fn.from_str.html). //! //! [`serde_json::from_str`]: https://docs.serde.rs/serde_json/fn.from_str.html //! [`serde_yaml::from_str`]: https://docs.serde.rs/serde_yaml/fn.from_str.html @@ -103,13 +103,13 @@ //! let data = "{ x = 1, y = 1 + 1 }"; //! //! // Convert the Dhall string to a Point. -//! let point: Point = serde_dhall::from_str_static_type(data)?; +//! let point: Point = serde_dhall::from_str(data).static_type_annotation().parse()?; //! assert_eq!(point.x, 1); //! assert_eq!(point.y, 2); //! //! // Invalid data fails the type validation //! let invalid_data = "{ x = 1, z = 0.3 }"; -//! assert!(serde_dhall::from_str_static_type::(invalid_data).is_err()); +//! assert!(serde_dhall::from_str::(invalid_data).static_type_annotation().parse().is_err()); //! # Ok(()) //! # } //! ``` @@ -124,7 +124,7 @@ //! //! // Parse a Dhall type //! let point_type_str = "{ x: Natural, y: Natural }"; -//! let point_type: SimpleType = serde_dhall::from_str(point_type_str)?; +//! let point_type: SimpleType = serde_dhall::from_str(point_type_str).parse()?; //! //! // Some Dhall data //! let point_data = "{ x = 1, y = 1 + 1 }"; @@ -132,7 +132,7 @@ //! // Deserialize the data to a Rust type. This checks that //! // the data matches the provided type. //! let deserialized_map: HashMap = -//! serde_dhall::from_str_manual_type(point_data, &point_type)?; +//! serde_dhall::from_str(point_data).type_annotation(&point_type).parse()?; //! //! let mut expected_map = HashMap::new(); //! expected_map.insert("x".to_string(), 1); @@ -158,13 +158,9 @@ mod test_readme { doc_comment::doctest!("../../README.md"); } -/// Finer-grained control over deserializing Dhall values -pub mod options; - +mod options; mod deserialize; mod error; -/// Common patterns made easier -mod shortcuts; mod static_type; /// Dhall values mod value; @@ -176,9 +172,8 @@ pub use deserialize::FromDhall; pub(crate) use deserialize::Sealed; pub(crate) use error::ErrorKind; pub use error::{Error, Result}; -pub use shortcuts::{ - from_file, from_file_manual_type, from_file_static_type, from_str, - from_str_manual_type, from_str_static_type, +pub use options::{ + from_file, from_str, Deserializer }; pub use static_type::StaticType; pub use value::{SimpleType, Value}; diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index f3797ee..c44de90 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -27,9 +27,9 @@ enum Source<'a> { /// /// ```no_run /// # fn main() -> serde_dhall::Result<()> { -/// use serde_dhall::options; +/// use serde_dhall::from_file; /// -/// let data = options::from_file("foo.dhall").parse()?; +/// let data = from_file("foo.dhall").parse()?; /// # Ok(()) /// # } /// ``` @@ -38,10 +38,10 @@ enum Source<'a> { /// /// ```no_run /// # fn main() -> serde_dhall::Result<()> { -/// use serde_dhall::options; +/// use serde_dhall::{from_file, from_str}; /// -/// let ty = options::from_str("{ x: Natural, y: Natural }").parse()?; -/// let data = options::from_file("foo.dhall") +/// let ty = from_str("{ x: Natural, y: Natural }").parse()?; +/// let data = from_file("foo.dhall") /// .type_annotation(&ty) /// .parse()?; /// # Ok(()) @@ -91,7 +91,7 @@ impl<'a, T> Deserializer<'a, T> { /// /// let data = "12 + ./other_file.dhall : Natural"; /// assert!( - /// serde_dhall::options::from_str::(data) + /// serde_dhall::from_str::(data) /// .imports(false) /// .parse() /// .is_err() @@ -136,11 +136,11 @@ impl<'a, T> Deserializer<'a, T> { /// /// // Parse a Dhall type /// let point_type_str = "{ x: Natural, y: Optional Natural }"; - /// let point_type: SimpleType = serde_dhall::options::from_str(point_type_str).parse()?; + /// let point_type: SimpleType = serde_dhall::from_str(point_type_str).parse()?; /// /// // Parse some Dhall data to a Point. /// let data = "{ x = 1, y = Some (1 + 1) }"; - /// let point: Point = serde_dhall::options::from_str(data) + /// let point: Point = serde_dhall::from_str(data) /// .type_annotation(&point_type) /// .parse()?; /// assert_eq!(point.x, 1); @@ -149,7 +149,7 @@ impl<'a, T> Deserializer<'a, T> { /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. /// let invalid_data = "{ x = 1 }"; /// assert!( - /// serde_dhall::options::from_str::(invalid_data) + /// serde_dhall::from_str::(invalid_data) /// .type_annotation(&point_type) /// .parse() /// .is_err() @@ -187,7 +187,7 @@ impl<'a, T> Deserializer<'a, T> { /// let data = "{ x = 1, y = Some (1 + 1) }"; /// /// // Convert the Dhall string to a Point. - /// let point: Point = serde_dhall::options::from_str(data) + /// let point: Point = serde_dhall::from_str(data) /// .static_type_annotation() /// .parse()?; /// assert_eq!(point.x, 1); @@ -196,7 +196,7 @@ impl<'a, T> Deserializer<'a, T> { /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. /// let invalid_data = "{ x = 1 }"; /// assert!( - /// serde_dhall::options::from_str::(invalid_data) + /// serde_dhall::from_str::(invalid_data) /// .static_type_annotation() /// .parse() /// .is_err() @@ -240,8 +240,7 @@ impl<'a, T> Deserializer<'a, T> { /// /// ```no_run /// # fn main() -> serde_dhall::Result<()> { - /// use serde_dhall::options; - /// let data = options::from_file("foo.dhall").parse()?; + /// let data = serde_dhall::from_file("foo.dhall").parse()?; /// # Ok(()) /// # } /// ``` @@ -276,7 +275,7 @@ impl<'a, T> Deserializer<'a, T> { /// let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; /// /// // Parse the Dhall string as a Point. -/// let point: Point = serde_dhall::options::from_str(data).parse()?; +/// let point: Point = serde_dhall::from_str(data).parse()?; /// /// assert_eq!(point.x, 1); /// assert_eq!(point.y, 2); @@ -309,7 +308,7 @@ pub fn from_str(s: &str) -> Deserializer<'_, T> { /// } /// /// // Parse the Dhall file as a Point. -/// let point: Point = serde_dhall::options::from_file("foo.dhall").parse()?; +/// let point: Point = serde_dhall::from_file("foo.dhall").parse()?; /// # Ok(()) /// # } /// ``` diff --git a/serde_dhall/src/shortcuts.rs b/serde_dhall/src/shortcuts.rs deleted file mode 100644 index 9c9ce9f..0000000 --- a/serde_dhall/src/shortcuts.rs +++ /dev/null @@ -1,272 +0,0 @@ -use doc_comment::doc_comment; -use std::path::Path; - -use crate::{options, FromDhall, Result, SimpleType, StaticType}; - -// Avoid copy-pasting documentation - -#[rustfmt::skip] -macro_rules! gen_doc { - (@source_desc, str) => {"a string of Dhall text"}; - (@source_desc, file) => {"a Dhall file"}; - (@source_desc, url) => {"a remote url"}; - - (@tck_info1, none) => {""}; - (@tck_info1, manual) => {", additionally checking that it matches the supplied type"}; - (@tck_info1, static) => {", additionally checking that it matches the type of `T`"}; - - (@tck_info2, none) => {""}; - (@tck_info2, manual) => {" against the supplied type"}; - (@tck_info2, static) => {" against the type of `T`"}; - - (@tck_req, $src:tt, none) => {""}; - (@tck_req, $src:tt, manual) => {""}; - (@tck_req, $src:tt, static) => { - concat!("`T` must implement the [`StaticType`] trait. Use [`from_", stringify!($src), - "_manual_type`] to provide a type manually.\n") - }; - - (@tck_comment, $src:tt, none) => { - concat!("For additional type safety, prefer [`from_", stringify!($src), "_static_type`] - or [`from_", stringify!($src), "_manual_type`].\n") - }; - (@tck_comment, $src:tt, manual) => {concat!("See also [`from_", stringify!($src), "_static_type`].\n")}; - (@tck_comment, $src:tt, static) => {""}; - - (@run_example, str) => {""}; - (@run_example, file) => {"no_run"}; - (@run_example, url) => {"no_run"}; - - ($src:tt, $ty:tt) => {concat!(" -Deserialize an instance of type `T` from ", gen_doc!(@source_desc, $src), gen_doc!(@tck_info1, $ty),". - -", gen_doc!(@tck_req, $src, $ty), " -This will recursively resolve all imports in the expression, and typecheck it", gen_doc!(@tck_info2, $ty)," -before deserialization. Relative imports will be resolved relative to the current directory. -See [`options`] for more control over this process. - -", gen_doc!(@tck_comment, $src, $ty), " - -# Example - -```", gen_doc!(@run_example, $src), " -# fn main() -> serde_dhall::Result<()> {", -gen_example!($src, $ty), " -# Ok(()) -# } -``` - -[`options`]: options/index.html -[`from_", stringify!($src), "_manual_type`]: fn.from_", stringify!($src), "_manual_type.html -[`from_", stringify!($src), "_static_type`]: fn.from_", stringify!($src), "_static_type.html -[`StaticType`]: trait.StaticType.html -")}; -} - -#[rustfmt::skip] -macro_rules! gen_example { - (str, none) => {concat!(r#" -use serde::Deserialize; - -// We use serde's derive feature -#[derive(Deserialize)] -struct Point { - x: u64, - y: u64, -} - -// Some Dhall data -let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; - -// Parse the Dhall string as a Point. -let point: Point = serde_dhall::from_str(data)?; - -assert_eq!(point.x, 1); -assert_eq!(point.y, 2); -"#)}; - - (str, manual) => {concat!(r#" -use std::collections::HashMap; -use serde_dhall::SimpleType; - -// Parse a Dhall type -let point_type_str = "{ x: Natural, y: Natural }"; -let point_type: SimpleType = serde_dhall::from_str(point_type_str)?; - -// Some Dhall data -let point_data = "{ x = 1, y = 1 + 1 }"; - -// Deserialize the data to a Rust type. This checks that -// the data matches the provided type. -let deserialized_map: HashMap = - serde_dhall::from_str_manual_type(point_data, &point_type)?; - -let mut expected_map = HashMap::new(); -expected_map.insert("x".to_string(), 1); -expected_map.insert("y".to_string(), 2); - -assert_eq!(deserialized_map, expected_map); -"#)}; - - (str, static) => {concat!(r#" -use serde::Deserialize; -use serde_dhall::StaticType; - -#[derive(Deserialize, StaticType)] -struct Point { - x: u64, - y: u64, -} - -// Some Dhall data -let data = "{ x = 1, y = 1 + 1 }"; - -// Convert the Dhall string to a Point. -let point: Point = serde_dhall::from_str_static_type(data)?; -assert_eq!(point.x, 1); -assert_eq!(point.y, 2); - -// Invalid data fails the type validation -let invalid_data = "{ x = 1, z = 0.3 }"; -assert!(serde_dhall::from_str_static_type::(invalid_data).is_err()); -"#)}; - - (file, none) => {concat!(r#" -use serde::Deserialize; - -// We use serde's derive feature -#[derive(Deserialize)] -struct Point { - x: u64, - y: u64, -} - -// Parse the Dhall file as a Point. -let point: Point = serde_dhall::from_file("foo.dhall")?; -"#)}; - - (file, manual) => {concat!(r#" -use std::collections::HashMap; -use serde_dhall::SimpleType; - -// Parse a Dhall type -let point_type_str = "{ x: Natural, y: Natural }"; -let point_type: SimpleType = serde_dhall::from_str(point_type_str)?; - -// Deserialize the data to a Rust type. This checks that -// the data matches the provided type. -let deserialized_map: HashMap = - serde_dhall::from_file_manual_type("foo.dhall", &point_type)?; -"#)}; - - (file, static) => {concat!(r#" -use serde::Deserialize; -use serde_dhall::StaticType; - -#[derive(Deserialize, StaticType)] -struct Point { - x: u64, - y: u64, -} - -// Convert the Dhall string to a Point. -let point: Point = serde_dhall::from_file_static_type("foo.dhall")?; -"#)}; - - ($src:tt, $ty:tt) => {""}; -} - -macro_rules! generate_fn { - (@generate_src, - str, $ty:tt, $name:ident, - ) => { - generate_fn!(@generate_ty, - str, $ty, $name, - (), - (s: &str), - (options::from_str(s)), - ); - }; - (@generate_src, - file, $ty:tt, $name:ident, - ) => { - generate_fn!(@generate_ty, - file, $ty, $name, - (P: AsRef), - (path: P), - (options::from_file(path)), - ); - }; - - (@generate_ty, - $src:tt, none, $name:ident, - ($($ty_params:tt)*), - ($($input_args:tt)*), - ($($create_options:tt)*), - ) => { - generate_fn!(@generate, - $src, none, $name, - ($($ty_params)*), - ($($input_args)*), - (), - ($($create_options)*), - ); - }; - (@generate_ty, - $src:tt, manual, $name:ident, - ($($ty_params:tt)*), - ($($input_args:tt)*), - ($($create_options:tt)*), - ) => { - generate_fn!(@generate, - $src, manual, $name, - ($($ty_params)*), - ($($input_args)*, ty: &SimpleType), - (), - ($($create_options)* .type_annotation(ty)), - ); - }; - (@generate_ty, - $src:tt, static, $name:ident, - ($($ty_params:tt)*), - ($($input_args:tt)*), - ($($create_options:tt)*), - ) => { - generate_fn!(@generate, - $src, static, $name, - ($($ty_params)*), - ($($input_args)*), - (+ StaticType), - ($($create_options)* .static_type_annotation()), - ); - }; - - (@generate, - $src:tt, $ty:tt, $name:ident, - ($($ty_params:tt)*), - ($($input_args:tt)*), - ($($extra_bounds:tt)*), - ($($create_options:tt)*), - ) => { - doc_comment! { - gen_doc!($src, $ty), - pub fn $name ($($input_args)*) -> Result - where - T: FromDhall $($extra_bounds)*, - { - $($create_options)* .parse() - } - } - }; - - ($src:tt, $ty:tt, $name:ident) => { - generate_fn!(@generate_src, $src, $ty, $name,); - }; -} - -generate_fn!(str, none, from_str); -generate_fn!(str, manual, from_str_manual_type); -generate_fn!(str, static, from_str_static_type); -generate_fn!(file, none, from_file); -generate_fn!(file, manual, from_file_manual_type); -generate_fn!(file, static, from_file_static_type); diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index 020dfce..6e76424 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -23,7 +23,7 @@ use crate::SimpleType; /// } /// /// let ty: SimpleType = -/// serde_dhall::from_str("{ x: Bool, y: List Natural }")?; +/// serde_dhall::from_str("{ x: Bool, y: List Natural }").parse()?; /// /// assert_eq!(Foo::static_type(), ty); /// # Ok(()) @@ -71,7 +71,7 @@ pub trait StaticType { /// } /// } /// - /// let foo: Foo = serde_dhall::from_str_static_type("[ 1, 2 ]")?; + /// let foo: Foo = serde_dhall::from_str("[ 1, 2 ]").static_type_annotation().parse()?; /// /// assert_eq!(foo.0, vec![1, 2]); /// # Ok(()) diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index ea7c20a..f21e836 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -28,7 +28,7 @@ pub(crate) enum SimpleValue { Union(String, Option>), } -/// The type of a value that can be decoded by Serde, like `{ x: Bool, y: List Natural }`. +/// The type of a value that can be decoded by Serde, e.g. `{ x: Bool, y: List Natural }`. /// /// A `SimpleType` is used when deserializing values to ensure they are of the expected type. /// Rather than letting `serde` handle potential type mismatches, this uses the type-checking @@ -53,7 +53,7 @@ pub(crate) enum SimpleValue { /// use serde_dhall::SimpleType; /// /// let ty: SimpleType = -/// serde_dhall::from_str("{ x: Natural, y: Natural }")?; +/// serde_dhall::from_str("{ x: Natural, y: Natural }").parse()?; /// /// let mut map = HashMap::new(); /// map.insert("x".to_string(), SimpleType::Natural); @@ -74,7 +74,7 @@ pub(crate) enum SimpleValue { /// } /// /// let ty: SimpleType = -/// serde_dhall::from_str("{ x: Bool, y: List Natural }")?; +/// serde_dhall::from_str("{ x: Bool, y: List Natural }").parse()?; /// /// assert_eq!(Foo::static_type(), ty); /// # Ok(()) diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index b9a504a..970234b 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -1,10 +1,10 @@ use serde::Deserialize; -use serde_dhall::{from_str, from_str_static_type, FromDhall, StaticType}; +use serde_dhall::{from_str, FromDhall, StaticType}; #[test] fn test_de_typed() { fn parse(s: &str) -> T { - from_str_static_type(s).unwrap() + from_str(s).static_type_annotation().parse().unwrap() } assert_eq!(parse::("True"), true); @@ -52,13 +52,13 @@ fn test_de_typed() { } assert_eq!(parse::("< X | Y: Integer >.X"), Baz::X); - assert!(from_str_static_type::("< X | Y: Integer >.Y").is_err()); + assert!(from_str::("< X | Y: Integer >.Y").static_type_annotation().parse().is_err()); } #[test] fn test_de_untyped() { fn parse(s: &str) -> T { - from_str(s).unwrap() + from_str(s).parse().unwrap() } // Test tuples on record of wrong type @@ -94,5 +94,5 @@ fn test_de_untyped() { assert_eq!(parse::("{ x = 1 }"), Foo { x: 1, y: None }); // https://github.com/Nadrieril/dhall-rust/issues/155 - assert!(from_str::("List/length [True, 42]").is_err()); + assert!(from_str::("List/length [True, 42]").parse().is_err()); } diff --git a/serde_dhall/tests/traits.rs b/serde_dhall/tests/traits.rs index 608e6ed..3c6fbfe 100644 --- a/serde_dhall/tests/traits.rs +++ b/serde_dhall/tests/traits.rs @@ -3,7 +3,7 @@ use serde_dhall::{from_str, SimpleType, StaticType}; #[test] fn test_static_type() { fn parse(s: &str) -> SimpleType { - from_str(s).unwrap() + from_str(s).parse().unwrap() } assert_eq!(bool::static_type(), parse("Bool")); -- cgit v1.3.1 From 797241ebec5cec686056b5da73864db8eab03d48 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 16:36:54 +0100 Subject: Rewrite builder with state machine to allow parse::<> --- serde_dhall/src/lib.rs | 24 ++++-- serde_dhall/src/options.rs | 203 ++++++++++++++++++++++++++------------------- serde_dhall/tests/de.rs | 10 ++- 3 files changed, 140 insertions(+), 97 deletions(-) (limited to 'serde_dhall/tests') diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 8ad7cb3..08ca4a5 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -103,13 +103,20 @@ //! let data = "{ x = 1, y = 1 + 1 }"; //! //! // Convert the Dhall string to a Point. -//! let point: Point = serde_dhall::from_str(data).static_type_annotation().parse()?; +//! let point = serde_dhall::from_str(data) +//! .static_type_annotation() +//! .parse::()?; //! assert_eq!(point.x, 1); //! assert_eq!(point.y, 2); //! //! // Invalid data fails the type validation //! let invalid_data = "{ x = 1, z = 0.3 }"; -//! assert!(serde_dhall::from_str::(invalid_data).static_type_annotation().parse().is_err()); +//! assert!( +//! serde_dhall::from_str(invalid_data) +//! .static_type_annotation() +//! .parse::() +//! .is_err() +//! ); //! # Ok(()) //! # } //! ``` @@ -124,15 +131,16 @@ //! //! // Parse a Dhall type //! let point_type_str = "{ x: Natural, y: Natural }"; -//! let point_type: SimpleType = serde_dhall::from_str(point_type_str).parse()?; +//! let point_type = serde_dhall::from_str(point_type_str).parse::()?; //! //! // Some Dhall data //! let point_data = "{ x = 1, y = 1 + 1 }"; //! //! // Deserialize the data to a Rust type. This checks that //! // the data matches the provided type. -//! let deserialized_map: HashMap = -//! serde_dhall::from_str(point_data).type_annotation(&point_type).parse()?; +//! let deserialized_map = serde_dhall::from_str(point_data) +//! .type_annotation(&point_type) +//! .parse::>()?; //! //! let mut expected_map = HashMap::new(); //! expected_map.insert("x".to_string(), 1); @@ -158,9 +166,9 @@ mod test_readme { doc_comment::doctest!("../../README.md"); } -mod options; mod deserialize; mod error; +mod options; mod static_type; /// Dhall values mod value; @@ -172,8 +180,6 @@ pub use deserialize::FromDhall; pub(crate) use deserialize::Sealed; pub(crate) use error::ErrorKind; pub use error::{Error, Result}; -pub use options::{ - from_file, from_str, Deserializer -}; +pub use options::{from_file, from_str, Deserializer}; pub use static_type::StaticType; pub use value::{SimpleType, Value}; diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index c44de90..a20891a 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -12,6 +12,32 @@ enum Source<'a> { // Url(&'a str), } +#[derive(Debug, Clone)] +pub struct NoAnnot; +#[derive(Debug, Clone)] +pub struct ManualAnnot(SimpleType); +#[derive(Debug, Clone)] +pub struct StaticAnnot; + +pub trait HasAnnot { + fn get_annot(a: &A) -> Option; +} +impl HasAnnot for T { + fn get_annot(_: &NoAnnot) -> Option { + None + } +} +impl HasAnnot for T { + fn get_annot(a: &ManualAnnot) -> Option { + Some(a.0.clone()) + } +} +impl HasAnnot for T { + fn get_annot(_: &StaticAnnot) -> Option { + Some(T::static_type()) + } +} + /// Controls how a dhall value is read. /// /// This builder exposes the ability to configure how a value is deserialized and what operations @@ -29,7 +55,7 @@ enum Source<'a> { /// # fn main() -> serde_dhall::Result<()> { /// use serde_dhall::from_file; /// -/// let data = from_file("foo.dhall").parse()?; +/// let data = from_file("foo.dhall").parse::()?; /// # Ok(()) /// # } /// ``` @@ -38,34 +64,33 @@ enum Source<'a> { /// /// ```no_run /// # fn main() -> serde_dhall::Result<()> { +/// use std::collections::HashMap; /// use serde_dhall::{from_file, from_str}; /// /// let ty = from_str("{ x: Natural, y: Natural }").parse()?; /// let data = from_file("foo.dhall") /// .type_annotation(&ty) -/// .parse()?; +/// .parse::>()?; /// # Ok(()) /// # } /// ``` -#[derive(Debug)] -pub struct Deserializer<'a, T> { +#[derive(Debug, Clone)] +pub struct Deserializer<'a, A> { source: Source<'a>, - annot: Option, + annot: A, allow_imports: bool, // allow_remote_imports: bool, // use_cache: bool, - target_type: std::marker::PhantomData, } -impl<'a, T> Deserializer<'a, T> { +impl<'a> Deserializer<'a, NoAnnot> { fn default_with_source(source: Source<'a>) -> Self { Deserializer { source, - annot: None, + annot: NoAnnot, allow_imports: true, // allow_remote_imports: true, // use_cache: true, - target_type: std::marker::PhantomData, } } fn from_str(s: &'a str) -> Self { @@ -77,45 +102,9 @@ impl<'a, T> Deserializer<'a, T> { // fn from_url(url: &'a str) -> Self { // Self::default_with_source(Source::Url(url)) // } +} - /// Sets whether to enable imports. - /// - /// By default, imports are enabled. - /// - /// # Examples - /// - /// ``` - /// # fn main() -> serde_dhall::Result<()> { - /// use serde::Deserialize; - /// use serde_dhall::SimpleType; - /// - /// let data = "12 + ./other_file.dhall : Natural"; - /// assert!( - /// serde_dhall::from_str::(data) - /// .imports(false) - /// .parse() - /// .is_err() - /// ); - /// # Ok(()) - /// # } - /// ``` - /// - /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation - /// [`StaticType`]: trait.StaticType.html - pub fn imports(&mut self, imports: bool) -> &mut Self { - self.allow_imports = imports; - self - } - - // /// TODO - // pub fn remote_imports(&mut self, imports: bool) -> &mut Self { - // self.allow_remote_imports = imports; - // if imports { - // self.allow_imports = true; - // } - // self - // } - +impl<'a> Deserializer<'a, NoAnnot> { /// Ensures that the parsed value matches the provided type. /// /// In many cases the Dhall type that corresponds to a Rust type can be inferred automatically. @@ -136,22 +125,22 @@ impl<'a, T> Deserializer<'a, T> { /// /// // Parse a Dhall type /// let point_type_str = "{ x: Natural, y: Optional Natural }"; - /// let point_type: SimpleType = serde_dhall::from_str(point_type_str).parse()?; + /// let point_type = serde_dhall::from_str(point_type_str).parse::()?; /// /// // Parse some Dhall data to a Point. /// let data = "{ x = 1, y = Some (1 + 1) }"; - /// let point: Point = serde_dhall::from_str(data) + /// let point = serde_dhall::from_str(data) /// .type_annotation(&point_type) - /// .parse()?; + /// .parse::()?; /// assert_eq!(point.x, 1); /// assert_eq!(point.y, Some(2)); /// /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. /// let invalid_data = "{ x = 1 }"; /// assert!( - /// serde_dhall::from_str::(invalid_data) + /// serde_dhall::from_str(invalid_data) /// .type_annotation(&point_type) - /// .parse() + /// .parse::() /// .is_err() /// ); /// # Ok(()) @@ -160,9 +149,15 @@ impl<'a, T> Deserializer<'a, T> { /// /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation /// [`StaticType`]: trait.StaticType.html - pub fn type_annotation(&mut self, ty: &SimpleType) -> &mut Self { - self.annot = Some(ty.clone()); - self + pub fn type_annotation( + self, + ty: &SimpleType, + ) -> Deserializer<'a, ManualAnnot> { + Deserializer { + annot: ManualAnnot(ty.clone()), + source: self.source, + allow_imports: self.allow_imports, + } } /// Ensures that the parsed value matches the type of `T`. @@ -187,18 +182,18 @@ impl<'a, T> Deserializer<'a, T> { /// let data = "{ x = 1, y = Some (1 + 1) }"; /// /// // Convert the Dhall string to a Point. - /// let point: Point = serde_dhall::from_str(data) + /// let point = serde_dhall::from_str(data) /// .static_type_annotation() - /// .parse()?; + /// .parse::()?; /// assert_eq!(point.x, 1); /// assert_eq!(point.y, Some(2)); /// /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. /// let invalid_data = "{ x = 1 }"; /// assert!( - /// serde_dhall::from_str::(invalid_data) + /// serde_dhall::from_str(invalid_data) /// .static_type_annotation() - /// .parse() + /// .parse::() /// .is_err() /// ); /// # Ok(()) @@ -207,15 +202,60 @@ impl<'a, T> Deserializer<'a, T> { /// /// [`type_annotation`]: struct.Deserializer.html#method.type_annotation /// [`StaticType`]: trait.StaticType.html - pub fn static_type_annotation(&mut self) -> &mut Self - where - T: StaticType, - { - self.annot = Some(T::static_type()); - self + pub fn static_type_annotation(self) -> Deserializer<'a, StaticAnnot> { + Deserializer { + annot: StaticAnnot, + source: self.source, + allow_imports: self.allow_imports, + } + } +} + +impl<'a, A> Deserializer<'a, A> { + /// Sets whether to enable imports. + /// + /// By default, imports are enabled. + /// + /// # Examples + /// + /// ``` + /// # fn main() -> serde_dhall::Result<()> { + /// use serde::Deserialize; + /// use serde_dhall::SimpleType; + /// + /// let data = "12 + ./other_file.dhall : Natural"; + /// assert!( + /// serde_dhall::from_str(data) + /// .imports(false) + /// .parse::() + /// .is_err() + /// ); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation + /// [`StaticType`]: trait.StaticType.html + pub fn imports(self, imports: bool) -> Self { + Deserializer { + allow_imports: imports, + ..self + } } - fn _parse(&self) -> dhall::error::Result { + // /// TODO + // pub fn remote_imports(&mut self, imports: bool) -> &mut Self { + // self.allow_remote_imports = imports; + // if imports { + // self.allow_imports = true; + // } + // self + // } + + fn _parse(&self) -> dhall::error::Result + where + T: HasAnnot, + { let parsed = match &self.source { Source::Str(s) => Parsed::parse_str(s)?, Source::File(p) => Parsed::parse_file(p.as_ref())?, @@ -225,7 +265,7 @@ impl<'a, T> Deserializer<'a, T> { } else { parsed.skip_resolve()? }; - let typed = match &self.annot { + let typed = match &T::get_annot(&self.annot) { None => resolved.typecheck()?, Some(ty) => resolved.typecheck_with(ty.to_value().as_hir())?, }; @@ -240,15 +280,18 @@ impl<'a, T> Deserializer<'a, T> { /// /// ```no_run /// # fn main() -> serde_dhall::Result<()> { - /// let data = serde_dhall::from_file("foo.dhall").parse()?; + /// let data = serde_dhall::from_file("foo.dhall").parse::()?; /// # Ok(()) /// # } /// ``` - pub fn parse(&self) -> Result + pub fn parse(&self) -> Result where - T: FromDhall, + T: FromDhall + HasAnnot, { - let val = self._parse().map_err(ErrorKind::Dhall).map_err(Error)?; + let val = self + ._parse::() + .map_err(ErrorKind::Dhall) + .map_err(Error)?; T::from_dhall(&val) } } @@ -285,7 +328,7 @@ impl<'a, T> Deserializer<'a, T> { /// /// [`Deserializer`]: struct.Deserializer.html /// [`parse`]: struct.Deserializer.html#method.parse -pub fn from_str(s: &str) -> Deserializer<'_, T> { +pub fn from_str(s: &str) -> Deserializer<'_, NoAnnot> { Deserializer::from_str(s) } @@ -315,22 +358,10 @@ pub fn from_str(s: &str) -> Deserializer<'_, T> { /// /// [`Deserializer`]: struct.Deserializer.html /// [`parse`]: struct.Deserializer.html#method.parse -pub fn from_file<'a, T, P: AsRef>(path: P) -> Deserializer<'a, T> { +pub fn from_file<'a, P: AsRef>(path: P) -> Deserializer<'a, NoAnnot> { Deserializer::from_file(path) } -// pub fn from_url<'a, T>(url: &'a str) -> Deserializer<'a, T> { +// pub fn from_url(url: &str) -> Deserializer<'_, NoAnnot> { // Deserializer::from_url(url) // } - -// Custom impl to not get a Clone bound on T -impl<'a, T> Clone for Deserializer<'a, T> { - fn clone(&self) -> Self { - Deserializer { - source: self.source.clone(), - annot: self.annot.clone(), - allow_imports: self.allow_imports.clone(), - target_type: std::marker::PhantomData, - } - } -} diff --git a/serde_dhall/tests/de.rs b/serde_dhall/tests/de.rs index 970234b..a5c42fd 100644 --- a/serde_dhall/tests/de.rs +++ b/serde_dhall/tests/de.rs @@ -52,7 +52,10 @@ fn test_de_typed() { } assert_eq!(parse::("< X | Y: Integer >.X"), Baz::X); - assert!(from_str::("< X | Y: Integer >.Y").static_type_annotation().parse().is_err()); + assert!(from_str("< X | Y: Integer >.Y") + .static_type_annotation() + .parse::() + .is_err()); } #[test] @@ -94,5 +97,8 @@ fn test_de_untyped() { assert_eq!(parse::("{ x = 1 }"), Foo { x: 1, y: None }); // https://github.com/Nadrieril/dhall-rust/issues/155 - assert!(from_str::("List/length [True, 42]").parse().is_err()); + assert!(from_str("List/length [True, 42]").parse::().is_err()); } + +// TODO: test various builder configurations +// In particular test cloning and reusing builder -- cgit v1.3.1