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 --- serde_dhall/src/deserialize.rs | 124 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 serde_dhall/src/deserialize.rs (limited to 'serde_dhall/src/deserialize.rs') 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 + } +} -- cgit v1.2.3 From 002d7c2a74647312a821598ac3d9f5521296873d Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 21:25:44 +0000 Subject: Add a bunch of TODOs --- serde_dhall/src/deserialize.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 75a08a9..cccadad 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -16,9 +16,10 @@ pub trait Sealed {} /// can deserialize. /// /// This trait cannot be implemented manually. +/// +/// TODO pub trait Deserialize: Sealed + Sized { #[doc(hidden)] - /// See [serde_dhall::from_str][crate::from_str] fn from_dhall(v: &Value) -> Result; } -- cgit v1.2.3 From f598e3612a854076b570bbc9c88abcdc1da528bd Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 22:17:22 +0000 Subject: Rework SimpleValue --- serde_dhall/src/deserialize.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index cccadad..43b7914 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use dhall::syntax::NumKind; -use crate::simple::{ValKind, Value as SimpleValue}; +use crate::simple::SimpleValue; use crate::{Error, Result, Value}; pub trait Sealed {} @@ -58,10 +58,10 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { { use std::convert::TryInto; use NumKind::*; - use ValKind::*; + use SimpleValue::*; let val = |x| Deserializer(Cow::Borrowed(x)); - match self.0.kind() { + match self.0.as_ref() { Num(Bool(x)) => visitor.visit_bool(*x), Num(Natural(x)) => { if let Ok(x64) = (*x).try_into() { @@ -109,9 +109,9 @@ impl<'de: 'a, 'a> serde::Deserializer<'de> for Deserializer<'a> { V: serde::de::Visitor<'de>, { let val = |x| Deserializer(Cow::Borrowed(x)); - match self.0.kind() { + match self.0.as_ref() { // Blindly takes keys in sorted order. - ValKind::Record(m) => visitor + SimpleValue::Record(m) => visitor .visit_seq(SeqDeserializer::new(m.iter().map(|(_, v)| val(v)))), _ => self.deserialize_any(visitor), } -- cgit v1.2.3 From 3a5f2044954aae7278f16e30561a81626dba6923 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 22 Mar 2020 22:27:56 +0000 Subject: Move mod simple into value --- serde_dhall/src/deserialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 43b7914..ab5580e 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use dhall::syntax::NumKind; -use crate::simple::SimpleValue; +use crate::value::SimpleValue; use crate::{Error, Result, Value}; pub trait Sealed {} -- cgit v1.2.3 From f9848b54fe2e64901042fba66fb471999f415ff1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 24 Mar 2020 18:53:25 +0000 Subject: Hide serde Error internals --- serde_dhall/src/deserialize.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index ab5580e..7bb0051 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -6,7 +6,7 @@ use std::borrow::Cow; use dhall::syntax::NumKind; use crate::value::SimpleValue; -use crate::{Error, Result, Value}; +use crate::{Error, ErrorKind, Result, Value}; pub trait Sealed {} @@ -33,10 +33,10 @@ where { fn from_dhall(v: &Value) -> Result { let sval = v.to_simple_value().ok_or_else(|| { - Error::Deserialize(format!( + Error(ErrorKind::Deserialize(format!( "this cannot be deserialized into the serde data model: {}", v - )) + ))) })?; T::deserialize(Deserializer(Cow::Owned(sval))) } -- cgit v1.2.3 From 060c835db9638556763b98cfcf7c4be196653644 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 24 Mar 2020 19:42:48 +0000 Subject: More doc --- serde_dhall/src/deserialize.rs | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 7bb0051..b9b711c 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -10,26 +10,44 @@ use crate::{Error, ErrorKind, Result, Value}; pub trait Sealed {} -/// A data structure that can be deserialized from a Dhall expression +/// A data structure that can be deserialized from a Dhall expression. /// -/// This is automatically implemented for any type that [serde][serde] -/// can deserialize. +/// This is automatically implemented for any type that [serde] can deserialize. +/// In fact, this trait cannot be implemented manually. To implement it for your type, +/// use serde's derive mechanism. /// -/// This trait cannot be implemented manually. +/// # Example /// -/// TODO +/// ```rust +/// # fn main() -> serde_dhall::Result<()> { +/// use serde::Deserialize; +/// +/// // Use serde's derive +/// #[derive(Deserialize)] +/// struct Point { +/// x: u64, +/// y: u64, +/// } +/// +/// // Convert a Dhall string to a Point. +/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }")?; +/// # Ok(()) +/// # } +/// ``` +/// +/// [serde]: https://serde.rs pub trait Deserialize: Sealed + Sized { #[doc(hidden)] fn from_dhall(v: &Value) -> Result; } -impl<'a, T> Sealed for T where T: serde::Deserialize<'a> {} +impl Sealed for T where T: serde::de::DeserializeOwned {} struct Deserializer<'a>(Cow<'a, SimpleValue>); -impl<'a, T> Deserialize for T +impl Deserialize for T where - T: serde::Deserialize<'a>, + T: serde::de::DeserializeOwned, { fn from_dhall(v: &Value) -> Result { let sval = v.to_simple_value().ok_or_else(|| { -- cgit v1.2.3 From 15a0902b50ff6d1b36dbf7a220b6ff42ceefada6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 11:43:22 +0100 Subject: Rename Deserialize trait to FromDhall --- serde_dhall/src/deserialize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index b9b711c..1be68c4 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -36,7 +36,7 @@ pub trait Sealed {} /// ``` /// /// [serde]: https://serde.rs -pub trait Deserialize: Sealed + Sized { +pub trait FromDhall: Sealed + Sized { #[doc(hidden)] fn from_dhall(v: &Value) -> Result; } @@ -45,7 +45,7 @@ impl Sealed for T where T: serde::de::DeserializeOwned {} struct Deserializer<'a>(Cow<'a, SimpleValue>); -impl Deserialize for T +impl FromDhall for T where T: serde::de::DeserializeOwned, { -- cgit v1.2.3 From 678d254a06dbb75f5398abaacee41d1712bf7194 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Apr 2020 15:53:15 +0100 Subject: Make Deserializer functions the only functions --- serde_dhall/src/deserialize.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'serde_dhall/src/deserialize.rs') diff --git a/serde_dhall/src/deserialize.rs b/serde_dhall/src/deserialize.rs index 1be68c4..92be2e9 100644 --- a/serde_dhall/src/deserialize.rs +++ b/serde_dhall/src/deserialize.rs @@ -30,7 +30,7 @@ pub trait Sealed {} /// } /// /// // Convert a Dhall string to a Point. -/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }")?; +/// let point: Point = serde_dhall::from_str("{ x = 1, y = 1 + 1 }").parse()?; /// # Ok(()) /// # } /// ``` -- cgit v1.2.3