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/src/serde.rs | 102 ++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 67 deletions(-) (limited to 'serde_dhall/src/serde.rs') diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 4fd7815..9cb67d1 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -4,25 +4,31 @@ use serde::de::value::{ MapAccessDeserializer, MapDeserializer, SeqDeserializer, }; -use dhall::syntax::{ExprKind, LitKind}; -use dhall::NormalizedExpr; +use dhall::syntax::LitKind; +use dhall::{SValKind, SimpleValue}; use crate::de::{Deserialize, Error, Result}; use crate::Value; impl<'a, T> crate::de::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 { - T::deserialize(Deserializer(Cow::Owned(v.to_expr()))) + let sval = v.to_simple_value().map_err(|expr| { + Error::Deserialize(format!( + "this cannot be deserialized into the serde data model: {}", + expr + )) + })?; + T::deserialize(Deserializer(Cow::Owned(sval))) } } -struct Deserializer<'a>(Cow<'a, NormalizedExpr>); - impl<'de: 'a, 'a> serde::de::IntoDeserializer<'de, Error> for Deserializer<'a> { type Deserializer = Deserializer<'a>; fn into_deserializer(self) -> Self::Deserializer { @@ -38,17 +44,11 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { V: serde::de::Visitor<'de>, { use std::convert::TryInto; - use ExprKind::*; use LitKind::*; - let expr = self.0.as_ref(); - let not_serde_compatible = || { - Err(Error::Deserialize(format!( - "this cannot be deserialized into the serde data model: {}", - expr - ))) - }; + use SValKind::*; - match expr.kind() { + let val = |x| Deserializer(Cow::Borrowed(x)); + match self.0.kind() { Lit(Bool(x)) => visitor.visit_bool(*x), Lit(Natural(x)) => { if let Ok(x64) = (*x).try_into() { @@ -69,54 +69,25 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { } } Lit(Double(x)) => visitor.visit_f64((*x).into()), - TextLit(x) => { - // Normal form ensures that the tail is empty. - assert!(x.tail().is_empty()); - visitor.visit_str(x.head()) + Text(x) => visitor.visit_str(x), + List(xs) => { + visitor.visit_seq(SeqDeserializer::new(xs.iter().map(val))) } - EmptyListLit(..) => { - visitor.visit_seq(SeqDeserializer::new(None::<()>.into_iter())) - } - NEListLit(xs) => visitor.visit_seq(SeqDeserializer::new( - xs.iter().map(|x| Deserializer(Cow::Borrowed(x))), + 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))), )), - SomeLit(x) => visitor.visit_some(Deserializer(Cow::Borrowed(x))), - App(f, x) => match f.kind() { - Builtin(dhall::syntax::Builtin::OptionalNone) => { - visitor.visit_none() - } - Field(y, name) => match y.kind() { - UnionType(..) => { - let name: String = name.into(); - visitor.visit_enum(MapAccessDeserializer::new( - MapDeserializer::new( - Some((name, Deserializer(Cow::Borrowed(x)))) - .into_iter(), - ), - )) - } - _ => not_serde_compatible(), - }, - _ => not_serde_compatible(), - }, - RecordLit(m) => visitor - .visit_map(MapDeserializer::new(m.iter().map(|(k, v)| { - (k.as_ref(), Deserializer(Cow::Borrowed(v))) - }))), - Field(y, name) => match y.kind() { - UnionType(..) => { - let name: String = name.into(); - visitor.visit_enum(MapAccessDeserializer::new( - MapDeserializer::new(Some((name, ())).into_iter()), - )) - } - _ => not_serde_compatible(), - }, - Const(..) | Var(..) | Lam(..) | Pi(..) | Let(..) | Annot(..) - | Assert(..) | Builtin(..) | BinOp(..) | BoolIf(..) - | RecordType(..) | UnionType(..) | Merge(..) | ToMap(..) - | Projection(..) | ProjectionByExpr(..) | Completion(..) - | Import(..) => not_serde_compatible(), + 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(), + )), + ), } } @@ -124,14 +95,11 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { where V: serde::de::Visitor<'de>, { - use ExprKind::*; - let expr = self.0.as_ref(); - - match expr.kind() { + let val = |x| Deserializer(Cow::Borrowed(x)); + match self.0.kind() { // Blindly takes keys in sorted order. - RecordLit(m) => visitor.visit_seq(SeqDeserializer::new( - m.iter().map(|(_, v)| Deserializer(Cow::Borrowed(v))), - )), + SValKind::Record(m) => visitor + .visit_seq(SeqDeserializer::new(m.iter().map(|(_, v)| val(v)))), _ => self.deserialize_any(visitor), } } -- cgit v1.3.1 From 60425d58151fef142b066d523dc4d5e832070b9c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 13 Mar 2020 14:30:15 +0000 Subject: Add new Value type in API --- dhall/src/lib.rs | 64 +++++++++++++++++++++++++++++++++--- dhall/src/semantics/tck/typecheck.rs | 4 +-- serde_dhall/src/lib.rs | 47 +++++++++++++------------- serde_dhall/src/serde.rs | 4 +-- 4 files changed, 86 insertions(+), 33 deletions(-) (limited to 'serde_dhall/src/serde.rs') diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 25196ba..60b7a0e 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -49,11 +49,18 @@ pub struct Typed { } /// A normalized expression. -/// -/// Invariant: the contained expression must be in normal form, #[derive(Debug, Clone)] pub struct Normalized(Nir); +/// A Dhall value. +#[derive(Debug, Clone)] +pub struct Value { + /// Invariant: in normal form + pub(crate) hir: Hir, + simple_val: Option, + simple_ty: Option, +} + /// Controls conversion from `Nir` to `Expr` #[derive(Copy, Clone, Default)] pub(crate) struct ToExprOptions { @@ -99,8 +106,8 @@ impl Resolved { pub fn typecheck(&self) -> Result { Ok(Typed::from_tir(typecheck(&self.0)?)) } - pub fn typecheck_with(self, ty: &Normalized) -> Result { - Ok(Typed::from_tir(typecheck_with(&self.0, ty.to_hir())?)) + pub(crate) fn typecheck_with(self, ty: &Hir) -> Result { + Ok(Typed::from_tir(typecheck_with(&self.0, ty)?)) } /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self) -> ResolvedExpr { @@ -137,6 +144,13 @@ impl Normalized { pub fn encode(&self) -> Result, EncodeError> { binary::encode(&self.to_expr()) } + pub fn to_value(&self) -> Value { + Value { + hir: self.to_hir(), + simple_val: self.0.to_simple_value(), + simple_ty: self.0.to_simple_type(), + } + } /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self) -> NormalizedExpr { @@ -200,6 +214,36 @@ impl Normalized { } } +impl Value { + /// Parse a string into a Value, and optionally ensure that the value matches the provided type + /// annotation. + pub fn from_str_with_annot( + s: &str, + ty: Option<&Self>, + ) -> Result { + let resolved = Parsed::parse_str(s)?.resolve()?; + let typed = match ty { + None => resolved.typecheck()?, + Some(ty) => resolved.typecheck_with(&ty.hir)?, + }; + Ok(typed.normalize().to_value()) + } + + /// Converts a Value into a SimpleValue. + pub fn to_simple_value(&self) -> Option { + self.simple_val.clone() + } + /// Converts a Value into a SimpleType. + pub fn to_simple_type(&self) -> Option { + self.simple_ty.clone() + } + + /// Converts a value back to the corresponding AST expression. + pub(crate) fn to_expr(&self) -> NormalizedExpr { + self.hir.to_expr(ToExprOptions::default()) + } +} + macro_rules! derive_traits_for_wrapper_struct { ($ty:ident) => { impl std::cmp::PartialEq for $ty { @@ -274,3 +318,15 @@ impl Display for Normalized { self.to_expr().fmt(f) } } + +impl Eq for Value {} +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + self.hir == other.hir + } +} +impl Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 173b76d..9fa33f2 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -808,8 +808,8 @@ pub(crate) fn typecheck<'hir>(hir: &'hir Hir) -> Result, TypeError> { /// Like `typecheck`, but additionally checks that the expression's type matches the provided type. pub(crate) fn typecheck_with<'hir>( hir: &'hir Hir, - ty: Hir, + ty: &Hir, ) -> Result, TypeError> { - let ty = typecheck(&ty)?.eval_to_type(&TyEnv::new())?; + let ty = typecheck(ty)?.eval_to_type(&TyEnv::new())?; type_with(&TyEnv::new(), hir, Some(ty)) } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index d019238..1f7ecf8 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -183,38 +183,26 @@ pub use value::Value; // A Dhall value. #[doc(hidden)] pub mod value { - use dhall::{Normalized, NormalizedExpr, Parsed, SimpleType, SimpleValue}; + use dhall::{SimpleType, SimpleValue}; use super::de::Error; use super::Type; /// A Dhall value #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Value(pub(crate) Normalized); + pub struct Value(pub(crate) dhall::Value); impl Value { 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) + let ty = ty.map(|t| t.to_dhall_value()); + let val = dhall::Value::from_str_with_annot(s, ty.as_ref()) + .map_err(Error::Dhall)?; + Ok(Value(val)) } - 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.to_normalized())?, - }; - Ok(Value(typed.normalize())) - } - pub(crate) fn to_simple_value( - &self, - ) -> Result { + pub(crate) fn to_simple_value(&self) -> Option { self.0.to_simple_value() } - pub(crate) fn to_simple_type( - &self, - ) -> Result { + pub(crate) fn to_simple_type(&self) -> Option { self.0.to_simple_type() } } @@ -226,12 +214,21 @@ pub mod value { Ok(v.clone()) } } + + impl std::fmt::Display for Value { + fn fmt( + &self, + f: &mut std::fmt::Formatter, + ) -> Result<(), std::fmt::Error> { + self.0.fmt(f) + } + } } // A Dhall type. #[doc(hidden)] pub mod ty { - use dhall::{Normalized, STyKind, SimpleType}; + use dhall::{STyKind, SimpleType}; use super::de::Error; @@ -240,8 +237,8 @@ pub mod ty { pub struct Type(SimpleType); impl Type { - pub(crate) fn to_normalized(&self) -> Normalized { - self.0.clone().into_normalized() + pub(crate) fn to_dhall_value(&self) -> dhall::Value { + self.0.clone().into_normalized().to_value() } pub(crate) fn from_simple_type(ty: SimpleType) -> Self { @@ -279,10 +276,10 @@ pub mod ty { impl super::de::Deserialize for Type { fn from_dhall(v: &super::Value) -> super::de::Result { - let sty = v.to_simple_type().map_err(|expr| { + let sty = v.to_simple_type().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", - expr + v )) })?; Ok(Type(sty)) diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 9cb67d1..5d8fcf3 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -19,10 +19,10 @@ where T: serde::Deserialize<'a>, { fn from_dhall(v: &Value) -> Result { - let sval = v.to_simple_value().map_err(|expr| { + let sval = v.to_simple_value().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into the serde data model: {}", - expr + v )) })?; T::deserialize(Deserializer(Cow::Owned(sval))) -- cgit v1.3.1 From 2f5c45fd2f712f7befe6f7c92b62dc76d5f77538 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 13 Mar 2020 16:50:49 +0000 Subject: Rename LitKind to NumKind --- dhall/src/semantics/builtins.rs | 54 ++++++++++++++-------------- dhall/src/semantics/nze/nir.rs | 10 +++--- dhall/src/semantics/nze/normalize.rs | 70 ++++++++++++++++++------------------ dhall/src/semantics/tck/typecheck.rs | 10 +++--- dhall/src/simple.rs | 4 +-- dhall/src/syntax/ast/expr.rs | 6 ++-- dhall/src/syntax/ast/visitor.rs | 2 +- dhall/src/syntax/binary/decode.rs | 16 ++++----- dhall/src/syntax/binary/encode.rs | 10 +++--- dhall/src/syntax/text/parser.rs | 14 ++++---- dhall/src/syntax/text/printer.rs | 6 ++-- serde_dhall/src/serde.rs | 12 +++---- 12 files changed, 107 insertions(+), 107 deletions(-) (limited to 'serde_dhall/src/serde.rs') diff --git a/dhall/src/semantics/builtins.rs b/dhall/src/semantics/builtins.rs index 803630b..8d17aed 100644 --- a/dhall/src/semantics/builtins.rs +++ b/dhall/src/semantics/builtins.rs @@ -5,7 +5,7 @@ use crate::syntax::map::DupTreeMap; use crate::syntax::Const::Type; use crate::syntax::{ BinOp, Builtin, Const, Expr, ExprKind, InterpolatedText, - InterpolatedTextContents, Label, LitKind, NaiveDouble, Span, UnspannedExpr, + InterpolatedTextContents, Label, NaiveDouble, NumKind, Span, UnspannedExpr, V, }; use crate::Normalized; @@ -241,7 +241,7 @@ macro_rules! make_closure { rc(ExprKind::BinOp( BinOp::NaturalPlus, make_closure!($($v)*), - rc(ExprKind::Lit(LitKind::Natural(1))) + rc(ExprKind::Num(NumKind::Natural(1))) )) }; ([ $($head:tt)* ] # $($tail:tt)*) => {{ @@ -257,8 +257,8 @@ macro_rules! make_closure { #[allow(clippy::cognitive_complexity)] fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { - use LitKind::{Bool, Double, Integer, Natural}; use NirKind::*; + use NumKind::{Bool, Double, Integer, Natural}; // Small helper enum enum Ret { @@ -277,36 +277,36 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { Ret::NirKind(EmptyOptionalLit(t.clone())) } (Builtin::NaturalIsZero, [n]) => match &*n.kind() { - Lit(Natural(n)) => Ret::NirKind(Lit(Bool(*n == 0))), + Num(Natural(n)) => Ret::NirKind(Num(Bool(*n == 0))), _ => Ret::DoneAsIs, }, (Builtin::NaturalEven, [n]) => match &*n.kind() { - Lit(Natural(n)) => Ret::NirKind(Lit(Bool(*n % 2 == 0))), + Num(Natural(n)) => Ret::NirKind(Num(Bool(*n % 2 == 0))), _ => Ret::DoneAsIs, }, (Builtin::NaturalOdd, [n]) => match &*n.kind() { - Lit(Natural(n)) => Ret::NirKind(Lit(Bool(*n % 2 != 0))), + Num(Natural(n)) => Ret::NirKind(Num(Bool(*n % 2 != 0))), _ => Ret::DoneAsIs, }, (Builtin::NaturalToInteger, [n]) => match &*n.kind() { - Lit(Natural(n)) => Ret::NirKind(Lit(Integer(*n as isize))), + Num(Natural(n)) => Ret::NirKind(Num(Integer(*n as isize))), _ => Ret::DoneAsIs, }, (Builtin::NaturalShow, [n]) => match &*n.kind() { - Lit(Natural(n)) => Ret::Nir(Nir::from_text(n)), + Num(Natural(n)) => Ret::Nir(Nir::from_text(n)), _ => Ret::DoneAsIs, }, (Builtin::NaturalSubtract, [a, b]) => match (&*a.kind(), &*b.kind()) { - (Lit(Natural(a)), Lit(Natural(b))) => { - Ret::NirKind(Lit(Natural(if b > a { b - a } else { 0 }))) + (Num(Natural(a)), Num(Natural(b))) => { + Ret::NirKind(Num(Natural(if b > a { b - a } else { 0 }))) } - (Lit(Natural(0)), _) => Ret::Nir(b.clone()), - (_, Lit(Natural(0))) => Ret::NirKind(Lit(Natural(0))), - _ if a == b => Ret::NirKind(Lit(Natural(0))), + (Num(Natural(0)), _) => Ret::Nir(b.clone()), + (_, Num(Natural(0))) => Ret::NirKind(Num(Natural(0))), + _ if a == b => Ret::NirKind(Num(Natural(0))), _ => Ret::DoneAsIs, }, (Builtin::IntegerShow, [n]) => match &*n.kind() { - Lit(Integer(n)) => { + Num(Integer(n)) => { let s = if *n < 0 { n.to_string() } else { @@ -317,23 +317,23 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { _ => Ret::DoneAsIs, }, (Builtin::IntegerToDouble, [n]) => match &*n.kind() { - Lit(Integer(n)) => { - Ret::NirKind(Lit(Double(NaiveDouble::from(*n as f64)))) + Num(Integer(n)) => { + Ret::NirKind(Num(Double(NaiveDouble::from(*n as f64)))) } _ => Ret::DoneAsIs, }, (Builtin::IntegerNegate, [n]) => match &*n.kind() { - Lit(Integer(n)) => Ret::NirKind(Lit(Integer(-n))), + Num(Integer(n)) => Ret::NirKind(Num(Integer(-n))), _ => Ret::DoneAsIs, }, (Builtin::IntegerClamp, [n]) => match &*n.kind() { - Lit(Integer(n)) => { - Ret::NirKind(Lit(Natural((*n).try_into().unwrap_or(0)))) + Num(Integer(n)) => { + Ret::NirKind(Num(Natural((*n).try_into().unwrap_or(0)))) } _ => Ret::DoneAsIs, }, (Builtin::DoubleShow, [n]) => match &*n.kind() { - Lit(Double(n)) => Ret::Nir(Nir::from_text(n)), + Num(Double(n)) => Ret::Nir(Nir::from_text(n)), _ => Ret::DoneAsIs, }, (Builtin::TextShow, [v]) => match &*v.kind() { @@ -351,8 +351,8 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { _ => Ret::DoneAsIs, }, (Builtin::ListLength, [_, l]) => match &*l.kind() { - EmptyListLit(_) => Ret::NirKind(Lit(Natural(0))), - NEListLit(xs) => Ret::NirKind(Lit(Natural(xs.len()))), + EmptyListLit(_) => Ret::NirKind(Num(Natural(0))), + NEListLit(xs) => Ret::NirKind(Num(Natural(xs.len()))), _ => Ret::DoneAsIs, }, (Builtin::ListHead, [_, l]) => match &*l.kind() { @@ -398,7 +398,7 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { let mut kvs = HashMap::new(); kvs.insert( "index".into(), - Nir::from_kind(Lit(Natural(i))), + Nir::from_kind(Num(Natural(i))), ); kvs.insert("value".into(), e.clone()); Nir::from_kind(RecordLit(kvs)) @@ -466,14 +466,14 @@ fn apply_builtin(b: Builtin, args: Vec, env: NzEnv) -> NirKind { λ(x : Natural) -> 1 + var(x) ))) - .app(Lit(Natural(0)).into_nir()), + .app(Num(Natural(0)).into_nir()), ), (Builtin::NaturalFold, [n, t, succ, zero]) => match &*n.kind() { - Lit(Natural(0)) => Ret::Nir(zero.clone()), - Lit(Natural(n)) => { + Num(Natural(0)) => Ret::Nir(zero.clone()), + Num(Natural(n)) => { let fold = Nir::from_builtin(Builtin::NaturalFold) - .app(Lit(Natural(n - 1)).into_nir()) + .app(Num(Natural(n - 1)).into_nir()) .app(t.clone()) .app(succ.clone()) .app(zero.clone()); diff --git a/dhall/src/semantics/nze/nir.rs b/dhall/src/semantics/nze/nir.rs index 4615b39..6f482a8 100644 --- a/dhall/src/semantics/nze/nir.rs +++ b/dhall/src/semantics/nze/nir.rs @@ -7,7 +7,7 @@ use crate::semantics::{ BuiltinClosure, Hir, HirKind, NzEnv, NzVar, TyEnv, Type, Universe, VarEnv, }; use crate::syntax::{ - BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, LitKind, + BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, Label, NumKind, Span, }; use crate::{NormalizedExpr, ToExprOptions}; @@ -75,7 +75,7 @@ pub(crate) enum NirKind { Var(NzVar), Const(Const), - Lit(LitKind), + Num(NumKind), EmptyOptionalLit(Nir), NEOptionalLit(Nir), // EmptyListLit(t) means `[] : List t`, not `[] : t` @@ -145,7 +145,7 @@ impl Nir { } pub(crate) fn to_simple_value(&self) -> Option { Some(SimpleValue::new(match self.kind() { - NirKind::Lit(lit) => SValKind::Lit(lit.clone()), + NirKind::Num(lit) => SValKind::Num(lit.clone()), NirKind::TextLit(x) => SValKind::Text( x.as_text() .expect("Normal form should ensure the text is a string"), @@ -268,7 +268,7 @@ impl Nir { closure.to_hir(venv), ), NirKind::Const(c) => ExprKind::Const(*c), - NirKind::Lit(l) => ExprKind::Lit(l.clone()), + NirKind::Num(l) => ExprKind::Num(l.clone()), NirKind::EmptyOptionalLit(n) => ExprKind::App( Nir::from_builtin(Builtin::OptionalNone).to_hir(venv), n.to_hir(venv), @@ -366,7 +366,7 @@ impl NirKind { pub(crate) fn normalize(&self) { match self { - NirKind::Var(..) | NirKind::Const(_) | NirKind::Lit(_) => {} + NirKind::Var(..) | NirKind::Const(_) | NirKind::Num(_) => {} NirKind::EmptyOptionalLit(tth) | NirKind::EmptyListLit(tth) => { tth.normalize(); diff --git a/dhall/src/semantics/nze/normalize.rs b/dhall/src/semantics/nze/normalize.rs index 79d55e8..c5e66a1 100644 --- a/dhall/src/semantics/nze/normalize.rs +++ b/dhall/src/semantics/nze/normalize.rs @@ -6,7 +6,7 @@ use crate::semantics::{ Binder, BuiltinClosure, Closure, Hir, HirKind, Nir, NirKind, TextLit, }; use crate::syntax::{ - BinOp, Builtin, ExprKind, InterpolatedTextContents, LitKind, + BinOp, Builtin, ExprKind, InterpolatedTextContents, NumKind, }; pub(crate) fn apply_any(f: Nir, a: Nir) -> NirKind { @@ -99,40 +99,40 @@ fn apply_binop<'a>(o: BinOp, x: &'a Nir, y: &'a Nir) -> Option> { NaturalTimes, RecursiveRecordMerge, RecursiveRecordTypeMerge, RightBiasedRecordMerge, TextAppend, }; - use LitKind::{Bool, Natural}; - use NirKind::{EmptyListLit, Lit, NEListLit, RecordLit, RecordType}; + use NirKind::{EmptyListLit, NEListLit, Num, RecordLit, RecordType}; + use NumKind::{Bool, Natural}; Some(match (o, x.kind(), y.kind()) { - (BoolAnd, Lit(Bool(true)), _) => Ret::NirRef(y), - (BoolAnd, _, Lit(Bool(true))) => Ret::NirRef(x), - (BoolAnd, Lit(Bool(false)), _) => Ret::NirKind(Lit(Bool(false))), - (BoolAnd, _, Lit(Bool(false))) => Ret::NirKind(Lit(Bool(false))), + (BoolAnd, Num(Bool(true)), _) => Ret::NirRef(y), + (BoolAnd, _, Num(Bool(true))) => Ret::NirRef(x), + (BoolAnd, Num(Bool(false)), _) => Ret::NirKind(Num(Bool(false))), + (BoolAnd, _, Num(Bool(false))) => Ret::NirKind(Num(Bool(false))), (BoolAnd, _, _) if x == y => Ret::NirRef(x), - (BoolOr, Lit(Bool(true)), _) => Ret::NirKind(Lit(Bool(true))), - (BoolOr, _, Lit(Bool(true))) => Ret::NirKind(Lit(Bool(true))), - (BoolOr, Lit(Bool(false)), _) => Ret::NirRef(y), - (BoolOr, _, Lit(Bool(false))) => Ret::NirRef(x), + (BoolOr, Num(Bool(true)), _) => Ret::NirKind(Num(Bool(true))), + (BoolOr, _, Num(Bool(true))) => Ret::NirKind(Num(Bool(true))), + (BoolOr, Num(Bool(false)), _) => Ret::NirRef(y), + (BoolOr, _, Num(Bool(false))) => Ret::NirRef(x), (BoolOr, _, _) if x == y => Ret::NirRef(x), - (BoolEQ, Lit(Bool(true)), _) => Ret::NirRef(y), - (BoolEQ, _, Lit(Bool(true))) => Ret::NirRef(x), - (BoolEQ, Lit(Bool(x)), Lit(Bool(y))) => Ret::NirKind(Lit(Bool(x == y))), - (BoolEQ, _, _) if x == y => Ret::NirKind(Lit(Bool(true))), - (BoolNE, Lit(Bool(false)), _) => Ret::NirRef(y), - (BoolNE, _, Lit(Bool(false))) => Ret::NirRef(x), - (BoolNE, Lit(Bool(x)), Lit(Bool(y))) => Ret::NirKind(Lit(Bool(x != y))), - (BoolNE, _, _) if x == y => Ret::NirKind(Lit(Bool(false))), + (BoolEQ, Num(Bool(true)), _) => Ret::NirRef(y), + (BoolEQ, _, Num(Bool(true))) => Ret::NirRef(x), + (BoolEQ, Num(Bool(x)), Num(Bool(y))) => Ret::NirKind(Num(Bool(x == y))), + (BoolEQ, _, _) if x == y => Ret::NirKind(Num(Bool(true))), + (BoolNE, Num(Bool(false)), _) => Ret::NirRef(y), + (BoolNE, _, Num(Bool(false))) => Ret::NirRef(x), + (BoolNE, Num(Bool(x)), Num(Bool(y))) => Ret::NirKind(Num(Bool(x != y))), + (BoolNE, _, _) if x == y => Ret::NirKind(Num(Bool(false))), - (NaturalPlus, Lit(Natural(0)), _) => Ret::NirRef(y), - (NaturalPlus, _, Lit(Natural(0))) => Ret::NirRef(x), - (NaturalPlus, Lit(Natural(x)), Lit(Natural(y))) => { - Ret::NirKind(Lit(Natural(x + y))) + (NaturalPlus, Num(Natural(0)), _) => Ret::NirRef(y), + (NaturalPlus, _, Num(Natural(0))) => Ret::NirRef(x), + (NaturalPlus, Num(Natural(x)), Num(Natural(y))) => { + Ret::NirKind(Num(Natural(x + y))) } - (NaturalTimes, Lit(Natural(0)), _) => Ret::NirKind(Lit(Natural(0))), - (NaturalTimes, _, Lit(Natural(0))) => Ret::NirKind(Lit(Natural(0))), - (NaturalTimes, Lit(Natural(1)), _) => Ret::NirRef(y), - (NaturalTimes, _, Lit(Natural(1))) => Ret::NirRef(x), - (NaturalTimes, Lit(Natural(x)), Lit(Natural(y))) => { - Ret::NirKind(Lit(Natural(x * y))) + (NaturalTimes, Num(Natural(0)), _) => Ret::NirKind(Num(Natural(0))), + (NaturalTimes, _, Num(Natural(0))) => Ret::NirKind(Num(Natural(0))), + (NaturalTimes, Num(Natural(1)), _) => Ret::NirRef(y), + (NaturalTimes, _, Num(Natural(1))) => Ret::NirRef(x), + (NaturalTimes, Num(Natural(x)), Num(Natural(y))) => { + Ret::NirKind(Num(Natural(x * y))) } (ListAppend, EmptyListLit(_), _) => Ret::NirRef(y), @@ -212,12 +212,12 @@ fn apply_binop<'a>(o: BinOp, x: &'a Nir, y: &'a Nir) -> Option> { #[allow(clippy::cognitive_complexity)] pub(crate) fn normalize_one_layer(expr: ExprKind, env: &NzEnv) -> NirKind { - use LitKind::Bool; use NirKind::{ - EmptyListLit, EmptyOptionalLit, Lit, NEListLit, NEOptionalLit, + EmptyListLit, EmptyOptionalLit, NEListLit, NEOptionalLit, Num, PartialExpr, RecordLit, RecordType, UnionConstructor, UnionLit, UnionType, }; + use NumKind::Bool; let ret = match expr { ExprKind::Import(..) | ExprKind::Completion(..) => { @@ -235,7 +235,7 @@ pub(crate) fn normalize_one_layer(expr: ExprKind, env: &NzEnv) -> NirKind { ExprKind::Builtin(b) => Ret::Nir(Nir::from_builtin_env(b, env)), ExprKind::Assert(_) => Ret::Expr(expr), ExprKind::App(v, a) => Ret::Nir(v.app(a)), - ExprKind::Lit(l) => Ret::NirKind(Lit(l)), + ExprKind::Num(l) => Ret::NirKind(Num(l)), ExprKind::SomeLit(e) => Ret::NirKind(NEOptionalLit(e)), ExprKind::EmptyListLit(t) => { let arg = match t.kind() { @@ -271,12 +271,12 @@ pub(crate) fn normalize_one_layer(expr: ExprKind, env: &NzEnv) -> NirKind { } ExprKind::BoolIf(ref b, ref e1, ref e2) => { match b.kind() { - Lit(Bool(true)) => Ret::NirRef(e1), - Lit(Bool(false)) => Ret::NirRef(e2), + Num(Bool(true)) => Ret::NirRef(e1), + Num(Bool(false)) => Ret::NirRef(e2), _ => { match (e1.kind(), e2.kind()) { // Simplify `if b then True else False` - (Lit(Bool(true)), Lit(Bool(false))) => Ret::NirRef(b), + (Num(Bool(true)), Num(Bool(false))) => Ret::NirRef(b), _ if e1 == e2 => Ret::NirRef(e1), _ => Ret::Expr(expr), } diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 9fa33f2..6951d62 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -9,7 +9,7 @@ use crate::semantics::{ NirKind, Tir, TyEnv, Type, }; use crate::syntax::{ - BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, LitKind, Span, + BinOp, Builtin, Const, ExprKind, InterpolatedTextContents, NumKind, Span, }; fn check_rectymerge( @@ -96,14 +96,14 @@ fn type_one_layer( let t_hir = type_of_builtin(*b); typecheck(&t_hir)?.eval_to_type(env)? } - ExprKind::Lit(LitKind::Bool(_)) => Type::from_builtin(Builtin::Bool), - ExprKind::Lit(LitKind::Natural(_)) => { + ExprKind::Num(NumKind::Bool(_)) => Type::from_builtin(Builtin::Bool), + ExprKind::Num(NumKind::Natural(_)) => { Type::from_builtin(Builtin::Natural) } - ExprKind::Lit(LitKind::Integer(_)) => { + ExprKind::Num(NumKind::Integer(_)) => { Type::from_builtin(Builtin::Integer) } - ExprKind::Lit(LitKind::Double(_)) => { + ExprKind::Num(NumKind::Double(_)) => { Type::from_builtin(Builtin::Double) } ExprKind::TextLit(interpolated) => { diff --git a/dhall/src/simple.rs b/dhall/src/simple.rs index 7e7e459..9c4d6ba 100644 --- a/dhall/src/simple.rs +++ b/dhall/src/simple.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use crate::semantics::{Hir, HirKind}; -use crate::syntax::{Builtin, ExprKind, LitKind, Span}; +use crate::syntax::{Builtin, ExprKind, NumKind, Span}; use crate::Value; #[derive(Debug, Clone, PartialEq, Eq)] @@ -11,7 +11,7 @@ pub struct SimpleValue { #[derive(Debug, Clone, PartialEq, Eq)] pub enum SValKind { - Lit(LitKind), + Num(NumKind), Optional(Option), List(Vec), Record(BTreeMap), diff --git a/dhall/src/syntax/ast/expr.rs b/dhall/src/syntax/ast/expr.rs index b53e6cb..2c1860e 100644 --- a/dhall/src/syntax/ast/expr.rs +++ b/dhall/src/syntax/ast/expr.rs @@ -112,9 +112,9 @@ pub struct Expr { pub type UnspannedExpr = ExprKind; -/// Simple literals +/// Numeric literals #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum LitKind { +pub enum NumKind { /// `True` Bool(bool), /// `1` @@ -132,7 +132,7 @@ pub enum LitKind { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ExprKind { Const(Const), - Lit(LitKind), + Num(NumKind), /// `x` /// `x@n` Var(V), diff --git a/dhall/src/syntax/ast/visitor.rs b/dhall/src/syntax/ast/visitor.rs index c361bc1..0743af4 100644 --- a/dhall/src/syntax/ast/visitor.rs +++ b/dhall/src/syntax/ast/visitor.rs @@ -91,7 +91,7 @@ where Annot(x, t) => Annot(expr!(x)?, expr!(t)?), Const(k) => Const(*k), Builtin(v) => Builtin(*v), - Lit(l) => Lit(l.clone()), + Num(n) => Num(n.clone()), TextLit(t) => TextLit(t.traverse_ref(|e| expr!(e))?), BinOp(o, x, y) => BinOp(*o, expr!(x)?, expr!(y)?), BoolIf(b, t, f) => BoolIf(expr!(b)?, expr!(t)?, expr!(f)?), diff --git a/dhall/src/syntax/binary/decode.rs b/dhall/src/syntax/binary/decode.rs index 2ecd7e0..05d5921 100644 --- a/dhall/src/syntax/binary/decode.rs +++ b/dhall/src/syntax/binary/decode.rs @@ -6,7 +6,7 @@ use crate::error::DecodeError; use crate::syntax; use crate::syntax::{ Expr, ExprKind, FilePath, FilePrefix, Hash, ImportMode, ImportTarget, - Integer, InterpolatedText, Label, LitKind, Natural, Scheme, Span, + Integer, InterpolatedText, Label, Natural, NumKind, Scheme, Span, UnspannedExpr, URL, V, }; use crate::DecodedExpr; @@ -31,8 +31,8 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { String(s) => match Builtin::parse(s) { Some(b) => ExprKind::Builtin(b), None => match s.as_str() { - "True" => Lit(LitKind::Bool(true)), - "False" => Lit(LitKind::Bool(false)), + "True" => Num(NumKind::Bool(true)), + "False" => Num(NumKind::Bool(false)), "Type" => Const(Const::Type), "Kind" => Const(Const::Kind), "Sort" => Const(Const::Sort), @@ -44,8 +44,8 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { }, }, U64(n) => Var(V(Label::from("_"), *n as usize)), - F64(x) => Lit(LitKind::Double((*x).into())), - Bool(b) => Lit(LitKind::Bool(*b)), + F64(x) => Num(NumKind::Double((*x).into())), + Bool(b) => Num(NumKind::Bool(*b)), Array(vec) => match vec.as_slice() { [String(l), U64(n)] => { if l.as_str() == "_" { @@ -224,9 +224,9 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { let z = cbor_value_to_dhall(&z)?; BoolIf(x, y, z) } - [U64(15), U64(x)] => Lit(LitKind::Natural(*x as Natural)), - [U64(16), U64(x)] => Lit(LitKind::Integer(*x as Integer)), - [U64(16), I64(x)] => Lit(LitKind::Integer(*x as Integer)), + [U64(15), U64(x)] => Num(NumKind::Natural(*x as Natural)), + [U64(16), U64(x)] => Num(NumKind::Integer(*x as Integer)), + [U64(16), I64(x)] => Num(NumKind::Integer(*x as Integer)), [U64(18), String(first), rest @ ..] => { TextLit(InterpolatedText::from(( first.clone(), diff --git a/dhall/src/syntax/binary/encode.rs b/dhall/src/syntax/binary/encode.rs index 9e6948e..5974f47 100644 --- a/dhall/src/syntax/binary/encode.rs +++ b/dhall/src/syntax/binary/encode.rs @@ -48,7 +48,7 @@ where use std::iter::once; use syntax::Builtin; use syntax::ExprKind::*; - use syntax::LitKind::*; + use syntax::NumKind::*; use self::Serialize::{RecordDupMap, RecordMap, UnionMap}; fn expr(x: &Expr) -> self::Serialize<'_> { @@ -63,10 +63,10 @@ where match e.as_ref() { Const(c) => ser.serialize_str(&c.to_string()), Builtin(b) => ser.serialize_str(&b.to_string()), - Lit(Bool(b)) => ser.serialize_bool(*b), - Lit(Natural(n)) => ser_seq!(ser; tag(15), U64(*n as u64)), - Lit(Integer(n)) => ser_seq!(ser; tag(16), I64(*n as i64)), - Lit(Double(n)) => { + Num(Bool(b)) => ser.serialize_bool(*b), + Num(Natural(n)) => ser_seq!(ser; tag(15), U64(*n as u64)), + Num(Integer(n)) => ser_seq!(ser; tag(16), I64(*n as i64)), + Num(Double(n)) => { let n: f64 = (*n).into(); ser.serialize_f64(n) } diff --git a/dhall/src/syntax/text/parser.rs b/dhall/src/syntax/text/parser.rs index 03211c7..6f5949f 100644 --- a/dhall/src/syntax/text/parser.rs +++ b/dhall/src/syntax/text/parser.rs @@ -9,7 +9,7 @@ use pest_consume::{match_nodes, Parser}; use crate::syntax::map::{DupTreeMap, DupTreeSet}; use crate::syntax::ExprKind::*; -use crate::syntax::LitKind::*; +use crate::syntax::NumKind::*; use crate::syntax::{ Double, Expr, FilePath, FilePrefix, Hash, ImportMode, ImportTarget, Integer, InterpolatedText, InterpolatedTextContents, Label, NaiveDouble, @@ -135,7 +135,7 @@ fn insert_recordlit_entry(map: &mut BTreeMap, l: Label, e: Expr) { entry.insert(e); } Entry::Occupied(mut entry) => { - let dummy = Expr::new(Lit(Bool(false)), Span::Artificial); + let dummy = Expr::new(Num(Bool(false)), Span::Artificial); let other = entry.insert(dummy); entry.insert(Expr::new( BinOp(RecursiveRecordMerge, other, e), @@ -390,8 +390,8 @@ impl DhallParser { let e = match crate::syntax::Builtin::parse(s) { Some(b) => Builtin(b), None => match s { - "True" => Lit(Bool(true)), - "False" => Lit(Bool(false)), + "True" => Num(Bool(true)), + "False" => Num(Bool(false)), "Type" => Const(crate::syntax::Const::Type), "Kind" => Const(crate::syntax::Const::Kind), "Sort" => Const(crate::syntax::Const::Sort), @@ -924,9 +924,9 @@ impl DhallParser { #[alias(expression, shortcut = true)] fn primitive_expression(input: ParseInput) -> ParseResult { Ok(match_nodes!(input.children(); - [double_literal(n)] => spanned(input, Lit(Double(n))), - [natural_literal(n)] => spanned(input, Lit(Natural(n))), - [integer_literal(n)] => spanned(input, Lit(Integer(n))), + [double_literal(n)] => spanned(input, Num(Double(n))), + [natural_literal(n)] => spanned(input, Num(Natural(n))), + [integer_literal(n)] => spanned(input, Num(Integer(n))), [double_quote_literal(s)] => spanned(input, TextLit(s)), [single_quote_literal(s)] => spanned(input, TextLit(s)), [record_type_or_literal(e)] => spanned(input, e), diff --git a/dhall/src/syntax/text/printer.rs b/dhall/src/syntax/text/printer.rs index 2b7bc2e..378f408 100644 --- a/dhall/src/syntax/text/printer.rs +++ b/dhall/src/syntax/text/printer.rs @@ -201,7 +201,7 @@ impl Display for ExprKind { Var(a) => a.fmt(f)?, Const(k) => k.fmt(f)?, Builtin(v) => v.fmt(f)?, - Lit(a) => a.fmt(f)?, + Num(a) => a.fmt(f)?, TextLit(a) => a.fmt(f)?, RecordType(a) if a.is_empty() => f.write_str("{}")?, RecordType(a) => fmt_list("{ ", ", ", " }", a, f, |(k, t), f| { @@ -240,9 +240,9 @@ impl Display for Expr { } } -impl Display for LitKind { +impl Display for NumKind { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - use LitKind::*; + use NumKind::*; match self { Bool(true) => f.write_str("True")?, Bool(false) => f.write_str("False")?, diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 5d8fcf3..227ba31 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -4,7 +4,7 @@ use serde::de::value::{ MapAccessDeserializer, MapDeserializer, SeqDeserializer, }; -use dhall::syntax::LitKind; +use dhall::syntax::NumKind; use dhall::{SValKind, SimpleValue}; use crate::de::{Deserialize, Error, Result}; @@ -44,13 +44,13 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { V: serde::de::Visitor<'de>, { use std::convert::TryInto; - use LitKind::*; + use NumKind::*; use SValKind::*; let val = |x| Deserializer(Cow::Borrowed(x)); match self.0.kind() { - Lit(Bool(x)) => visitor.visit_bool(*x), - Lit(Natural(x)) => { + 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() { @@ -59,7 +59,7 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { unimplemented!() } } - Lit(Integer(x)) => { + Num(Integer(x)) => { if let Ok(x64) = (*x).try_into() { visitor.visit_i64(x64) } else if let Ok(x32) = (*x).try_into() { @@ -68,7 +68,7 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { unimplemented!() } } - Lit(Double(x)) => visitor.visit_f64((*x).into()), + 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))) -- cgit v1.3.1 From b3a05d930dd8f2bbc705145219025af96e5dec86 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Fri, 13 Mar 2020 20:16:08 +0000 Subject: Use dhall::Value more in serde --- dhall/src/simple.rs | 2 +- serde_dhall/src/lib.rs | 65 ++++++++++++++++++++++++------------------------ serde_dhall/src/serde.rs | 3 +-- 3 files changed, 34 insertions(+), 36 deletions(-) (limited to 'serde_dhall/src/serde.rs') diff --git a/dhall/src/simple.rs b/dhall/src/simple.rs index 9c4d6ba..32c9c79 100644 --- a/dhall/src/simple.rs +++ b/dhall/src/simple.rs @@ -12,11 +12,11 @@ pub struct SimpleValue { #[derive(Debug, Clone, PartialEq, Eq)] pub enum SValKind { Num(NumKind), + Text(String), Optional(Option), List(Vec), Record(BTreeMap), Union(String, Option), - Text(String), } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 103fdc3..134528c 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -183,44 +183,31 @@ pub use value::Value; // A Dhall value. #[doc(hidden)] pub mod value { - use dhall::{SimpleType, SimpleValue}; + use dhall::SimpleValue; use super::de::Error; - use super::Type; - /// A Dhall value + /// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. #[derive(Debug, Clone, PartialEq, Eq)] - pub struct Value(pub(crate) dhall::Value); + pub struct Value(SimpleValue); impl Value { - pub fn from_str(s: &str, ty: Option<&Type>) -> super::de::Result { - let ty = ty.map(|t| t.to_dhall_value()); - let val = dhall::Value::from_str_with_annot(s, ty.as_ref()) - .map_err(Error::Dhall)?; - Ok(Value(val)) - } - pub(crate) fn to_simple_value(&self) -> Option { - self.0.to_simple_value() - } - pub(crate) fn to_simple_type(&self) -> Option { - self.0.to_simple_type() + 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: &Value) -> super::de::Result { - Ok(v.clone()) - } - } - - impl std::fmt::Display for Value { - fn fmt( - &self, - f: &mut std::fmt::Formatter, - ) -> Result<(), std::fmt::Error> { - self.0.fmt(f) + 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)) } } } @@ -232,12 +219,15 @@ pub mod ty { use super::de::Error; - /// A Dhall type + /// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Type(SimpleType); impl Type { - pub(crate) fn to_dhall_value(&self) -> dhall::Value { + pub fn into_simple_type(self) -> SimpleType { + self.0 + } + pub fn to_dhall_value(&self) -> dhall::Value { self.0.to_value() } @@ -275,7 +265,7 @@ pub mod ty { impl super::de::sealed::Sealed for Type {} impl super::de::Deserialize for Type { - fn from_dhall(v: &super::Value) -> super::de::Result { + 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: {}", @@ -291,7 +281,6 @@ pub mod ty { pub mod de { use super::StaticType; use super::Type; - use super::Value; pub use error::{Error, Result}; mod error { @@ -339,7 +328,17 @@ pub mod de { /// 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; + 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) } /// Deserialize an instance of type `T` from a string of Dhall text. @@ -352,7 +351,7 @@ pub mod de { where T: Deserialize, { - T::from_dhall(&Value::from_str(s, None)?) + from_str_with_annot(s, None) } /// Deserialize an instance of type `T` from a string of Dhall text, @@ -364,7 +363,7 @@ pub mod de { where T: Deserialize, { - T::from_dhall(&Value::from_str(s, Some(ty))?) + from_str_with_annot(s, Some(ty)) } /// Deserialize an instance of type `T` from a string of Dhall text, diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 227ba31..e06fb3d 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -8,7 +8,6 @@ use dhall::syntax::NumKind; use dhall::{SValKind, SimpleValue}; use crate::de::{Deserialize, Error, Result}; -use crate::Value; impl<'a, T> crate::de::sealed::Sealed for T where T: serde::Deserialize<'a> {} @@ -18,7 +17,7 @@ impl<'a, T> Deserialize for T where T: serde::Deserialize<'a>, { - fn from_dhall(v: &Value) -> Result { + fn from_dhall(v: &dhall::Value) -> Result { let sval = v.to_simple_value().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into the serde data model: {}", -- 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/src/serde.rs') 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 fa89e9cb319b353332c9e835944e7f86a6604c42 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 18 Mar 2020 21:37:14 +0000 Subject: Move Value, SimpleValue and SimpleType to serde --- dhall/src/lib.rs | 66 +------------ dhall/src/semantics/tck/typecheck.rs | 5 +- dhall/src/simple.rs | 163 ------------------------------- serde_dhall/src/lib.rs | 9 +- serde_dhall/src/serde.rs | 6 +- serde_dhall/src/simple.rs | 180 +++++++++++++++++++++++++++++++++-- serde_dhall/src/static_type.rs | 3 +- serde_dhall/src/value.rs | 73 ++++++++++++++ 8 files changed, 257 insertions(+), 248 deletions(-) delete mode 100644 dhall/src/simple.rs create mode 100644 serde_dhall/src/value.rs (limited to 'serde_dhall/src/serde.rs') diff --git a/dhall/src/lib.rs b/dhall/src/lib.rs index 34a9bac..0f4b623 100644 --- a/dhall/src/lib.rs +++ b/dhall/src/lib.rs @@ -9,7 +9,6 @@ mod tests; pub mod error; pub mod semantics; -pub mod simple; pub mod syntax; use std::fmt::Display; @@ -23,8 +22,6 @@ use crate::semantics::resolve::ImportLocation; use crate::semantics::{typecheck, typecheck_with, Hir, Nir, Tir, Type}; use crate::syntax::Expr; -pub use crate::simple::{STyKind, SValKind, SimpleType, SimpleValue}; - #[derive(Debug, Clone)] pub struct Parsed(Expr, ImportLocation); @@ -47,16 +44,6 @@ pub struct Typed { #[derive(Debug, Clone)] pub struct Normalized(Nir); -/// A Dhall value. -#[derive(Debug, Clone)] -pub struct Value { - /// Invariant: in normal form - pub hir: Hir, - /// Cached conversions because they are annoying to construct from Hir. - pub as_simple_val: Option, - pub as_simple_ty: Option, -} - /// Controls conversion from `Nir` to `Expr` #[derive(Copy, Clone, Default)] pub struct ToExprOptions { @@ -131,14 +118,6 @@ impl Typed { } impl Normalized { - pub fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: SimpleValue::from_nir(&self.0), - as_simple_ty: SimpleType::from_nir(&self.0), - } - } - /// Converts a value back to the corresponding AST expression. pub fn to_expr(&self) -> Expr { self.0.to_expr(ToExprOptions::default()) @@ -147,42 +126,15 @@ impl Normalized { pub fn to_hir(&self) -> Hir { self.0.to_hir_noenv() } + pub fn as_nir(&self) -> &Nir { + &self.0 + } /// Converts a value back to the corresponding AST expression, alpha-normalizing in the process. pub fn to_expr_alpha(&self) -> Expr { self.0.to_expr(ToExprOptions { alpha: true }) } } -impl Value { - /// Parse a string into a Value, and optionally ensure that the value matches the provided type - /// annotation. - pub fn from_str_with_annot( - s: &str, - ty: Option<&Self>, - ) -> Result { - let resolved = Parsed::parse_str(s)?.resolve()?; - let typed = match ty { - None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(&ty.hir)?, - }; - Ok(typed.normalize().to_value()) - } - - /// Converts a Value into a SimpleValue. - pub fn to_simple_value(&self) -> Option { - self.as_simple_val.clone() - } - /// Converts a Value into a SimpleType. - pub fn to_simple_type(&self) -> Option { - self.as_simple_ty.clone() - } - - /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> Expr { - self.hir.to_expr(ToExprOptions::default()) - } -} - macro_rules! derive_traits_for_wrapper_struct { ($ty:ident) => { impl std::cmp::PartialEq for $ty { @@ -246,15 +198,3 @@ impl Display for Normalized { self.to_expr().fmt(f) } } - -impl Eq for Value {} -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - self.hir == other.hir - } -} -impl Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - self.to_expr().fmt(f) - } -} diff --git a/dhall/src/semantics/tck/typecheck.rs b/dhall/src/semantics/tck/typecheck.rs index 205185f..c3334b5 100644 --- a/dhall/src/semantics/tck/typecheck.rs +++ b/dhall/src/semantics/tck/typecheck.rs @@ -57,10 +57,7 @@ pub fn mkerr(msg: S) -> Result { Err(TypeError::new(TypeMessage::Custom(msg.to_string()))) } -pub fn mk_span_err( - span: Span, - msg: S, -) -> Result { +pub fn mk_span_err(span: Span, msg: S) -> Result { mkerr( ErrorBuilder::new(msg.to_string()) .span_err(span, msg.to_string()) diff --git a/dhall/src/simple.rs b/dhall/src/simple.rs deleted file mode 100644 index c00380c..0000000 --- a/dhall/src/simple.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::collections::BTreeMap; - -use crate::semantics::{Hir, HirKind, Nir, NirKind}; -use crate::syntax::{Builtin, ExprKind, NumKind, Span}; -use crate::Value; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleValue { - kind: Box, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum SValKind { - Num(NumKind), - Text(String), - Optional(Option), - List(Vec), - Record(BTreeMap), - Union(String, Option), -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleType { - kind: Box, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum STyKind { - Bool, - Natural, - Integer, - Double, - Text, - Optional(SimpleType), - List(SimpleType), - Record(BTreeMap), - Union(BTreeMap>), -} - -impl SimpleValue { - pub fn new(kind: SValKind) -> Self { - SimpleValue { - kind: Box::new(kind), - } - } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleValue::new(match nir.kind() { - NirKind::Num(lit) => SValKind::Num(lit.clone()), - NirKind::TextLit(x) => SValKind::Text( - x.as_text() - .expect("Normal form should ensure the text is a string"), - ), - NirKind::EmptyOptionalLit(_) => SValKind::Optional(None), - NirKind::NEOptionalLit(x) => { - SValKind::Optional(Some(Self::from_nir(x)?)) - } - NirKind::EmptyListLit(_) => SValKind::List(vec![]), - NirKind::NEListLit(xs) => SValKind::List( - xs.iter() - .map(|v| Self::from_nir(v)) - .collect::>()?, - ), - NirKind::RecordLit(kvs) => SValKind::Record( - kvs.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) - .collect::>()?, - ), - NirKind::UnionLit(field, x, _) => { - SValKind::Union(field.into(), Some(Self::from_nir(x)?)) - } - NirKind::UnionConstructor(field, ty) - if ty.get(field).map(|f| f.is_some()) == Some(false) => - { - SValKind::Union(field.into(), None) - } - _ => return None, - })) - } - - pub fn kind(&self) -> &SValKind { - self.kind.as_ref() - } -} - -impl SimpleType { - pub fn new(kind: STyKind) -> Self { - SimpleType { - kind: Box::new(kind), - } - } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleType::new(match nir.kind() { - NirKind::BuiltinType(b) => match b { - Builtin::Bool => STyKind::Bool, - Builtin::Natural => STyKind::Natural, - Builtin::Integer => STyKind::Integer, - Builtin::Double => STyKind::Double, - Builtin::Text => STyKind::Text, - _ => unreachable!(), - }, - NirKind::OptionalType(t) => STyKind::Optional(Self::from_nir(t)?), - NirKind::ListType(t) => STyKind::List(Self::from_nir(t)?), - NirKind::RecordType(kts) => STyKind::Record( - kts.iter() - .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) - .collect::>()?, - ), - NirKind::UnionType(kts) => STyKind::Union( - kts.iter() - .map(|(k, v)| { - Some(( - k.into(), - v.as_ref() - .map(|v| Ok(Self::from_nir(v)?)) - .transpose()?, - )) - }) - .collect::>()?, - ), - _ => return None, - })) - } - - pub fn kind(&self) -> &STyKind { - self.kind.as_ref() - } - pub fn to_value(&self) -> Value { - Value { - hir: self.to_hir(), - as_simple_val: None, - as_simple_ty: Some(self.clone()), - } - } - pub fn to_hir(&self) -> Hir { - let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); - hir(match self.kind() { - STyKind::Bool => ExprKind::Builtin(Builtin::Bool), - STyKind::Natural => ExprKind::Builtin(Builtin::Natural), - STyKind::Integer => ExprKind::Builtin(Builtin::Integer), - STyKind::Double => ExprKind::Builtin(Builtin::Double), - STyKind::Text => ExprKind::Builtin(Builtin::Text), - STyKind::Optional(t) => ExprKind::App( - hir(ExprKind::Builtin(Builtin::Optional)), - t.to_hir(), - ), - STyKind::List(t) => { - ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) - } - STyKind::Record(kts) => ExprKind::RecordType( - kts.into_iter() - .map(|(k, t)| (k.as_str().into(), t.to_hir())) - .collect(), - ), - STyKind::Union(kts) => ExprKind::UnionType( - kts.into_iter() - .map(|(k, t)| { - (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) - }) - .collect(), - ), - }) - } -} diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index 15f45ce..adc242f 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -171,11 +171,13 @@ mod error; mod serde; pub mod simple; mod static_type; +mod value; #[doc(hidden)] pub use dhall_proc_macros::StaticType; pub use error::{Error, Result}; pub use static_type::StaticType; +pub use value::Value; use simple::Type; @@ -191,16 +193,15 @@ pub(crate) mod sealed { /// 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_dhall(v: &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)?; + let ty = ty.map(|ty| ty.to_value()); + let val = Value::from_str_with_annot(s, ty.as_ref())?; T::from_dhall(&val) } diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index d144abf..91ef5d7 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -5,9 +5,9 @@ use serde::de::value::{ }; use dhall::syntax::NumKind; -use dhall::{SValKind, SimpleValue}; -use crate::{Deserialize, Error, Result}; +use crate::simple::{SValKind, SimpleValue}; +use crate::{Deserialize, Error, Result, Value}; impl<'a, T> crate::sealed::Sealed for T where T: serde::Deserialize<'a> {} @@ -17,7 +17,7 @@ impl<'a, T> Deserialize for T where T: serde::Deserialize<'a>, { - fn from_dhall(v: &dhall::Value) -> Result { + 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: {}", diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs index 93364a0..0b322ae 100644 --- a/serde_dhall/src/simple.rs +++ b/serde_dhall/src/simple.rs @@ -1,25 +1,62 @@ -use super::Error; -use dhall::{STyKind, SimpleType, SimpleValue}; +use std::collections::BTreeMap; + +use dhall::semantics::{Hir, HirKind, Nir, NirKind}; +use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; + +use crate::Error; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SimpleValue { + kind: Box, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum SValKind { + Num(NumKind), + Text(String), + Optional(Option), + List(Vec), + Record(BTreeMap), + Union(String, Option), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct SimpleType { + kind: Box, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum STyKind { + Bool, + Natural, + Integer, + Double, + Text, + Optional(SimpleType), + List(SimpleType), + Record(BTreeMap), + Union(BTreeMap>), +} /// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Value(SimpleValue); +/// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Type(SimpleType); + 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 { + pub fn to_value(&self) -> crate::Value { self.0.to_value() } @@ -52,10 +89,135 @@ impl Type { } } +impl SimpleValue { + pub fn new(kind: SValKind) -> Self { + SimpleValue { + kind: Box::new(kind), + } + } + pub fn from_nir(nir: &Nir) -> Option { + Some(SimpleValue::new(match nir.kind() { + NirKind::Num(lit) => SValKind::Num(lit.clone()), + NirKind::TextLit(x) => SValKind::Text( + x.as_text() + .expect("Normal form should ensure the text is a string"), + ), + NirKind::EmptyOptionalLit(_) => SValKind::Optional(None), + NirKind::NEOptionalLit(x) => { + SValKind::Optional(Some(Self::from_nir(x)?)) + } + NirKind::EmptyListLit(_) => SValKind::List(vec![]), + NirKind::NEListLit(xs) => SValKind::List( + xs.iter() + .map(|v| Self::from_nir(v)) + .collect::>()?, + ), + NirKind::RecordLit(kvs) => SValKind::Record( + kvs.iter() + .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .collect::>()?, + ), + NirKind::UnionLit(field, x, _) => { + SValKind::Union(field.into(), Some(Self::from_nir(x)?)) + } + NirKind::UnionConstructor(field, ty) + if ty.get(field).map(|f| f.is_some()) == Some(false) => + { + SValKind::Union(field.into(), None) + } + _ => return None, + })) + } + + pub fn kind(&self) -> &SValKind { + self.kind.as_ref() + } +} + +impl SimpleType { + pub fn new(kind: STyKind) -> Self { + SimpleType { + kind: Box::new(kind), + } + } + pub fn from_nir(nir: &Nir) -> Option { + Some(SimpleType::new(match nir.kind() { + NirKind::BuiltinType(b) => match b { + Builtin::Bool => STyKind::Bool, + Builtin::Natural => STyKind::Natural, + Builtin::Integer => STyKind::Integer, + Builtin::Double => STyKind::Double, + Builtin::Text => STyKind::Text, + _ => unreachable!(), + }, + NirKind::OptionalType(t) => STyKind::Optional(Self::from_nir(t)?), + NirKind::ListType(t) => STyKind::List(Self::from_nir(t)?), + NirKind::RecordType(kts) => STyKind::Record( + kts.iter() + .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) + .collect::>()?, + ), + NirKind::UnionType(kts) => STyKind::Union( + kts.iter() + .map(|(k, v)| { + Some(( + k.into(), + v.as_ref() + .map(|v| Ok(Self::from_nir(v)?)) + .transpose()?, + )) + }) + .collect::>()?, + ), + _ => return None, + })) + } + + pub fn kind(&self) -> &STyKind { + self.kind.as_ref() + } + pub fn to_value(&self) -> crate::Value { + crate::Value { + hir: self.to_hir(), + as_simple_val: None, + as_simple_ty: Some(self.clone()), + } + } + pub fn to_hir(&self) -> Hir { + let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); + hir(match self.kind() { + STyKind::Bool => ExprKind::Builtin(Builtin::Bool), + STyKind::Natural => ExprKind::Builtin(Builtin::Natural), + STyKind::Integer => ExprKind::Builtin(Builtin::Integer), + STyKind::Double => ExprKind::Builtin(Builtin::Double), + STyKind::Text => ExprKind::Builtin(Builtin::Text), + STyKind::Optional(t) => ExprKind::App( + hir(ExprKind::Builtin(Builtin::Optional)), + t.to_hir(), + ), + STyKind::List(t) => { + ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) + } + STyKind::Record(kts) => ExprKind::RecordType( + kts.into_iter() + .map(|(k, t)| (k.as_str().into(), t.to_hir())) + .collect(), + ), + STyKind::Union(kts) => ExprKind::UnionType( + kts.into_iter() + .map(|(k, t)| { + (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) + }) + .collect(), + ), + }) + } +} + impl super::sealed::Sealed for Value {} impl super::Deserialize for Value { - fn from_dhall(v: &dhall::Value) -> super::Result { + fn from_dhall(v: &crate::Value) -> super::Result { let sval = v.to_simple_value().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", @@ -69,7 +231,7 @@ impl super::Deserialize for Value { impl super::sealed::Sealed for Type {} impl super::Deserialize for Type { - fn from_dhall(v: &dhall::Value) -> super::Result { + fn from_dhall(v: &crate::Value) -> super::Result { let sty = v.to_simple_type().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs index bc5f366..4e30f34 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,5 +1,4 @@ -use dhall::{STyKind, SimpleType}; - +use crate::simple::{STyKind, SimpleType}; use crate::Type; /// A Rust type that can be represented as a Dhall type. diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs new file mode 100644 index 0000000..a24f211 --- /dev/null +++ b/serde_dhall/src/value.rs @@ -0,0 +1,73 @@ +use dhall::semantics::Hir; +use dhall::syntax::Expr; +use dhall::{Normalized, Parsed}; + +use crate::simple::{SimpleType, SimpleValue}; +use crate::Error; + +/// A Dhall value. +#[derive(Debug, Clone)] +pub struct Value { + /// Invariant: in normal form + pub(crate) 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, +} + +impl Value { + /// Parse a string into a Value, and optionally ensure that the value matches the provided type + /// annotation. + pub fn from_str_with_annot( + s: &str, + ty: Option<&Self>, + ) -> Result { + Self::from_str_with_annot_dhall_error(s, ty).map_err(Error::Dhall) + } + fn from_normalized(x: &Normalized) -> Self { + Value { + hir: x.to_hir(), + as_simple_val: SimpleValue::from_nir(x.as_nir()), + as_simple_ty: SimpleType::from_nir(x.as_nir()), + } + } + + fn from_str_with_annot_dhall_error( + s: &str, + ty: Option<&Self>, + ) -> Result { + let resolved = Parsed::parse_str(s)?.resolve()?; + let typed = match ty { + None => resolved.typecheck()?, + Some(ty) => resolved.typecheck_with(&ty.hir)?, + }; + Ok(Self::from_normalized(&typed.normalize())) + } + + /// Converts a Value into a SimpleValue. + pub fn to_simple_value(&self) -> Option { + self.as_simple_val.clone() + } + /// Converts a Value into a SimpleType. + pub fn to_simple_type(&self) -> Option { + self.as_simple_ty.clone() + } + + /// Converts a value back to the corresponding AST expression. + pub fn to_expr(&self) -> Expr { + self.hir.to_expr(Default::default()) + } +} + +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) -> Result<(), std::fmt::Error> { + self.to_expr().fmt(f) + } +} -- cgit v1.3.1 From a1f370cb68974c1e69f8f85345e91ec763b23ae2 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 18 Mar 2020 22:28:41 +0000 Subject: Expose simple::Val/Ty properly in the API --- README.md | 2 +- dhall_proc_macros/src/derive.rs | 19 ++-- serde_dhall/src/lib.rs | 31 +++---- serde_dhall/src/serde.rs | 6 +- serde_dhall/src/simple.rs | 195 ++++++++++++++++------------------------ serde_dhall/src/static_type.rs | 21 +++-- serde_dhall/src/value.rs | 27 +++--- 7 files changed, 132 insertions(+), 169 deletions(-) (limited to 'serde_dhall/src/serde.rs') diff --git a/README.md b/README.md index 1bcf558..2cb3c0b 100644 --- a/README.md +++ b/README.md @@ -169,7 +169,7 @@ same name as the corresponding test. #### [???] -- Breaking change: use `serde_dhall::Type` type for type-checking instead of `serde_dhall::Value` +- Breaking change: use `serde_dhall::simple::Type` type for type-checking instead of `serde_dhall::Value` #### [0.4.0] diff --git a/dhall_proc_macros/src/derive.rs b/dhall_proc_macros/src/derive.rs index 4885b49..f7edf3a 100644 --- a/dhall_proc_macros/src/derive.rs +++ b/dhall_proc_macros/src/derive.rs @@ -52,9 +52,11 @@ fn derive_for_struct( let ty = static_type(ty); quote!( (#name.to_owned(), #ty) ) }); - Ok(quote! { ::serde_dhall::simple::Type::make_record_type( - vec![ #(#entries),* ].into_iter() - ) }) + Ok(quote! { + ::serde_dhall::simple::TyKind::Record( + vec![ #(#entries),* ].into_iter().collect() + ).into() + }) } fn derive_for_enum( @@ -89,9 +91,11 @@ fn derive_for_enum( }) .collect::>()?; - Ok(quote! { ::serde_dhall::simple::Type::make_union_type( - vec![ #(#entries),* ].into_iter() - ) }) + Ok(quote! { + ::serde_dhall::simple::TyKind::Union( + vec![ #(#entries),* ].into_iter().collect() + ).into() + }) } pub fn derive_static_type_inner( @@ -164,8 +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::simple::Type { #(#assertions)* #get_type } diff --git a/serde_dhall/src/lib.rs b/serde_dhall/src/lib.rs index adc242f..4b1a689 100644 --- a/serde_dhall/src/lib.rs +++ b/serde_dhall/src/lib.rs @@ -16,7 +16,7 @@ //! //! # Basic usage //! -//! The main entrypoint of this library is the [`from_str`][from_str] function. It reads a string +//! The main entrypoint of this library is the [`from_str`](fn.from_str.html) function. It reads a string //! containing a Dhall expression and deserializes it into any serde-compatible type. //! //! This could mean a common Rust type like `HashMap`: @@ -88,11 +88,11 @@ //! //! # 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][from_str]. +//! 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_json::from_str]: https://docs.serde.rs/serde_json/de/fn.from_str.html -//! [serde_yaml::from_str]: https://docs.serde.rs/serde_yaml/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 //! //! //! # Additional Dhall typechecking @@ -106,8 +106,8 @@ //! 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::Type`][Type], then -//! pass it to [`from_str_check_type`][from_str_check_type]. +//! 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). //! //! ```rust //! # fn main() -> serde_dhall::Result<()> { @@ -135,7 +135,8 @@ //! # } //! ``` //! -//! You can also let Rust infer the appropriate Dhall type, using the [StaticType] trait. +//! You can also let Rust infer the appropriate Dhall type, using the +//! [StaticType](trait.StaticType.html) trait. //! //! ```rust //! # fn main() -> serde_dhall::Result<()> { @@ -169,18 +170,19 @@ mod error; mod serde; +/// Serde-compatible values and their type pub mod simple; mod static_type; -mod value; +/// Arbitrary Dhall values +pub mod value; +pub use crate::simple::{Type as SimpleType, Value as SimpleValue}; #[doc(hidden)] pub use dhall_proc_macros::StaticType; pub use error::{Error, Result}; pub use static_type::StaticType; pub use value::Value; -use simple::Type; - pub(crate) mod sealed { pub trait Sealed {} } @@ -196,12 +198,11 @@ pub trait Deserialize: sealed::Sealed + Sized { fn from_dhall(v: &Value) -> Result; } -fn from_str_with_annot(s: &str, ty: Option<&Type>) -> Result +fn from_str_with_annot(s: &str, ty: Option<&simple::Type>) -> Result where T: Deserialize, { - let ty = ty.map(|ty| ty.to_value()); - let val = Value::from_str_with_annot(s, ty.as_ref())?; + let val = Value::from_str_with_annot(s, ty)?; T::from_dhall(&val) } @@ -223,7 +224,7 @@ where /// /// 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 +pub fn from_str_check_type(s: &str, ty: &simple::Type) -> Result where T: Deserialize, { diff --git a/serde_dhall/src/serde.rs b/serde_dhall/src/serde.rs index 91ef5d7..717450a 100644 --- a/serde_dhall/src/serde.rs +++ b/serde_dhall/src/serde.rs @@ -6,7 +6,7 @@ use serde::de::value::{ use dhall::syntax::NumKind; -use crate::simple::{SValKind, SimpleValue}; +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> {} @@ -44,7 +44,7 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { { use std::convert::TryInto; use NumKind::*; - use SValKind::*; + use ValKind::*; let val = |x| Deserializer(Cow::Borrowed(x)); match self.0.kind() { @@ -97,7 +97,7 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { let val = |x| Deserializer(Cow::Borrowed(x)); match self.0.kind() { // Blindly takes keys in sorted order. - SValKind::Record(m) => visitor + ValKind::Record(m) => visitor .visit_seq(SeqDeserializer::new(m.iter().map(|(_, v)| val(v)))), _ => self.deserialize_any(visitor), } diff --git a/serde_dhall/src/simple.rs b/serde_dhall/src/simple.rs index 0b322ae..4cd4ab7 100644 --- a/serde_dhall/src/simple.rs +++ b/serde_dhall/src/simple.rs @@ -3,161 +3,114 @@ use std::collections::BTreeMap; use dhall::semantics::{Hir, HirKind, Nir, NirKind}; use dhall::syntax::{Builtin, ExprKind, NumKind, Span}; -use crate::Error; +use crate::{sealed::Sealed, Deserialize, Error, Result}; +/// A simple value of the kind that can be encoded/decoded with serde #[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleValue { - kind: Box, +pub struct Value { + kind: Box, } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum SValKind { +pub enum ValKind { + // TODO: redefine NumKind locally Num(NumKind), Text(String), - Optional(Option), - List(Vec), - Record(BTreeMap), - Union(String, Option), + Optional(Option), + List(Vec), + // TODO: HashMap ? + Record(BTreeMap), + Union(String, Option), } +/// The type of a `simple::Value`. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct SimpleType { - kind: Box, +pub struct Type { + kind: Box, } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum STyKind { +pub enum TyKind { Bool, Natural, Integer, Double, Text, - Optional(SimpleType), - List(SimpleType), - Record(BTreeMap), - Union(BTreeMap>), + Optional(Type), + List(Type), + Record(BTreeMap), + Union(BTreeMap>), } -/// A Dhall value. This is a wrapper around [`dhall::SimpleValue`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Value(SimpleValue); - -/// A Dhall type. This is a wrapper around [`dhall::SimpleType`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Type(SimpleType); - impl Value { - pub fn into_simple_value(self) -> SimpleValue { - self.0 - } -} - -impl Type { - pub fn into_simple_type(self) -> SimpleType { - self.0 - } - pub fn to_value(&self) -> crate::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 SimpleValue { - pub fn new(kind: SValKind) -> Self { - SimpleValue { + pub(crate) fn new(kind: ValKind) -> Self { + Value { kind: Box::new(kind), } } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleValue::new(match nir.kind() { - NirKind::Num(lit) => SValKind::Num(lit.clone()), - NirKind::TextLit(x) => SValKind::Text( + pub(crate) fn from_nir(nir: &Nir) -> Option { + Some(Value::new(match nir.kind() { + NirKind::Num(lit) => ValKind::Num(lit.clone()), + NirKind::TextLit(x) => ValKind::Text( x.as_text() .expect("Normal form should ensure the text is a string"), ), - NirKind::EmptyOptionalLit(_) => SValKind::Optional(None), + NirKind::EmptyOptionalLit(_) => ValKind::Optional(None), NirKind::NEOptionalLit(x) => { - SValKind::Optional(Some(Self::from_nir(x)?)) + ValKind::Optional(Some(Self::from_nir(x)?)) } - NirKind::EmptyListLit(_) => SValKind::List(vec![]), - NirKind::NEListLit(xs) => SValKind::List( + NirKind::EmptyListLit(_) => ValKind::List(vec![]), + NirKind::NEListLit(xs) => ValKind::List( xs.iter() .map(|v| Self::from_nir(v)) .collect::>()?, ), - NirKind::RecordLit(kvs) => SValKind::Record( + NirKind::RecordLit(kvs) => ValKind::Record( kvs.iter() .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) .collect::>()?, ), NirKind::UnionLit(field, x, _) => { - SValKind::Union(field.into(), Some(Self::from_nir(x)?)) + ValKind::Union(field.into(), Some(Self::from_nir(x)?)) } NirKind::UnionConstructor(field, ty) if ty.get(field).map(|f| f.is_some()) == Some(false) => { - SValKind::Union(field.into(), None) + ValKind::Union(field.into(), None) } _ => return None, })) } - pub fn kind(&self) -> &SValKind { + pub fn kind(&self) -> &ValKind { self.kind.as_ref() } } -impl SimpleType { - pub fn new(kind: STyKind) -> Self { - SimpleType { +impl Type { + pub fn new(kind: TyKind) -> Self { + Type { kind: Box::new(kind), } } - pub fn from_nir(nir: &Nir) -> Option { - Some(SimpleType::new(match nir.kind() { + pub(crate) fn from_nir(nir: &Nir) -> Option { + Some(Type::new(match nir.kind() { NirKind::BuiltinType(b) => match b { - Builtin::Bool => STyKind::Bool, - Builtin::Natural => STyKind::Natural, - Builtin::Integer => STyKind::Integer, - Builtin::Double => STyKind::Double, - Builtin::Text => STyKind::Text, + Builtin::Bool => TyKind::Bool, + Builtin::Natural => TyKind::Natural, + Builtin::Integer => TyKind::Integer, + Builtin::Double => TyKind::Double, + Builtin::Text => TyKind::Text, _ => unreachable!(), }, - NirKind::OptionalType(t) => STyKind::Optional(Self::from_nir(t)?), - NirKind::ListType(t) => STyKind::List(Self::from_nir(t)?), - NirKind::RecordType(kts) => STyKind::Record( + NirKind::OptionalType(t) => TyKind::Optional(Self::from_nir(t)?), + NirKind::ListType(t) => TyKind::List(Self::from_nir(t)?), + NirKind::RecordType(kts) => TyKind::Record( kts.iter() .map(|(k, v)| Some((k.into(), Self::from_nir(v)?))) .collect::>()?, ), - NirKind::UnionType(kts) => STyKind::Union( + NirKind::UnionType(kts) => TyKind::Union( kts.iter() .map(|(k, v)| { Some(( @@ -173,37 +126,37 @@ impl SimpleType { })) } - pub fn kind(&self) -> &STyKind { + pub fn kind(&self) -> &TyKind { self.kind.as_ref() } - pub fn to_value(&self) -> crate::Value { - crate::Value { + pub fn to_value(&self) -> crate::value::Value { + crate::value::Value { hir: self.to_hir(), as_simple_val: None, as_simple_ty: Some(self.clone()), } } - pub fn to_hir(&self) -> Hir { + pub(crate) fn to_hir(&self) -> Hir { let hir = |k| Hir::new(HirKind::Expr(k), Span::Artificial); hir(match self.kind() { - STyKind::Bool => ExprKind::Builtin(Builtin::Bool), - STyKind::Natural => ExprKind::Builtin(Builtin::Natural), - STyKind::Integer => ExprKind::Builtin(Builtin::Integer), - STyKind::Double => ExprKind::Builtin(Builtin::Double), - STyKind::Text => ExprKind::Builtin(Builtin::Text), - STyKind::Optional(t) => ExprKind::App( + 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(ExprKind::Builtin(Builtin::Optional)), t.to_hir(), ), - STyKind::List(t) => { + TyKind::List(t) => { ExprKind::App(hir(ExprKind::Builtin(Builtin::List)), t.to_hir()) } - STyKind::Record(kts) => ExprKind::RecordType( + TyKind::Record(kts) => ExprKind::RecordType( kts.into_iter() .map(|(k, t)| (k.as_str().into(), t.to_hir())) .collect(), ), - STyKind::Union(kts) => ExprKind::UnionType( + TyKind::Union(kts) => ExprKind::UnionType( kts.into_iter() .map(|(k, t)| { (k.as_str().into(), t.as_ref().map(|t| t.to_hir())) @@ -214,30 +167,34 @@ impl SimpleType { } } -impl super::sealed::Sealed for Value {} +impl Sealed for Value {} -impl super::Deserialize for Value { - fn from_dhall(v: &crate::Value) -> super::Result { - let sval = v.to_simple_value().ok_or_else(|| { +impl Deserialize for Value { + fn from_dhall(v: &crate::value::Value) -> Result { + 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 Sealed for Type {} -impl super::Deserialize for Type { - fn from_dhall(v: &crate::Value) -> super::Result { - let sty = v.to_simple_type().ok_or_else(|| { +impl Deserialize for Type { + fn from_dhall(v: &crate::value::Value) -> Result { + v.to_simple_type().ok_or_else(|| { Error::Deserialize(format!( "this cannot be deserialized into a simple type: {}", v )) - })?; - Ok(Type(sty)) + }) + } +} + +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 4e30f34..79418d2 100644 --- a/serde_dhall/src/static_type.rs +++ b/serde_dhall/src/static_type.rs @@ -1,5 +1,4 @@ -use crate::simple::{STyKind, SimpleType}; -use crate::Type; +use crate::simple::{TyKind, Type}; /// A Rust type that can be represented as a Dhall type. /// @@ -20,7 +19,7 @@ macro_rules! derive_builtin { ($rust_ty:ty, $dhall_ty:ident) => { impl StaticType for $rust_ty { fn static_type() -> Type { - Type::from_simple_type(SimpleType::new(STyKind::$dhall_ty)) + Type::new(TyKind::$dhall_ty) } } }; @@ -43,13 +42,15 @@ where B: StaticType, { fn static_type() -> Type { - Type::make_record_type( + TyKind::Record( vec![ ("_1".to_owned(), A::static_type()), ("_2".to_owned(), B::static_type()), ] - .into_iter(), + .into_iter() + .collect(), ) + .into() } } @@ -59,13 +60,15 @@ where E: StaticType, { fn static_type() -> Type { - Type::make_union_type( + TyKind::Union( vec![ ("Ok".to_owned(), Some(T::static_type())), ("Err".to_owned(), Some(E::static_type())), ] - .into_iter(), + .into_iter() + .collect(), ) + .into() } } @@ -74,7 +77,7 @@ where T: StaticType, { fn static_type() -> Type { - Type::make_optional_type(T::static_type()) + TyKind::Optional(T::static_type()).into() } } @@ -83,7 +86,7 @@ where T: StaticType, { fn static_type() -> Type { - Type::make_list_type(T::static_type()) + TyKind::List(T::static_type()).into() } } diff --git a/serde_dhall/src/value.rs b/serde_dhall/src/value.rs index a24f211..62632e5 100644 --- a/serde_dhall/src/value.rs +++ b/serde_dhall/src/value.rs @@ -1,11 +1,11 @@ -use dhall::semantics::Hir; +use dhall::semantics::{Hir, Nir}; use dhall::syntax::Expr; -use dhall::{Normalized, Parsed}; +use dhall::Parsed; -use crate::simple::{SimpleType, SimpleValue}; +use crate::simple::{Type as SimpleType, Value as SimpleValue}; use crate::Error; -/// A Dhall value. +/// An arbitrary Dhall value. #[derive(Debug, Clone)] pub struct Value { /// Invariant: in normal form @@ -21,28 +21,27 @@ impl Value { /// annotation. pub fn from_str_with_annot( s: &str, - ty: Option<&Self>, + ty: Option<&SimpleType>, ) -> Result { Self::from_str_with_annot_dhall_error(s, ty).map_err(Error::Dhall) } - fn from_normalized(x: &Normalized) -> Self { + fn from_nir(x: &Nir) -> Self { Value { - hir: x.to_hir(), - as_simple_val: SimpleValue::from_nir(x.as_nir()), - as_simple_ty: SimpleType::from_nir(x.as_nir()), + hir: x.to_hir_noenv(), + as_simple_val: SimpleValue::from_nir(x), + as_simple_ty: SimpleType::from_nir(x), } } - fn from_str_with_annot_dhall_error( s: &str, - ty: Option<&Self>, + ty: Option<&SimpleType>, ) -> Result { let resolved = Parsed::parse_str(s)?.resolve()?; let typed = match ty { None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(&ty.hir)?, + Some(ty) => resolved.typecheck_with(&ty.to_value().hir)?, }; - Ok(Self::from_normalized(&typed.normalize())) + Ok(Self::from_nir(typed.normalize().as_nir())) } /// Converts a Value into a SimpleValue. @@ -55,7 +54,7 @@ impl Value { } /// Converts a value back to the corresponding AST expression. - pub fn to_expr(&self) -> Expr { + pub(crate) fn to_expr(&self) -> Expr { self.hir.to_expr(Default::default()) } } -- 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/src/serde.rs') 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