diff options
author | Nadrieril | 2020-03-22 21:20:58 +0000 |
---|---|---|
committer | Nadrieril | 2020-03-31 21:45:31 +0100 |
commit | 1a98b506055779e1a60558d9c5a56b071b3d61a0 (patch) | |
tree | 1ec11648ed9e3c503c6f4f06307c3541af648a23 | |
parent | 196491a37a9ab2869ab6d76e1417a85a9e033dd4 (diff) |
Reorganize API and internals of serde_dhall a bit
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | abnf_to_pest/Cargo.toml | 2 | ||||
-rw-r--r-- | dhall/src/semantics/resolve/resolve.rs | 2 | ||||
-rw-r--r-- | serde_dhall/src/deserialize.rs (renamed from serde_dhall/src/serde.rs) | 21 | ||||
-rw-r--r-- | serde_dhall/src/lib.rs | 80 | ||||
-rw-r--r-- | serde_dhall/src/shortcuts.rs | 100 | ||||
-rw-r--r-- | serde_dhall/src/simple.rs | 2 | ||||
-rw-r--r-- | serde_dhall/src/value.rs | 2 | ||||
-rw-r--r-- | serde_dhall/tests/de.rs | 6 | ||||
-rw-r--r-- | serde_dhall/tests/version_numbers.rs | 5 | ||||
-rw-r--r-- | tests_buffer | 4 |
12 files changed, 152 insertions, 76 deletions
@@ -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)", ] @@ -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<Hir, Error> { pub fn skip_resolve(parsed: Parsed) -> Result<Resolved, Error> { 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/serde.rs b/serde_dhall/src/deserialize.rs index 717450a..75a08a9 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/deserialize.rs @@ -1,15 +1,28 @@ -use std::borrow::Cow; - use serde::de::value::{ MapAccessDeserializer, MapDeserializer, SeqDeserializer, }; +use std::borrow::Cow; use dhall::syntax::NumKind; use crate::simple::{ValKind, Value as SimpleValue}; -use crate::{Deserialize, Error, Result, Value}; +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<Self>; +} -impl<'a, T> crate::sealed::Sealed for T where T: serde::Deserialize<'a> {} +impl<'a, T> Sealed for T where T: serde::Deserialize<'a> {} struct Deserializer<'a>(Cow<'a, SimpleValue>); 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<String, usize> = -//! 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::<Point>(invalid_data).is_err()); +//! assert!(serde_dhall::from_str_static_type::<Point>(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<Self>; -} - -/// 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<T>(s: &str) -> Result<T> -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<T>(s: &str, ty: &simple::Type) -> Result<T> -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<T>(s: &str) -> Result<T> -where - T: Deserialize + StaticType, -{ - options::from_str(s).static_type_annotation().parse() -} 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<T>(s: &str) -> Result<T> +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<String, usize> = +/// 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<T>(s: &str, ty: &SimpleType) -> Result<T> +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<T>(s: &str) -> Result<T> +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<T: serde_dhall::Deserialize + StaticType>(s: &str) -> T { - from_str_auto_type(s).unwrap() + from_str_static_type(s).unwrap() } assert_eq!(parse::<bool>("True"), true); @@ -52,7 +52,7 @@ fn test_de_typed() { } assert_eq!(parse::<Baz>("< X | Y: Integer >.X"), Baz::X); - assert!(from_str_auto_type::<Baz>("< X | Y: Integer >.Y").is_err()); + assert!(from_str_static_type::<Baz>("< 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/ |