From 85e2e8ee5e83dadd05b6974ba6c951350cb97a61 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 21 Mar 2020 21:30:30 +0000 Subject: Introduce option builder --- serde_dhall/src/options.rs | 138 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 serde_dhall/src/options.rs (limited to 'serde_dhall/src/options.rs') diff --git a/serde_dhall/src/options.rs b/serde_dhall/src/options.rs new file mode 100644 index 0000000..542804b --- /dev/null +++ b/serde_dhall/src/options.rs @@ -0,0 +1,138 @@ +use std::path::{Path, PathBuf}; + +use dhall::Parsed; + +use crate::simple::Type as SimpleType; +use crate::{Deserialize, Error, Result, StaticType, Value}; + +#[derive(Debug, Clone)] +enum Source<'a> { + Str(&'a str), + File(PathBuf), + // Url(&'a str), +} + +/// Options and flags which can be used to configure how a dhall value is read. +/// +/// This builder exposes the ability to configure how a value is deserialized and what operations +/// are permitted during evaluation. The functions in the crate root are aliases for +/// commonly used options using this builder. +/// +/// Generally speaking, when using `Options`, you'll create it with `from_str` or `from_file`, then +/// chain calls to methods to set each option, then call `parse`. This will give you a +/// `serde_dhall::Result` where `T` a deserializable type of your choice. +/// +/// # Examples +/// +/// Reading from a file: +/// +/// ```no_run +/// # fn main() -> serde_dhall::Result<()> { +/// use serde_dhall::options; +/// +/// let data = options::from_file("foo.dhall").parse()?; +/// # Ok(()) +/// # } +/// ``` +/// +/// Reading from a file and checking the value against a provided type: +/// +/// ```no_run +/// # fn main() -> serde_dhall::Result<()> { +/// use serde_dhall::options; +/// +/// let ty = options::from_str("{ x: Natural, y: Natural }").parse()?; +/// let data = options::from_file("foo.dhall") +/// .type_annotation(&ty) +/// .parse()?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug, Clone)] +pub struct Options<'a, T> { + source: Source<'a>, + annot: Option, + allow_imports: bool, + // allow_remote_imports: bool, + // use_cache: bool, + target_type: std::marker::PhantomData, +} + +impl<'a, T> Options<'a, T> { + fn default_with_source(source: Source<'a>) -> Self { + Options { + source, + annot: None, + allow_imports: true, + // allow_remote_imports: true, + // use_cache: true, + target_type: std::marker::PhantomData, + } + } + fn from_str(s: &'a str) -> Self { + Self::default_with_source(Source::Str(s)) + } + fn from_file>(path: P) -> Self { + Self::default_with_source(Source::File(path.as_ref().to_owned())) + } + // fn from_url(url: &'a str) -> Self { + // Self::default_with_source(Source::Url(url)) + // } + + pub fn imports(&mut self, imports: bool) -> &mut Self { + self.allow_imports = imports; + self + } + // pub fn remote_imports(&mut self, imports: bool) -> &mut Self { + // self.allow_remote_imports = imports; + // if imports { + // self.allow_imports = true; + // } + // self + // } + pub fn type_annotation(&mut self, ty: &SimpleType) -> &mut Self { + self.annot = Some(ty.clone()); + self + } + pub fn static_type_annotation(&mut self) -> &mut Self + where + T: StaticType, + { + self.annot = Some(T::static_type()); + self + } + + fn _parse(&self) -> dhall::error::Result { + let parsed = match &self.source { + Source::Str(s) => Parsed::parse_str(s)?, + Source::File(p) => Parsed::parse_file(p.as_ref())?, + }; + let resolved = if self.allow_imports { + parsed.resolve()? + } else { + parsed.skip_resolve()? + }; + let typed = match &self.annot { + None => resolved.typecheck()?, + Some(ty) => resolved.typecheck_with(&ty.to_value().hir)?, + }; + Ok(Value::from_nir(typed.normalize().as_nir())) + } + pub fn parse(&self) -> Result + where + T: Deserialize, + { + let val = self._parse().map_err(Error::Dhall)?; + T::from_dhall(&val) + } +} + +pub fn from_str<'a, T>(s: &'a str) -> Options<'a, T> { + Options::from_str(s) +} +pub fn from_file<'a, T, P: AsRef>(path: P) -> Options<'a, T> { + Options::from_file(path) +} +// pub fn from_url<'a, T>(url: &'a str) -> Options<'a, T> { +// Options::from_url(url) +// } -- cgit v1.2.3