From 0ea1399a45a01b6505224bef5b297df39eb9786c Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 19 Jan 2023 10:37:39 -0600 Subject: [PATCH] feat(toml): Make `Table` first class With #457, we've started to make a harder distinction between documents and values in `de`. We are looking to do similar for `ser` which requires us to do this for `Table`/`Value` as well. Fixes #367 --- crates/toml/src/lib.rs | 21 ++- crates/toml/src/value.rs | 322 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 326 insertions(+), 17 deletions(-) diff --git a/crates/toml/src/lib.rs b/crates/toml/src/lib.rs index 6897044b..d68d9bea 100644 --- a/crates/toml/src/lib.rs +++ b/crates/toml/src/lib.rs @@ -17,7 +17,7 @@ //! //! ## TOML values //! -//! A value in TOML is represented with the [`Value`] enum in this crate: +//! A TOML document is represented with the [`Table`] type which maps `String` to the [`Value`] enum: //! //! ```rust,ignore //! pub enum Value { @@ -31,25 +31,21 @@ //! } //! ``` //! -//! TOML is similar to JSON with the notable addition of a [`Datetime`] -//! type. In general, TOML and JSON are interchangeable in terms of -//! formats. -//! //! ## Parsing TOML //! -//! The easiest way to parse a TOML document is via the [`Value`] type: +//! The easiest way to parse a TOML document is via the [`Table`] type: //! //! ```rust -//! use toml::Value; +//! use toml::Table; //! -//! let value = "foo = 'bar'".parse::().unwrap(); +//! let value = "foo = 'bar'".parse::().unwrap(); //! //! assert_eq!(value["foo"].as_str(), Some("bar")); //! ``` //! -//! The [`Value`] type implements a number of convenience methods and +//! The [`Table`] type implements a number of convenience methods and //! traits; the example above uses [`FromStr`] to parse a [`str`] into a -//! [`Value`]. +//! [`Table`]. //! //! ## Deserialization and Serialization //! @@ -57,16 +53,19 @@ //! implementations of the `Deserialize`, `Serialize`, `Deserializer`, and //! `Serializer` traits. Namely, you'll find: //! +//! * `Deserialize for Table` +//! * `Serialize for Table` //! * `Deserialize for Value` //! * `Serialize for Value` //! * `Deserialize for Datetime` //! * `Serialize for Datetime` //! * `Deserializer for de::Deserializer` //! * `Serializer for ser::Serializer` +//! * `Deserializer for Table` //! * `Deserializer for Value` //! //! This means that you can use Serde to deserialize/serialize the -//! [`Value`] type as well as the [`Datetime`] type in this crate. You can also +//! [`Table`] type as well as [`Value`] and [`Datetime`] type in this crate. You can also //! use the [`Deserializer`], [`Serializer`], or [`Value`] type itself to act as //! a deserializer/serializer for arbitrary types. //! diff --git a/crates/toml/src/value.rs b/crates/toml/src/value.rs index 3fbae546..775b76d7 100644 --- a/crates/toml/src/value.rs +++ b/crates/toml/src/value.rs @@ -22,6 +22,33 @@ pub use crate::map::{Entry, Map}; /// to use a LinkedHashMap instead. pub type Table = Map; +impl Table { + /// Convert a `T` into `toml::Table`. + /// + /// This conversion can fail if `T`'s implementation of `Serialize` decides to + /// fail, or if `T` contains a map with non-string keys. + pub fn try_from(value: T) -> Result + where + T: ser::Serialize, + { + value.serialize(TableSerializer) + } + + /// Interpret a `toml::Table` as an instance of type `T`. + /// + /// This conversion can fail if the structure of the `Table` does not match the structure + /// expected by `T`, for example if `T` is a bool which can't be mapped to a `Table`. It can + /// also fail if the structure is correct but `T`'s implementation of `Deserialize` decides + /// that something is wrong with the data, for example required struct fields are missing from + /// the TOML map or some number is too big to fit in the expected primitive type. + pub fn try_into<'de, T>(self) -> Result + where + T: de::Deserialize<'de>, + { + de::Deserialize::deserialize(self) + } +} + impl fmt::Display for Table { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { crate::ser::to_string(self) @@ -37,6 +64,64 @@ impl FromStr for Table { } } +impl<'de> de::Deserializer<'de> for Table { + type Error = crate::de::Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Value::Table(self).deserialize_any(visitor) + } + + #[inline] + fn deserialize_enum( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + Value::Table(self).deserialize_enum(name, variants, visitor) + } + + // `None` is interpreted as a missing field so be sure to implement `Some` + // as a present field. + fn deserialize_option(self, visitor: V) -> Result + where + V: de::Visitor<'de>, + { + Value::Table(self).deserialize_option(visitor) + } + + fn deserialize_newtype_struct( + self, + name: &'static str, + visitor: V, + ) -> Result + where + V: de::Visitor<'de>, + { + Value::Table(self).deserialize_newtype_struct(name, visitor) + } + + serde::forward_to_deserialize_any! { + bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq + bytes byte_buf map unit_struct tuple_struct struct + tuple ignored_any identifier + } +} + +impl<'de> de::IntoDeserializer<'de, crate::de::Error> for Table { + type Deserializer = Self; + + fn into_deserializer(self) -> Self { + self + } +} + /// Type representing a TOML array, payload of the `Value::Array` variant pub type Array = Vec; @@ -557,6 +642,7 @@ impl<'de> de::Deserialize<'de> for Value { } } +// This is wrapped by `Table` and any trait methods implemented here need to be wrapped there. impl<'de> de::Deserializer<'de> for Value { type Error = crate::de::Error; @@ -675,12 +761,12 @@ impl<'de> de::SeqAccess<'de> for SeqDeserializer { } struct MapDeserializer { - iter: as IntoIterator>::IntoIter, + iter:
::IntoIter, value: Option<(String, Value)>, } impl MapDeserializer { - fn new(map: Map) -> Self { + fn new(map: Table) -> Self { MapDeserializer { iter: map.into_iter(), value: None, @@ -890,6 +976,182 @@ impl ser::Serializer for ValueSerializer { fn serialize_map(self, _len: Option) -> Result { Ok(ValueSerializeMap { + ser: SerializeMap { + map: Map::new(), + next_key: None, + }, + }) + } + + fn serialize_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + self.serialize_map(Some(len)) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(crate::ser::Error::UnsupportedType) + } +} + +struct TableSerializer; + +impl ser::Serializer for TableSerializer { + type Ok = Table; + type Error = crate::ser::Error; + + type SerializeSeq = ser::Impossible; + type SerializeTuple = ser::Impossible; + type SerializeTupleStruct = ser::Impossible; + type SerializeTupleVariant = ser::Impossible; + type SerializeMap = SerializeMap; + type SerializeStruct = SerializeMap; + type SerializeStructVariant = ser::Impossible; + + fn serialize_bool(self, _value: bool) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_i8(self, _value: i8) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_i16(self, _value: i16) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_i32(self, _value: i32) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_i64(self, _value: i64) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_u8(self, _value: u8) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_u16(self, _value: u16) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_u32(self, _value: u32) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_u64(self, _value: u64) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_f32(self, _value: f32) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_f64(self, _value: f64) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_char(self, _value: char) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_str(self, _value: &str) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_unit(self) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &T, + ) -> Result + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result + where + T: ser::Serialize, + { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_none(self) -> Result { + Err(crate::ser::Error::UnsupportedNone) + } + + fn serialize_some(self, value: &T) -> Result + where + T: ser::Serialize, + { + value.serialize(self) + } + + fn serialize_seq(self, _len: Option) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + Err(crate::ser::Error::UnsupportedType) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(SerializeMap { map: Map::new(), next_key: None, }) @@ -983,13 +1245,13 @@ impl ser::SerializeTupleVariant for ValueSerializeVec { } } -struct ValueSerializeMap { +struct SerializeMap { map: Map, next_key: Option, } -impl ser::SerializeMap for ValueSerializeMap { - type Ok = Value; +impl ser::SerializeMap for SerializeMap { + type Ok = Table; type Error = crate::ser::Error; fn serialize_key(&mut self, key: &T) -> Result<(), crate::ser::Error> @@ -1019,8 +1281,56 @@ impl ser::SerializeMap for ValueSerializeMap { Ok(()) } + fn end(self) -> Result { + Ok(self.map) + } +} + +impl ser::SerializeStruct for SerializeMap { + type Ok = Table; + type Error = crate::ser::Error; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), crate::ser::Error> + where + T: ser::Serialize, + { + ser::SerializeMap::serialize_key(self, key)?; + ser::SerializeMap::serialize_value(self, value) + } + + fn end(self) -> Result { + ser::SerializeMap::end(self) + } +} + +struct ValueSerializeMap { + ser: SerializeMap, +} + +impl ser::SerializeMap for ValueSerializeMap { + type Ok = Value; + type Error = crate::ser::Error; + + fn serialize_key(&mut self, key: &T) -> Result<(), crate::ser::Error> + where + T: ser::Serialize, + { + self.ser.serialize_key(key) + } + + fn serialize_value(&mut self, value: &T) -> Result<(), crate::ser::Error> + where + T: ser::Serialize, + { + self.ser.serialize_value(value) + } + fn end(self) -> Result { - Ok(Value::Table(self.map)) + self.ser.end().map(Value::Table) } }