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.
///