diff --git a/serde/src/de/impls.rs b/serde/src/de/impls.rs index c5aaca723..00c862af9 100644 --- a/serde/src/de/impls.rs +++ b/serde/src/de/impls.rs @@ -1,7 +1,8 @@ use lib::*; use de::{ - Deserialize, Deserializer, EnumAccess, Error, SeqAccess, Unexpected, VariantAccess, Visitor, + Deserialize, DeserializeEmbed, Deserializer, EnumAccess, Error, SeqAccess, Storage, Unexpected, + VariantAccess, Visitor, }; #[cfg(any(feature = "std", feature = "alloc", not(no_core_duration)))] @@ -14,7 +15,7 @@ use __private::size_hint; //////////////////////////////////////////////////////////////////////////////// -struct UnitVisitor; +pub struct UnitVisitor; impl<'de> Visitor<'de> for UnitVisitor { type Value = (); @@ -31,6 +32,23 @@ impl<'de> Visitor<'de> for UnitVisitor { } } +impl<'de> Storage<'de> for UnitVisitor { + type Key = (); + + #[inline] + fn is_known(_key: &Self::Key) -> bool { + true + } + + #[inline] + fn consume_value(&mut self, _key: Self::Key, map: A) -> Result + where + A: MapAccess<'de>, + { + Ok(map) + } +} + impl<'de> Deserialize<'de> for () { fn deserialize(deserializer: D) -> Result where @@ -40,6 +58,29 @@ impl<'de> Deserialize<'de> for () { } } +impl<'de> DeserializeEmbed<'de> for () { + type Storage = UnitVisitor; + type KeyVisitor = UnitVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + UnitVisitor + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + UnitVisitor + } + + #[inline] + fn deserialize_embed(_storage: Self::Storage) -> Result + where + E: Error, + { + Ok(()) + } +} + #[cfg(feature = "unstable")] impl<'de> Deserialize<'de> for ! { fn deserialize(_deserializer: D) -> Result @@ -822,6 +863,32 @@ where // deserialize_in_place the value is profitable (probably data-dependent?) } +impl<'de, T> DeserializeEmbed<'de> for Option +where + T: DeserializeEmbed<'de>, +{ + type Storage = T::Storage; + type KeyVisitor = T::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + T::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + T::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + Ok(T::deserialize_embed::(storage).ok()) + } +} + //////////////////////////////////////////////////////////////////////////////// struct PhantomDataVisitor { @@ -1420,6 +1487,112 @@ map_impl!( //////////////////////////////////////////////////////////////////////////////// +/// Implements [`DeserializeEmbed`] for maps. +/// +/// Example: +/// ```ignore +/// impl_deserialize_embed_for_map!(pub BTreeMap, BTreeMapStorage); +/// ``` +/// +/// # Parameters +/// - `vis`: visibility marker. [`Storage`] struct will be declared with such visibility +/// - `map`: name of map struct, followed by template parameters for keys +/// and values, optionally constrained by bounds. Any number of additional +/// parameters also permitted +/// - `storage`: name of generated structure for intermediate storage of values, +/// extracted from the map +/// +/// [`DeserializeEmbed`]: ./trait.DeserializeEmbed.html +/// [`Storage`]: ./trait.Storage.html +#[macro_export(local_inner_macros)] +macro_rules! impl_deserialize_embed_for_map { + ( + $vis:vis + $map:ident < $k:ident $(: $kbound1:ident $(+ $kbound2:ident)*)*, $v:ident $(, $typaram:ident : $bound1:ident $(+ $bound2:ident)*)* >, + $storage:ident + ) => { + $vis struct $storage<$k, $v $(, $typaram)*>($map<$k, $v $(, $typaram)*>); + + impl<$k, $v $(, $typaram)*> Default for $storage<$k, $v $(, $typaram)*> + where + $k $(: $kbound1 $(+ $kbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*),* + { + fn default() -> Self { Self(Default::default()) } + } + + impl<'de, $k, $v $(, $typaram)*> Visitor<'de> for $storage<$k, $v $(, $typaram)*> + where + $k: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Value = $k; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("a map key") + } + //TODO: Implement visitor + } + + impl<'de, $k, $v $(, $typaram)*> Storage<'de> for $storage<$k, $v $(, $typaram)*> + where + $k: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + $v: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Key = $k; + + #[inline] + fn is_known(_key: &Self::Key) -> bool { true } + + #[inline] + fn consume_value(&mut self, key: Self::Key, mut map: A) -> Result + where + A: MapAccess<'de> + { + self.0.insert(key, map.next_value()?); + Ok(map) + } + } + + impl<'de, $k, $v $(, $typaram)*> DeserializeEmbed<'de> for $map<$k, $v $(, $typaram)*> + where + $k: Deserialize<'de> $(+ $kbound1 $(+ $kbound2)*)*, + $v: Deserialize<'de>, + $($typaram: $bound1 $(+ $bound2)*),* + { + type Storage = $storage<$k, $v $(, $typaram)*>; + type KeyVisitor = $storage<$k, $v $(, $typaram)*>; + + #[inline] + fn new_storage() -> Self::Storage { + Self::KeyVisitor::default() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + Self::KeyVisitor::default() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + Ok(storage.0) + } + } + } +} + +#[cfg(any(feature = "std", feature = "alloc"))] +impl_deserialize_embed_for_map!(pub BTreeMap, BTreeMapStorage); + +#[cfg(feature = "std")] +impl_deserialize_embed_for_map!(pub HashMap, HashMapStorage); + +//////////////////////////////////////////////////////////////////////////////// + #[cfg(feature = "std")] macro_rules! parse_ip_impl { ($expecting:tt $ty:ty; $size:tt) => { @@ -1834,6 +2007,34 @@ where } } +#[cfg(any(feature = "std", feature = "alloc"))] +impl<'de, 'a, T> DeserializeEmbed<'de> for Cow<'a, T> +where + T: ToOwned, + T::Owned: DeserializeEmbed<'de>, +{ + type Storage = >::Storage; + type KeyVisitor = >::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + >::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + >::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + T::Owned::deserialize_embed(storage).map(Cow::Owned) + } +} + //////////////////////////////////////////////////////////////////////////////// /// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting @@ -1841,7 +2042,7 @@ where /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl<'de, T: ?Sized> Deserialize<'de> for RcWeak +impl<'de, T> Deserialize<'de> for RcWeak where T: Deserialize<'de>, { @@ -1859,7 +2060,39 @@ where /// /// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc #[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] -impl<'de, T: ?Sized> Deserialize<'de> for ArcWeak +impl<'de, T> DeserializeEmbed<'de> for RcWeak +where + T: DeserializeEmbed<'de>, +{ + type Storage = T::Storage; + type KeyVisitor = T::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + T::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + T::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + try!(Option::::deserialize_embed(storage)); + Ok(RcWeak::new()) + } +} + +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<'de, T> Deserialize<'de> for ArcWeak where T: Deserialize<'de>, { @@ -1872,6 +2105,38 @@ where } } +/// This impl requires the [`"rc"`] Cargo feature of Serde. The resulting +/// `Weak` has a reference count of 0 and cannot be upgraded. +/// +/// [`"rc"`]: https://serde.rs/feature-flags.html#-features-rc +#[cfg(all(feature = "rc", any(feature = "std", feature = "alloc")))] +impl<'de, T> DeserializeEmbed<'de> for ArcWeak +where + T: DeserializeEmbed<'de>, +{ + type Storage = T::Storage; + type KeyVisitor = T::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + T::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + T::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + try!(Option::::deserialize_embed(storage)); + Ok(ArcWeak::new()) + } +} + //////////////////////////////////////////////////////////////////////////////// #[cfg(all( @@ -1896,6 +2161,33 @@ macro_rules! box_forwarded_impl { Box::deserialize(deserializer).map(Into::into) } } + + $(#[doc = $doc])* + impl<'de, T> DeserializeEmbed<'de> for $t + where + Box: DeserializeEmbed<'de>, + { + type Storage = as DeserializeEmbed<'de>>::Storage; + type KeyVisitor = as DeserializeEmbed<'de>>::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + as DeserializeEmbed<'de>>::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + as DeserializeEmbed<'de>>::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + Box::deserialize_embed(storage).map(Into::into) + } + } }; } @@ -1945,6 +2237,32 @@ where } } +impl<'de, T> DeserializeEmbed<'de> for Cell +where + T: DeserializeEmbed<'de> + Copy, +{ + type Storage = T::Storage; + type KeyVisitor = T::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + T::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + T::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + T::deserialize_embed(storage).map(Cell::new) + } +} + forwarded_impl!((T), RefCell, RefCell::new); #[cfg(feature = "std")] @@ -2661,6 +2979,33 @@ where } } +#[cfg(feature = "std")] +impl<'de, T> DeserializeEmbed<'de> for Wrapping +where + T: DeserializeEmbed<'de>, +{ + type Storage = T::Storage; + type KeyVisitor = T::KeyVisitor; + + #[inline] + fn new_storage() -> Self::Storage { + T::new_storage() + } + + #[inline] + fn new_visitor() -> Self::KeyVisitor { + T::new_visitor() + } + + #[inline] + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error, + { + T::deserialize_embed(storage).map(Wrapping) + } +} + #[cfg(all(feature = "std", not(no_std_atomic)))] macro_rules! atomic_impl { ($($ty:ident)*) => { diff --git a/serde/src/de/mod.rs b/serde/src/de/mod.rs index 4ae477386..31170ef5f 100644 --- a/serde/src/de/mod.rs +++ b/serde/src/de/mod.rs @@ -790,6 +790,116 @@ where //////////////////////////////////////////////////////////////////////////////// +/// A data structure that can be represented in the parent structure as part +/// of that structure, without explicit indication of beginning and ending of its +/// boundaries. Only such structures can be used with `#[serde(flatten)]` attribute. +/// +/// When deserialized, embedded types created with help of their builders. Associated +/// type `Storage` is responsible to hold all intermediate data fields of the type +/// until all values will be consumed from the shared map, that holds fields of parent +/// and embedded types. +/// +/// # Derive implementation +/// When derived with `#[derive(Deserialize)]`, that trait is implemented for structs. +/// +/// This trait has special implementation for the [`HashMap`] and the [`BTreeMap`], +/// allowing them to consume all fields, that do not be consumed by named fields +/// of struct. Be noted, that if your type contains `#[serde(flatten)]` struct and +/// the map, then map field should be the last field, because derived implementation +/// try to supply fields to each embedded fields in that order in which their is +/// declared in the struct, and so how maps always consumes all keys, all following +/// fields after the map won't get anything. +/// +/// Another consequence of this implementation is that if you contain embedded maps +/// in both parent and embedded struct, all unknown keys go to the internal map: +/// +/// ```edition2018,no_run +/// # use std::collections::HashMap; +/// # use serde::Deserialize; +/// # mod serde_json { pub fn from_str(_: &str) -> Result { unreachable!() } } +/// #[derive(Debug, Deserialize, PartialEq)] +/// struct Parent { +/// #[serde(flatten)] +/// field: Embedded, +/// #[serde(flatten)] +/// outer: HashMap, +/// } +/// #[derive(Debug, Deserialize, PartialEq)] +/// struct Embedded { +/// #[serde(flatten)] +/// inner: HashMap, +/// } +/// +/// let data: Parent = serde_json::from_str(r#"{ "answer": 42 }"#).unwrap(); +/// assert_eq!(data, Parent { +/// field: Embedded { +/// inner: [("answer".to_string(), 42)].iter().cloned().collect() +/// }, +/// outer: HashMap::new(), +/// }); +/// ``` +/// +/// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html +/// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html +pub trait DeserializeEmbed<'de>: Sized { + /// Type used to collect fields during deserialization + type Storage: Storage<'de>; + /// Type for fields identifiers extraction + type KeyVisitor: Visitor<'de, Value = >::Key>; + + /// Creates the new storage, that will be used to collect fields of that type. + fn new_storage() -> Self::Storage; + + /// Creates the new visitor, that will be used to collect fields of that type. + fn new_visitor() -> Self::KeyVisitor; + + /// Creates final value from intermediate representation stored in `storage`. + /// + /// Building value can perform checks, such as presence of all fields and + /// absence of duplicated fields. + /// + /// # Derive implementation + /// When derived, this method checks, that all fields present. Checking for + /// duplicating fields performed in the [`consume_value()`] method. + /// + /// [`consume_value()`]: ./trait.Storage.html#tymethod.consume_value + fn deserialize_embed(storage: Self::Storage) -> Result + where + E: Error; +} + +/// Storage to temporary store components of a deserializable type. +/// +/// Storage is created by calling the [`new_storage()`] method of the `DeserializeEmbed` +/// trait and destructed after calling [`deserialize_embed()`] method. Between that two +/// points all needed fields must be supplied to the storage by calling [`consume_value()`] +/// method. +/// +/// [`new_storage()`]: ./trait.DeserializeEmbed.html#tymethod.new_storage +/// [`deserialize_embed()`]: ./trait.DeserializeEmbed.html#tymethod.deserialize_embed +/// [`consume_value()`]: ./trait.Storage.html#tymethod.consume_value +/// [`Visitor`]: ./trait.Visitor.html +pub trait Storage<'de> { + /// Type for field identifier of structure for which this object is intermediate + /// storage. Usually it is implemented as an enum + type Key; + + /// Checks, that the key is known + fn is_known(key: &Self::Key) -> bool; + + /// Try to extract value for given `key` from the `map`, returns the same map + /// in case of success. + /// + /// # Derive implementation + /// When derived, this method checks, that consumed fields doesn't have duplicates, + /// ie. each `key`, supplied to this method, is unique. + fn consume_value(&mut self, key: Self::Key, map: A) -> Result + where + A: MapAccess<'de>; +} + +//////////////////////////////////////////////////////////////////////////////// + /// A **data format** that can deserialize any data structure supported by /// Serde. ///