summaryrefslogtreecommitdiff
path: root/serde_dhall
diff options
context:
space:
mode:
Diffstat (limited to 'serde_dhall')
-rw-r--r--serde_dhall/src/deserialize.rs34
-rw-r--r--serde_dhall/src/lib.rs102
-rw-r--r--serde_dhall/src/shortcuts.rs19
-rw-r--r--serde_dhall/src/static_type.rs47
4 files changed, 128 insertions, 74 deletions
diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs
index 7bb0051..b9b711c 100644
--- a/serde_dhall/src/deserialize.rs
+++ b/serde_dhall/src/deserialize.rs
@@ -10,26 +10,44 @@ use crate::{Error, ErrorKind, Result, Value};
pub trait Sealed {}
-/// A data structure that can be deserialized from a Dhall expression
+/// A data structure that can be deserialized from a Dhall expression.
///
-/// This is automatically implemented for any type that [serde][serde]
-/// can deserialize.
+/// This is automatically implemented for any type that [serde] can deserialize.
+/// In fact, this trait cannot be implemented manually. To implement it for your type,
+/// use serde's derive mechanism.
///
-/// This trait cannot be implemented manually.
+/// # Example
///
-/// TODO
+/// ```rust
+/// # fn main() -> serde_dhall::Result<()> {
+/// use serde::Deserialize;
+///
+/// // Use serde's derive
+/// #[derive(Deserialize)]
+/// struct Point {
+/// x: u64,
+/// y: u64,
+/// }
+///
+/// // Convert a Dhall string to a Point.
+/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }")?;
+/// # Ok(())
+/// # }
+/// ```
+///
+/// [serde]: https://serde.rs
pub trait Deserialize: Sealed + Sized {
#[doc(hidden)]
fn from_dhall(v: &Value) -> Result<Self>;
}
-impl<'a, T> Sealed for T where T: serde::Deserialize<'a> {}
+impl<T> Sealed for T where T: serde::de::DeserializeOwned {}
struct Deserializer<'a>(Cow<'a, SimpleValue>);
-impl<'a, T> Deserialize for T
+impl<T> Deserialize for T
where
- T: serde::Deserialize<'a>,
+ T: serde::de::DeserializeOwned,
{
fn from_dhall(v: &Value) -> Result<Self> {
let sval = v.to_simple_value().ok_or_else(|| {
diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs
index fe1f4b2..71274b6 100644
--- a/serde_dhall/src/lib.rs
+++ b/serde_dhall/src/lib.rs
@@ -1,5 +1,5 @@
#![doc(html_root_url = "https://docs.rs/serde_dhall/0.4.0")]
-// TODO #![warn(missing_docs)] #![warn(missing_doc_code_examples)]
+#![warn(missing_docs, missing_doc_code_examples)]
//! [Dhall][dhall] is a programmable configuration language that provides a non-repetitive
//! alternative to JSON and YAML.
//!
@@ -47,7 +47,7 @@
//! # fn main() -> serde_dhall::Result<()> {
//! use serde::Deserialize;
//!
-//! #[derive(Debug, Deserialize)]
+//! #[derive(Deserialize)]
//! struct Point {
//! x: u64,
//! y: u64,
@@ -65,28 +65,6 @@
//! # }
//! ```
//!
-//! # Type correspondence
-//!
-//! The following Dhall types correspond to the following Rust types:
-//!
-//! Dhall | Rust
-//! -------|------
-//! `Bool` | `bool`
-//! `Natural` | `u64`, `u32`, ...
-//! `Integer` | `i64`, `i32`, ...
-//! `Double` | `f64`, `f32`, ...
-//! `Text` | `String`
-//! `List T` | `Vec<T>`
-//! `Optional T` | `Option<T>`
-//! `{ x: T, y: U }` | structs
-//! `{ _1: T, _2: U }` | `(T, U)`, structs
-//! `{ x: T, y: T }` | `HashMap<String, T>`, structs
-//! `< x: T \| y: U >` | enums
-//! `T -> U` | unsupported
-//! `Prelude.JSON.Type` | unsupported
-//! `Prelude.Map.Type T U` | unsupported
-//!
-//!
//! # Replacing `serde_json` or `serde_yaml`
//!
//! If you used to consume JSON or YAML, you only need to replace [`serde_json::from_str`] or
@@ -99,16 +77,45 @@
//! # Additional Dhall typechecking
//!
//! When deserializing, normal type checking is done to ensure that the returned value is a valid
-//! Dhall value, and that it can be deserialized into the required Rust type. However types are
-//! first-class in Dhall, and this library allows you to additionally check that some input data
+//! Dhall value. However types are
+//! first-class in Dhall, and this library allows you to additionally check that the input data
//! matches a given Dhall type. That way, a type error will be caught on the Dhall side, and have
//! pretty and explicit errors that point to the source file.
//!
-//! 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.
+//! There are two ways to typecheck a Dhall value in this way: you can provide the type manually or
+//! you can let Rust infer it for you.
+//!
+//! To let Rust infer the appropriate Dhall type, use the [StaticType](trait.StaticType.html)
+//! trait.
+//!
+//! ```rust
+//! # fn main() -> serde_dhall::Result<()> {
+//! 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::<Point>(invalid_data).is_err());
+//! # Ok(())
+//! # }
+//! ```
//!
-//! 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).
+//! To provide a type manually, you need a [`SimpleType`](enum.SimpleType.html) value. You
+//! can parse it from some Dhall text like you would parse any other value.
//!
//! ```rust
//! # fn main() -> serde_dhall::Result<()> {
@@ -136,41 +143,20 @@
//! # }
//! ```
//!
-//! You can also let Rust infer the appropriate Dhall type, using the
-//! [StaticType](trait.StaticType.html) trait.
-//!
-//! ```rust
-//! # fn main() -> serde_dhall::Result<()> {
-//! use serde::Deserialize;
-//! use serde_dhall::StaticType;
-//!
-//! #[derive(Debug, Deserialize, StaticType)]
-//! struct Point {
-//! x: u64,
-//! y: u64,
-//! }
+//! # Controlling deserialization
//!
-//! // 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::<Point>(invalid_data).is_err());
-//! # Ok(())
-//! # }
-//! ```
+//! If you need more control over the process of reading Dhall values, e.g. disabling
+//! imports, see the [`options`] module.
//!
+//! [`options`]: options/index.html
//! [dhall]: https://dhall-lang.org/
//! [serde]: https://docs.serde.rs/serde/
//! [serde::Deserialize]: https://docs.serde.rs/serde/trait.Deserialize.html
#[cfg(doctest)]
-doc_comment::doctest!("../../README.md");
+mod test_readme {
+ doc_comment::doctest!("../../README.md");
+}
/// Finer-grained control over deserializing Dhall values
pub mod options;
diff --git a/serde_dhall/src/shortcuts.rs b/serde_dhall/src/shortcuts.rs
index 4aba9d1..cd31402 100644
--- a/serde_dhall/src/shortcuts.rs
+++ b/serde_dhall/src/shortcuts.rs
@@ -19,9 +19,12 @@ macro_rules! gen_doc {
(@tck_info2, manual) => {" against the supplied type"};
(@tck_info2, static) => {" against the type of `T`"};
- (@tck_req, none) => {""};
- (@tck_req, manual) => {""};
- (@tck_req, static) => {"`T` must implement the [`StaticType`] trait.\n"};
+ (@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`]
@@ -37,7 +40,7 @@ macro_rules! gen_doc {
($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, $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.
@@ -66,7 +69,7 @@ macro_rules! gen_example {
use serde::Deserialize;
// We use serde's derive feature
-#[derive(Debug, Deserialize)]
+#[derive(Deserialize)]
struct Point {
x: u64,
y: u64,
@@ -109,7 +112,7 @@ assert_eq!(deserialized_map, expected_map);
use serde::Deserialize;
use serde_dhall::StaticType;
-#[derive(Debug, Deserialize, StaticType)]
+#[derive(Deserialize, StaticType)]
struct Point {
x: u64,
y: u64,
@@ -132,7 +135,7 @@ assert!(serde_dhall::from_str_static_type::<Point>(invalid_data).is_err());
use serde::Deserialize;
// We use serde's derive feature
-#[derive(Debug, Deserialize)]
+#[derive(Deserialize)]
struct Point {
x: u64,
y: u64,
@@ -160,7 +163,7 @@ let deserialized_map: HashMap<String, usize> =
use serde::Deserialize;
use serde_dhall::StaticType;
-#[derive(Debug, Deserialize, StaticType)]
+#[derive(Deserialize, StaticType)]
struct Point {
x: u64,
y: u64,
diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs
index 19f1202..020dfce 100644
--- a/serde_dhall/src/static_type.rs
+++ b/serde_dhall/src/static_type.rs
@@ -29,7 +29,54 @@ use crate::SimpleType;
/// # Ok(())
/// # }
/// ```
+///
+/// # Type correspondence
+///
+/// The following Dhall types correspond to the following Rust types:
+///
+/// Dhall | Rust
+/// -------|------
+/// `Bool` | `bool`
+/// `Natural` | `u64`, `u32`, ...
+/// `Integer` | `i64`, `i32`, ...
+/// `Double` | `f64`, `f32`, ...
+/// `Text` | `String`
+/// `List T` | `Vec<T>`
+/// `Optional T` | `Option<T>`
+/// `{ x: T, y: U }` | structs
+/// `{ _1: T, _2: U }` | `(T, U)`, structs
+/// `{ x: T, y: T }` | `HashMap<String, T>`, structs
+/// `< x: T \| y: U >` | enums
+/// `T -> U` | unsupported
+/// `Prelude.JSON.Type` | unsupported
+/// `Prelude.Map.Type T U` | unsupported
pub trait StaticType {
+ /// Return the Dhall type that represents this type.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # fn main() -> serde_dhall::Result<()> {
+ /// use serde::Deserialize;
+ /// use serde_dhall::{SimpleType, StaticType};
+ ///
+ /// // Using `derive(StaticType)` here would give it the type `{ _1: List Natural }`.
+ /// #[derive(Deserialize)]
+ /// #[serde(transparent)]
+ /// struct Foo(Vec<u64>);
+ ///
+ /// impl StaticType for Foo {
+ /// fn static_type() -> SimpleType {
+ /// SimpleType::List(Box::new(SimpleType::Natural))
+ /// }
+ /// }
+ ///
+ /// let foo: Foo = serde_dhall::from_str_static_type("[ 1, 2 ]")?;
+ ///
+ /// assert_eq!(foo.0, vec![1, 2]);
+ /// # Ok(())
+ /// # }
+ /// ```
fn static_type() -> SimpleType;
}