summaryrefslogtreecommitdiff
path: root/serde_dhall
diff options
context:
space:
mode:
authorNadrieril2020-03-18 22:28:41 +0000
committerNadrieril2020-03-31 21:44:01 +0100
commita1f370cb68974c1e69f8f85345e91ec763b23ae2 (patch)
treedb1be2a231e29f57ad820634b3b487637b663313 /serde_dhall
parentfa89e9cb319b353332c9e835944e7f86a6604c42 (diff)
Expose simple::Val/Ty properly in the API
Diffstat (limited to 'serde_dhall')
-rw-r--r--serde_dhall/src/lib.rs31
-rw-r--r--serde_dhall/src/serde.rs6
-rw-r--r--serde_dhall/src/simple.rs195
-rw-r--r--serde_dhall/src/static_type.rs21
-rw-r--r--serde_dhall/src/value.rs27
5 files changed, 120 insertions, 160 deletions
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<Self>;
}
-fn from_str_with_annot<T>(s: &str, ty: Option<&Type>) -> Result<T>
+fn from_str_with_annot<T>(s: &str, ty: Option<&simple::Type>) -> Result<T>
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<T>(s: &str, ty: &Type) -> Result<T>
+pub fn from_str_check_type<T>(s: &str, ty: &simple::Type) -> Result<T>
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<SValKind>,
+pub struct Value {
+ kind: Box<ValKind>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum SValKind {
+pub enum ValKind {
+ // TODO: redefine NumKind locally
Num(NumKind),
Text(String),
- Optional(Option<SimpleValue>),
- List(Vec<SimpleValue>),
- Record(BTreeMap<String, SimpleValue>),
- Union(String, Option<SimpleValue>),
+ Optional(Option<Value>),
+ List(Vec<Value>),
+ // TODO: HashMap ?
+ Record(BTreeMap<String, Value>),
+ Union(String, Option<Value>),
}
+/// The type of a `simple::Value`.
#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct SimpleType {
- kind: Box<STyKind>,
+pub struct Type {
+ kind: Box<TyKind>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum STyKind {
+pub enum TyKind {
Bool,
Natural,
Integer,
Double,
Text,
- Optional(SimpleType),
- List(SimpleType),
- Record(BTreeMap<String, SimpleType>),
- Union(BTreeMap<String, Option<SimpleType>>),
+ Optional(Type),
+ List(Type),
+ Record(BTreeMap<String, Type>),
+ Union(BTreeMap<String, Option<Type>>),
}
-/// 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<Item = (String, Type)>) -> Self {
- Type::from_stykind(STyKind::Record(
- kts.map(|(k, t)| (k, t.0)).collect(),
- ))
- }
- #[doc(hidden)]
- pub fn make_union_type(
- kts: impl Iterator<Item = (String, Option<Type>)>,
- ) -> 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<Self> {
- 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<Self> {
+ 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::<Option<_>>()?,
),
- NirKind::RecordLit(kvs) => SValKind::Record(
+ NirKind::RecordLit(kvs) => ValKind::Record(
kvs.iter()
.map(|(k, v)| Some((k.into(), Self::from_nir(v)?)))
.collect::<Option<_>>()?,
),
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<Self> {
- Some(SimpleType::new(match nir.kind() {
+ pub(crate) fn from_nir(nir: &Nir) -> Option<Self> {
+ 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::<Option<_>>()?,
),
- 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<Self> {
- let sval = v.to_simple_value().ok_or_else(|| {
+impl Deserialize for Value {
+ fn from_dhall(v: &crate::value::Value) -> Result<Self> {
+ 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<Self> {
- let sty = v.to_simple_type().ok_or_else(|| {
+impl Deserialize for Type {
+ fn from_dhall(v: &crate::value::Value) -> Result<Self> {
+ v.to_simple_type().ok_or_else(|| {
Error::Deserialize(format!(
"this cannot be deserialized into a simple type: {}",
v
))
- })?;
- Ok(Type(sty))
+ })
+ }
+}
+
+impl From<TyKind> for Type {
+ fn from(x: TyKind) -> Type {
+ Type::new(x)
}
}
diff --git a/serde_dhall/src/static_type.rs b/serde_dhall/src/static_type.rs
index 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, Error> {
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<Self, dhall::error::Error> {
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())
}
}