summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with/src/de/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/serde_with/src/de/mod.rs')
-rw-r--r--third_party/rust/serde_with/src/de/mod.rs143
1 files changed, 143 insertions, 0 deletions
diff --git a/third_party/rust/serde_with/src/de/mod.rs b/third_party/rust/serde_with/src/de/mod.rs
new file mode 100644
index 0000000000..518b4f2606
--- /dev/null
+++ b/third_party/rust/serde_with/src/de/mod.rs
@@ -0,0 +1,143 @@
+//! Module for [`DeserializeAs`][] implementations
+//!
+//! The module contains the [`DeserializeAs`][] trait and helper code.
+//! Additionally, it contains implementations of [`DeserializeAs`][] for types defined in the Rust Standard Library or this crate.
+//!
+//! You can find more details on how to implement this trait for your types in the documentation of the [`DeserializeAs`][] trait and details about the usage in the [user guide][].
+//!
+//! [user guide]: crate::guide
+
+mod const_arrays;
+mod impls;
+
+use super::*;
+
+/// A **data structure** that can be deserialized from any data format supported by Serde, analogue to [`Deserialize`].
+///
+/// The trait is analogue to the [`serde::Deserialize`][`Deserialize`] trait, with the same meaning of input and output arguments.
+/// It can and should the implemented using the same code structure as the [`Deserialize`] trait.
+/// As such, the same advice for [implementing `Deserialize`][impl-deserialize] applies here.
+///
+/// # Differences to [`Deserialize`]
+///
+/// The trait is only required for container-like types or types implementing specific conversion functions.
+/// Container-like types are [`Vec`], [`BTreeMap`], but also [`Option`] and [`Box`].
+/// Conversion types deserialize into a different Rust type.
+/// For example, [`DisplayFromStr`] uses the [`FromStr`] trait after deserializing a string and [`DurationSeconds`] creates a [`Duration`] from either String or integer values.
+///
+/// This code shows how to implement [`Deserialize`] for [`Box`]:
+///
+/// ```rust,ignore
+/// impl<'de, T: Deserialize<'de>> Deserialize<'de> for Box<T> {
+/// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+/// where
+/// D: Deserializer<'de>,
+/// {
+/// Ok(Box::new(Deserialize::deserialize(deserializer)?))
+/// }
+/// }
+/// ```
+///
+/// and this code shows how to do the same using [`DeserializeAs`][]:
+///
+/// ```rust,ignore
+/// impl<'de, T, U> DeserializeAs<'de, Box<T>> for Box<U>
+/// where
+/// U: DeserializeAs<'de, T>,
+/// {
+/// fn deserialize_as<D>(deserializer: D) -> Result<Box<T>, D::Error>
+/// where
+/// D: Deserializer<'de>,
+/// {
+/// Ok(Box::new(
+/// DeserializeAsWrap::<T, U>::deserialize(deserializer)?.into_inner(),
+/// ))
+/// }
+/// }
+/// ```
+///
+/// It uses two type parameters, `T` and `U` instead of only one and performs the deserialization step using the `DeserializeAsWrap` type.
+/// The `T` type is the on the Rust side after deserialization, whereas the `U` type determines how the value will be deserialized.
+/// These two changes are usually enough to make a container type implement [`DeserializeAs`][].
+///
+///
+/// [`DeserializeAsWrap`] is a piece of glue code which turns [`DeserializeAs`] into a serde compatible datatype, by converting all calls to `deserialize` into `deserialize_as`.
+/// This allows us to implement [`DeserializeAs`] such that it can be applied recursively throughout the whole data structure.
+/// This is mostly important for container types, such as `Vec` or `BTreeMap`.
+/// In a `BTreeMap` this allows us to specify two different serialization behaviors, one for key and one for value, using the [`DeserializeAs`] trait.
+///
+/// ## Implementing a converter Type
+///
+/// This shows a simplified implementation for [`DisplayFromStr`].
+///
+/// ```rust
+/// # #[cfg(all(feature = "macros"))] {
+/// # use serde::Deserialize;
+/// # use serde::de::Error;
+/// # use serde_with::DeserializeAs;
+/// # use std::str::FromStr;
+/// # use std::fmt::Display;
+/// struct DisplayFromStr;
+///
+/// impl<'de, T> DeserializeAs<'de, T> for DisplayFromStr
+/// where
+/// T: FromStr,
+/// T::Err: Display,
+/// {
+/// fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+/// where
+/// D: serde::Deserializer<'de>,
+/// {
+/// let s = String::deserialize(deserializer).map_err(Error::custom)?;
+/// s.parse().map_err(Error::custom)
+/// }
+/// }
+/// #
+/// # #[serde_with::serde_as]
+/// # #[derive(serde::Deserialize)]
+/// # struct S (#[serde_as(as = "DisplayFromStr")] bool);
+/// #
+/// # assert_eq!(false, serde_json::from_str::<S>(r#""false""#).unwrap().0);
+/// # }
+/// ```
+/// [`Box`]: std::boxed::Box
+/// [`BTreeMap`]: std::collections::BTreeMap
+/// [`Duration`]: std::time::Duration
+/// [`FromStr`]: std::str::FromStr
+/// [`Vec`]: std::vec::Vec
+/// [impl-deserialize]: https://serde.rs/impl-deserialize.html
+pub trait DeserializeAs<'de, T>: Sized {
+ /// Deserialize this value from the given Serde deserializer.
+ fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
+ where
+ D: Deserializer<'de>;
+}
+
+/// Helper type to implement [`DeserializeAs`] for container-like types.
+#[derive(Debug)]
+pub struct DeserializeAsWrap<T, U> {
+ value: T,
+ marker: PhantomData<U>,
+}
+
+impl<T, U> DeserializeAsWrap<T, U> {
+ /// Return the inner value of type `T`.
+ pub fn into_inner(self) -> T {
+ self.value
+ }
+}
+
+impl<'de, T, U> Deserialize<'de> for DeserializeAsWrap<T, U>
+where
+ U: DeserializeAs<'de, T>,
+{
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ U::deserialize_as(deserializer).map(|value| Self {
+ value,
+ marker: PhantomData,
+ })
+ }
+}