summaryrefslogtreecommitdiff
path: root/serde_dhall
diff options
context:
space:
mode:
authorNadrieril2020-03-22 22:11:00 +0000
committerNadrieril2020-03-31 21:45:31 +0100
commita70922c6c6beb58a45da80f15576b54fb915ec28 (patch)
tree13ec93aef7a8d5bb717b7722116c58f76a57dc36 /serde_dhall
parentfd4a81b1a92c1859941538b7f2212c621f4b43fd (diff)
Rework SimpleType
Diffstat (limited to 'serde_dhall')
-rw-r--r--serde_dhall/src/lib.rs12
-rw-r--r--serde_dhall/src/options.rs5
-rw-r--r--serde_dhall/src/shortcuts.rs10
-rw-r--r--serde_dhall/src/simple.rs145
-rw-r--r--serde_dhall/src/static_type.rs26
-rw-r--r--serde_dhall/src/value.rs2
-rw-r--r--serde_dhall/tests/traits.rs4
7 files changed, 120 insertions, 84 deletions
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<Value>),
List(Vec<Value>),
- // TODO: HashMap ?
Record(BTreeMap<String, Value>),
Union(String, Option<Value>),
}
-/// 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<u64>,
+/// }
+///
+/// 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<TyKind>,
-}
-
-#[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<String, Type>),
- Union(BTreeMap<String, Option<Type>>),
+ /// Corresponds to the Dhall type `Optional T`
+ Optional(Box<SimpleType>),
+ /// Corresponds to the Dhall type `List T`
+ List(Box<SimpleType>),
+ /// Corresponds to the Dhall type `{ x : T, y : U }`
+ Record(HashMap<String, SimpleType>),
+ /// Corresponds to the Dhall type `< x : T | y : U >`
+ Union(HashMap<String, Option<SimpleType>>),
}
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<Self> {
- 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::<Option<_>>()?,
),
- NirKind::UnionType(kts) => TyKind::Union(
+ NirKind::UnionType(kts) => SimpleType::Union(
kts.iter()
.map(|(k, v)| {
Some((
@@ -123,13 +171,10 @@ impl Type {
.collect::<Option<_>>()?,
),
_ => 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<Self> {
v.to_simple_type().ok_or_else(|| {
Error::Deserialize(format!(
@@ -192,9 +237,3 @@ impl Deserialize for Type {
})
}
}
-
-impl From<TyKind> 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<T> StaticType for Option<T>
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<T> StaticType for Vec<T>
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()
}