From e070270c3f1f10d46281ed7751ff95e15092e7f4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 10 May 2020 22:09:43 +0100 Subject: Implement serialization --- serde_dhall/src/options.rs | 372 --------------------------------------------- 1 file changed, 372 deletions(-) delete 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 deleted file mode 100644 index 7b27114..0000000 --- a/serde_dhall/src/options.rs +++ /dev/null @@ -1,372 +0,0 @@ -use std::path::{Path, PathBuf}; - -use dhall::Parsed; - -use crate::SimpleType; -use crate::{Error, ErrorKind, FromDhall, Result, StaticType, Value}; - -#[derive(Debug, Clone)] -enum Source<'a> { - Str(&'a str), - File(PathBuf), - // Url(&'a str), -} - -#[derive(Debug, Clone, Copy)] -pub struct NoAnnot; -#[derive(Debug, Clone, Copy)] -pub struct ManualAnnot<'ty>(&'ty SimpleType); -#[derive(Debug, Clone, Copy)] -pub struct StaticAnnot; - -pub trait HasAnnot { - fn get_annot(a: &A) -> Option; -} -impl HasAnnot for T { - fn get_annot(_: &NoAnnot) -> Option { - None - } -} -impl<'ty, T> HasAnnot> for T { - fn get_annot(a: &ManualAnnot<'ty>) -> Option { - Some(a.0.clone()) - } -} -impl HasAnnot for T { - fn get_annot(_: &StaticAnnot) -> Option { - Some(T::static_type()) - } -} - -/// Controls 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. -/// -/// Generally speaking, when using [`Deserializer`], 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 -/// [`Result`] where `T` is a deserializable type of your choice. -/// -/// [`Deserializer`]: struct.Deserializer.html -/// [`from_str`]: fn.from_str.html -/// [`from_file`]: fn.from_file.html -/// [`parse`]: struct.Deserializer.html#method.parse -/// [`Result`]: type.Result.html -/// -/// # Examples -/// -/// Reading from a file: -/// -/// ```no_run -/// # fn main() -> serde_dhall::Result<()> { -/// use serde_dhall::from_file; -/// -/// let data = 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 std::collections::HashMap; -/// use serde_dhall::{from_file, from_str}; -/// -/// let ty = from_str("{ x: Natural, y: Natural }").parse()?; -/// let data = from_file("foo.dhall") -/// .type_annotation(&ty) -/// .parse::>()?; -/// # Ok(()) -/// # } -/// ``` -#[derive(Debug, Clone)] -pub struct Deserializer<'a, A> { - source: Source<'a>, - annot: A, - allow_imports: bool, - // allow_remote_imports: bool, - // use_cache: bool, -} - -impl<'a> Deserializer<'a, NoAnnot> { - fn default_with_source(source: Source<'a>) -> Self { - Deserializer { - source, - annot: NoAnnot, - allow_imports: true, - // allow_remote_imports: true, - // use_cache: true, - } - } - 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)) - // } - - /// Ensures that the parsed value matches the provided type. - /// - /// In many cases the Dhall type that corresponds to a Rust type can be inferred automatically. - /// See the [`StaticType`] trait and the [`static_type_annotation`] method for that. - /// - /// # Example - /// - /// ``` - /// # fn main() -> serde_dhall::Result<()> { - /// use std::collections::HashMap; - /// use serde::Deserialize; - /// use serde_dhall::{from_str, SimpleType}; - /// - /// // Parse a Dhall type - /// let type_str = "{ x: Natural, y: Natural }"; - /// let ty = from_str(type_str).parse::()?; - /// - /// // Parse some Dhall data. - /// let data = "{ x = 1, y = 1 + 1 }"; - /// let point = from_str(data) - /// .type_annotation(&ty) - /// .parse::>()?; - /// assert_eq!(point.get("y"), Some(&2)); - /// - /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. - /// let invalid_data = "{ x = 1, z = 3 }"; - /// assert!( - /// from_str(invalid_data) - /// .type_annotation(&ty) - /// .parse::>() - /// .is_err() - /// ); - /// # Ok(()) - /// # } - /// ``` - /// - /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation - /// [`StaticType`]: trait.StaticType.html - pub fn type_annotation<'ty>( - self, - ty: &'ty SimpleType, - ) -> Deserializer<'a, ManualAnnot<'ty>> { - Deserializer { - annot: ManualAnnot(ty), - source: self.source, - allow_imports: self.allow_imports, - } - } - - /// Ensures that the parsed value matches the type of `T`. - /// - /// `T` must implement the [`StaticType`] trait. If it doesn't, you can use [`type_annotation`] - /// to provide a type manually. - /// - /// # Example - /// - /// ``` - /// # fn main() -> serde_dhall::Result<()> { - /// use serde::Deserialize; - /// use serde_dhall::StaticType; - /// - /// #[derive(Deserialize, StaticType)] - /// struct Point { - /// x: u64, - /// y: Option, - /// } - /// - /// // Some Dhall data - /// let data = "{ x = 1, y = Some (1 + 1) }"; - /// - /// // Convert the Dhall string to a Point. - /// let point = serde_dhall::from_str(data) - /// .static_type_annotation() - /// .parse::()?; - /// assert_eq!(point.x, 1); - /// assert_eq!(point.y, Some(2)); - /// - /// // Invalid data fails the type validation; deserialization would have succeeded otherwise. - /// let invalid_data = "{ x = 1 }"; - /// assert!( - /// serde_dhall::from_str(invalid_data) - /// .static_type_annotation() - /// .parse::() - /// .is_err() - /// ); - /// # Ok(()) - /// # } - /// ``` - /// - /// [`type_annotation`]: struct.Deserializer.html#method.type_annotation - /// [`StaticType`]: trait.StaticType.html - pub fn static_type_annotation(self) -> Deserializer<'a, StaticAnnot> { - Deserializer { - annot: StaticAnnot, - source: self.source, - allow_imports: self.allow_imports, - } - } -} - -impl<'a, A> Deserializer<'a, A> { - /// Sets whether to enable imports. - /// - /// By default, imports are enabled. - /// - /// # Example - /// - /// ``` - /// # fn main() -> serde_dhall::Result<()> { - /// use serde::Deserialize; - /// use serde_dhall::SimpleType; - /// - /// let data = "12 + ./other_file.dhall : Natural"; - /// assert!( - /// serde_dhall::from_str(data) - /// .imports(false) - /// .parse::() - /// .is_err() - /// ); - /// # Ok(()) - /// # } - /// ``` - /// - /// [`static_type_annotation`]: struct.Deserializer.html#method.static_type_annotation - /// [`StaticType`]: trait.StaticType.html - pub fn imports(self, imports: bool) -> Self { - Deserializer { - allow_imports: imports, - ..self - } - } - - // /// TODO - // pub fn remote_imports(&mut self, imports: bool) -> &mut Self { - // self.allow_remote_imports = imports; - // if imports { - // self.allow_imports = true; - // } - // self - // } - - fn _parse(&self) -> dhall::error::Result - where - T: HasAnnot, - { - 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 &T::get_annot(&self.annot) { - None => resolved.typecheck()?, - Some(ty) => resolved.typecheck_with(ty.to_value().as_hir())?, - }; - Ok(Value::from_nir(typed.normalize().as_nir())) - } - - /// Parses the chosen dhall value with the options provided. - /// - /// If you enabled static annotations, `T` is required to implement [`StaticType`]. - /// - /// - /// # Example - /// - /// ``` - /// # fn main() -> serde_dhall::Result<()> { - /// let data = serde_dhall::from_str("6 * 7").parse::()?; - /// assert_eq!(data, 42); - /// # Ok(()) - /// # } - /// ``` - /// [`StaticType`]: trait.StaticType.html - pub fn parse(&self) -> Result - where - T: FromDhall + HasAnnot, - { - let val = self - ._parse::() - .map_err(ErrorKind::Dhall) - .map_err(Error)?; - T::from_dhall(&val) - } -} - -/// Deserialize a value from a string of Dhall text. -/// -/// This returns a [`Deserializer`] object. Call the [`parse`] method to get the deserialized -/// value, or use other [`Deserializer`] methods to control the deserialization process. -/// -/// Imports will be resolved relative to the current directory. -/// -/// # Example -/// -/// ```rust -/// # fn main() -> serde_dhall::Result<()> { -/// use serde::Deserialize; -/// -/// // We use serde's derive feature -/// #[derive(Deserialize)] -/// struct Point { -/// x: u64, -/// y: u64, -/// } -/// -/// // Some Dhall data -/// let data = "{ x = 1, y = 1 + 1 } : { x: Natural, y: Natural }"; -/// -/// // Parse the Dhall string as a Point. -/// let point: Point = serde_dhall::from_str(data).parse()?; -/// -/// assert_eq!(point.x, 1); -/// assert_eq!(point.y, 2); -/// # Ok(()) -/// # } -/// ``` -/// -/// [`Deserializer`]: struct.Deserializer.html -/// [`parse`]: struct.Deserializer.html#method.parse -pub fn from_str(s: &str) -> Deserializer<'_, NoAnnot> { - Deserializer::from_str(s) -} - -/// Deserialize a value from a Dhall file. -/// -/// This returns a [`Deserializer`] object. Call the [`parse`] method to get the deserialized -/// value, or use other [`Deserializer`] methods to control the deserialization process. -/// -/// Imports will be resolved relative to the provided file's path. -/// -/// # Example -/// -/// ```no_run -/// # fn main() -> serde_dhall::Result<()> { -/// use serde::Deserialize; -/// -/// // We use serde's derive feature -/// #[derive(Deserialize)] -/// struct Point { -/// x: u64, -/// y: u64, -/// } -/// -/// // Parse the Dhall file as a Point. -/// let point: Point = serde_dhall::from_file("foo.dhall").parse()?; -/// # Ok(()) -/// # } -/// ``` -/// -/// [`Deserializer`]: struct.Deserializer.html -/// [`parse`]: struct.Deserializer.html#method.parse -pub fn from_file<'a, P: AsRef>(path: P) -> Deserializer<'a, NoAnnot> { - Deserializer::from_file(path) -} - -// pub fn from_url(url: &str) -> Deserializer<'_, NoAnnot> { -// Deserializer::from_url(url) -// } -- cgit v1.2.3