From 3a5f2044954aae7278f16e30561a81626dba6923 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 22:27:56 +0000 Subject: Move mod simple into value --- serde_dhall/src/deserialize.rs | 2 +- serde_dhall/src/lib.rs | 5 +- serde_dhall/src/options.rs | 2 +- serde_dhall/src/simple.rs | 224 ------------------------------------ serde_dhall/src/value.rs | 252 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 240 insertions(+), 245 deletions(-) delete mode 100644 serde_dhall/src/simple.rs diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 43b7914..ab5580e 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use dhall::syntax::NumKind; -use crate::simple::SimpleValue; +use crate::value::SimpleValue; use crate::{Error, Result, Value}; pub trait Sealed {} diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index c6c6bf9..02b34a7 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -179,8 +179,6 @@ mod deserialize; mod error; /// Common patterns made easier mod shortcuts; -/// Serde-compatible Dhall types -mod simple; mod static_type; /// Dhall values mod value; @@ -192,6 +190,5 @@ 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::SimpleType; pub use static_type::StaticType; -pub use value::Value; +pub use value::{SimpleType, Value}; diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs index 0072393..f468cf0 100644 --- a/serde_dhall/src/options.rs +++ b/serde_dhall/src/options.rs @@ -121,7 +121,7 @@ impl<'a, T> Options<'a, T> { }; let typed = match &self.annot { None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(&ty.to_value().hir)?, + Some(ty) => resolved.typecheck_with(ty.to_value().as_hir())?, }; Ok(Value::from_nir(typed.normalize().as_nir())) } diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs deleted file mode 100644 index c1f0047..0000000 --- a/serde_dhall/src/simple.rs +++ /dev/null @@ -1,224 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -use dhall::semantics::{Hir, HirKind, Nir, NirKind}; -use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; - -use crate::{Deserialize, Error, Result, Sealed, Value}; - -/// A simple value of the kind that can be decoded with serde -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum SimpleValue { - Num(NumKind), - Text(String), - Optional(Option>), - List(Vec), - Record(BTreeMap), - Union(String, Option>), -} - -/// 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 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, - /// 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 SimpleValue { - pub(crate) fn from_nir(nir: &Nir) -> Option { - Some(match nir.kind() { - NirKind::Num(lit) => SimpleValue::Num(lit.clone()), - NirKind::TextLit(x) => SimpleValue::Text( - x.as_text() - .expect("Normal form should ensure the text is a string"), - ), - NirKind::EmptyOptionalLit(_) => SimpleValue::Optional(None), - NirKind::NEOptionalLit(x) => { - SimpleValue::Optional(Some(Box::new(Self::from_nir(x)?))) - } - NirKind::EmptyListLit(_) => SimpleValue::List(vec![]), - NirKind::NEListLit(xs) => SimpleValue::List( - xs.iter().map(Self::from_nir).collect::>()?, - ), - NirKind::RecordLit(kvs) => SimpleValue::Record( - kvs.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) - .collect::>()?, - ), - NirKind::UnionLit(field, x, _) => SimpleValue::Union( - field.into(), - Some(Box::new(Self::from_nir(x)?)), - ), - NirKind::UnionConstructor(field, ty) - if ty.get(field).map(|f| f.is_some()) == Some(false) => - { - SimpleValue::Union(field.into(), None) - } - _ => return None, - }) - } -} - -impl SimpleType { - pub(crate) fn from_nir(nir: &Nir) -> Option { - Some(match nir.kind() { - NirKind::BuiltinType(b) => match b { - Builtin::Bool => SimpleType::Bool, - Builtin::Natural => SimpleType::Natural, - Builtin::Integer => SimpleType::Integer, - Builtin::Double => SimpleType::Double, - Builtin::Text => SimpleType::Text, - _ => unreachable!(), - }, - 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) => SimpleType::Union( - kts.iter() - .map(|(k, v)| { - Some(( - k.into(), - v.as_ref() - .map(|v| Ok(Self::from_nir(v)?)) - .transpose()?, - )) - }) - .collect::>()?, - ), - _ => return None, - }) - } - - pub(crate) fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: None, - as_simple_ty: Some(self.clone()), - } - } - pub(crate) fn to_hir(&self) -> Hir { - let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); - 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(), - ), - SimpleType::List(t) => { - ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) - } - SimpleType::Record(kts) => ExprKind::RecordType( - kts.into_iter() - .map(|(k, t)| (k.as_str().into(), t.to_hir())) - .collect(), - ), - SimpleType::Union(kts) => ExprKind::UnionType( - kts.into_iter() - .map(|(k, t)| { - (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) - }) - .collect(), - ), - }) - } -} - -impl Sealed for SimpleValue {} - -impl Deserialize for SimpleValue { - fn from_dhall(v: &Value) -> Result { - v.to_simple_value().ok_or_else(|| { - Error::Deserialize(format!( - "this cannot be deserialized into a simple type: {}", - v - )) - }) - } -} - -impl Sealed for SimpleType {} - -impl Deserialize for SimpleType { - fn from_dhall(v: &Value) -> Result { - v.to_simple_type().ok_or_else(|| { - Error::Deserialize(format!( - "this cannot be deserialized into a simple type: {}", - v - )) - }) - } -} diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index 88727bc..f542f0a 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -1,19 +1,101 @@ -use dhall::semantics::{Hir, Nir}; -use dhall::syntax::Expr; +use std::collections::{BTreeMap, HashMap}; -use crate::simple::{SimpleType, SimpleValue}; -use crate::{Deserialize, Error, Sealed}; +use dhall::semantics::{Hir, HirKind, Nir, NirKind}; +use dhall::syntax::{Builtin, Expr, ExprKind, NumKind, Span}; + +use crate::{Deserialize, Error, Result, Sealed}; #[doc(hidden)] /// An arbitrary Dhall value. #[derive(Debug, Clone)] pub struct Value { /// Invariant: in normal form - pub(crate) hir: Hir, + hir: Hir, /// Cached conversions because they are annoying to construct from Hir. /// At most one of them will be `Some`. - pub(crate) as_simple_val: Option, - pub(crate) as_simple_ty: Option, + as_simple_val: Option, + as_simple_ty: Option, +} + +/// A simple value of the kind that can be decoded with serde +#[derive(Debug, Clone, PartialEq, Eq)] +pub(crate) enum SimpleValue { + Num(NumKind), + Text(String), + Optional(Option>), + List(Vec), + Record(BTreeMap), + Union(String, Option>), +} + +/// 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 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, + /// 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 { @@ -25,6 +107,10 @@ impl Value { } } + pub(crate) fn as_hir(&self) -> &Hir { + &self.hir + } + /// Converts a Value into a SimpleValue. pub(crate) fn to_simple_value(&self) -> Option { self.as_simple_val.clone() @@ -41,22 +127,158 @@ impl Value { } } -impl Eq for Value {} -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - self.hir == other.hir +impl SimpleValue { + pub(crate) fn from_nir(nir: &Nir) -> Option { + Some(match nir.kind() { + NirKind::Num(lit) => SimpleValue::Num(lit.clone()), + NirKind::TextLit(x) => SimpleValue::Text( + x.as_text() + .expect("Normal form should ensure the text is a string"), + ), + NirKind::EmptyOptionalLit(_) => SimpleValue::Optional(None), + NirKind::NEOptionalLit(x) => { + SimpleValue::Optional(Some(Box::new(Self::from_nir(x)?))) + } + NirKind::EmptyListLit(_) => SimpleValue::List(vec![]), + NirKind::NEListLit(xs) => SimpleValue::List( + xs.iter().map(Self::from_nir).collect::>()?, + ), + NirKind::RecordLit(kvs) => SimpleValue::Record( + kvs.iter() + .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .collect::>()?, + ), + NirKind::UnionLit(field, x, _) => SimpleValue::Union( + field.into(), + Some(Box::new(Self::from_nir(x)?)), + ), + NirKind::UnionConstructor(field, ty) + if ty.get(field).map(|f| f.is_some()) == Some(false) => + { + SimpleValue::Union(field.into(), None) + } + _ => return None, + }) } } -impl std::fmt::Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.to_expr().fmt(f) + +impl SimpleType { + pub(crate) fn from_nir(nir: &Nir) -> Option { + Some(match nir.kind() { + NirKind::BuiltinType(b) => match b { + Builtin::Bool => SimpleType::Bool, + Builtin::Natural => SimpleType::Natural, + Builtin::Integer => SimpleType::Integer, + Builtin::Double => SimpleType::Double, + Builtin::Text => SimpleType::Text, + _ => unreachable!(), + }, + 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) => SimpleType::Union( + kts.iter() + .map(|(k, v)| { + Some(( + k.into(), + v.as_ref() + .map(|v| Ok(Self::from_nir(v)?)) + .transpose()?, + )) + }) + .collect::>()?, + ), + _ => return None, + }) + } + + pub(crate) fn to_value(&self) -> Value { + Value { + hir: self.to_hir(), + as_simple_val: None, + as_simple_ty: Some(self.clone()), + } + } + pub(crate) fn to_hir(&self) -> Hir { + let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); + 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(), + ), + SimpleType::List(t) => { + ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) + } + SimpleType::Record(kts) => ExprKind::RecordType( + kts.into_iter() + .map(|(k, t)| (k.as_str().into(), t.to_hir())) + .collect(), + ), + SimpleType::Union(kts) => ExprKind::UnionType( + kts.into_iter() + .map(|(k, t)| { + (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) + }) + .collect(), + ), + }) } } impl Sealed for Value {} +impl Sealed for SimpleValue {} +impl Sealed for SimpleType {} impl Deserialize for Value { - fn from_dhall(v: &Value) -> Result { + fn from_dhall(v: &Value) -> Result { Ok(v.clone()) } } +impl Deserialize for SimpleValue { + fn from_dhall(v: &Value) -> Result { + v.to_simple_value().ok_or_else(|| { + Error::Deserialize(format!( + "this cannot be deserialized into a simple type: {}", + v + )) + }) + } +} +impl Deserialize for SimpleType { + fn from_dhall(v: &Value) -> Result { + v.to_simple_type().ok_or_else(|| { + Error::Deserialize(format!( + "this cannot be deserialized into a simple type: {}", + v + )) + }) + } +} + +impl Eq for Value {} +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + self.hir == other.hir + } +} +impl std::fmt::Display for Value { + fn fmt( + &self, + f: &mut std::fmt::Formatter, + ) -> std::result::Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} -- cgit v1.2.3