summaryrefslogtreecommitdiff
path: root/serde_dhall/src
diff options
context:
space:
mode:
authorstuebinm2021-04-10 22:59:07 +0200
committerstuebinm2021-04-10 22:59:07 +0200
commit2958333c83dce911463734e391fe3ccc76cfc9d5 (patch)
treef8b6a6370222f6f1053061f684c27ead563b7c74 /serde_dhall/src
parentc307b914eca192f8e8648345e365f9c0207bc18c (diff)
add type substitutions to serde_dhall
this adds subsititutions, which work similar to the `Dhall.substitutions` mechanism of the Haskell dhall package, and which can be used e.g. like this: ```rust serde_dhall.from_str(...) .substitute_names(hashmap!["Newtype" => static_type]) .parse::<SimpleType>()? ``` The idea behind this is to make it easy to add programmer-defined types which may be used in configs for programs, without forcing the program's users to re-import the same type definitions each time (or the programmers to keep the dhall-based definitions in sync with their rust types, since these are now generated automatically). Caveats so far: - makes some of the code ugly (dhall internals are now used in serde_dhall/src/lib.rs, for example) - haven't tested error messages so far - some unecessary copying of strings and static type values
Diffstat (limited to 'serde_dhall/src')
-rw-r--r--serde_dhall/src/options/de.rs30
1 files changed, 28 insertions, 2 deletions
diff --git a/serde_dhall/src/options/de.rs b/serde_dhall/src/options/de.rs
index 103f161..a070af7 100644
--- a/serde_dhall/src/options/de.rs
+++ b/serde_dhall/src/options/de.rs
@@ -1,4 +1,5 @@
use std::path::{Path, PathBuf};
+use std::collections::HashMap;
use dhall::{Ctxt, Parsed};
@@ -58,6 +59,7 @@ pub struct Deserializer<'a, A> {
source: Source<'a>,
annot: A,
allow_imports: bool,
+ substitutions: HashMap<dhall::syntax::Label, dhall::syntax::Expr>,
// allow_remote_imports: bool,
// use_cache: bool,
}
@@ -68,6 +70,7 @@ impl<'a> Deserializer<'a, NoAnnot> {
source,
annot: NoAnnot,
allow_imports: true,
+ substitutions: HashMap::new(),
// allow_remote_imports: true,
// use_cache: true,
}
@@ -131,6 +134,7 @@ impl<'a> Deserializer<'a, NoAnnot> {
annot: ManualAnnot(ty),
source: self.source,
allow_imports: self.allow_imports,
+ substitutions: self.substitutions,
}
}
@@ -181,6 +185,7 @@ impl<'a> Deserializer<'a, NoAnnot> {
annot: StaticAnnot,
source: self.source,
allow_imports: self.allow_imports,
+ substitutions: self.substitutions,
}
}
}
@@ -223,6 +228,18 @@ impl<'a, A> Deserializer<'a, A> {
// self
// }
+ pub fn substitute_names(self, substs: HashMap<String, SimpleType>) -> Self {
+ Deserializer {
+ substitutions: substs
+ .iter()
+ .map(|(s, ty)| {
+ (dhall::syntax::Label::from_str(s), ty.to_expr())
+ })
+ .collect(),
+ ..self
+ }
+ }
+
fn _parse<T>(&self) -> dhall::error::Result<Result<Value>>
where
A: TypeAnnot,
@@ -234,11 +251,20 @@ impl<'a, A> Deserializer<'a, A> {
Source::File(p) => Parsed::parse_file(p.as_ref())?,
Source::BinaryFile(p) => Parsed::parse_binary_file(p.as_ref())?,
};
+
+ let parsed_with_substs = self
+ .substitutions
+ .iter()
+ .fold(parsed, |acc, (name, subst)| {
+ acc.substitute_name(name.clone(), subst.clone())
+ });
+
let resolved = if self.allow_imports {
- parsed.resolve(cx)?
+ parsed_with_substs.resolve(cx)?
} else {
- parsed.skip_resolve(cx)?
+ parsed_with_substs.skip_resolve(cx)?
};
+ //println!("{:#?}", resolved);
let typed = match &T::get_annot(self.annot) {
None => resolved.typecheck(cx)?,
Some(ty) => resolved.typecheck_with(cx, &ty.to_hir())?,