summaryrefslogtreecommitdiffstats
path: root/third_party/rust/serde_with/src/serde_conv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/serde_with/src/serde_conv.rs')
-rw-r--r--third_party/rust/serde_with/src/serde_conv.rs147
1 files changed, 147 insertions, 0 deletions
diff --git a/third_party/rust/serde_with/src/serde_conv.rs b/third_party/rust/serde_with/src/serde_conv.rs
new file mode 100644
index 0000000000..c5659ebfda
--- /dev/null
+++ b/third_party/rust/serde_with/src/serde_conv.rs
@@ -0,0 +1,147 @@
+/// Create new conversion adapters from functions
+///
+/// The macro lets you create a new converter, which is usable for serde's with-attribute and `#[serde_as]`.
+/// Its main use case is to write simple converters for types, which are not serializable.
+/// Another use-case is to change the serialization behavior if the implemented `Serialize`/`Deserialize` trait is insufficient.
+///
+/// The macro takes four arguments:
+///
+/// 1. The name of the converter type.
+/// The type can be prefixed with a visibility modifies like `pub` or `pub(crate)`.
+/// By default, the type is not marked as public (`pub(self)`).
+/// 2. The type `T` we want to extend with custom behavior.
+/// 3. A function or macro taking a `&T` and returning a serializable type.
+/// 4. A function or macro taking a deserializable type and returning a `Result<T, E>`.
+/// The error type `E` must implement `Display`.
+///
+/// # Example
+///
+/// In this example, we write custom serialization behavior for a `Rgb` type.
+/// We want to serialize it as a `[u8; 3]`.
+///
+/// ```rust
+/// # #[cfg(feature = "macros")] {
+/// # use serde::{Serialize, Deserialize};
+///
+/// #[derive(Clone, Copy, Debug, PartialEq)]
+/// struct Rgb {
+/// red: u8,
+/// green: u8,
+/// blue: u8,
+/// }
+///
+/// serde_with::serde_conv!(
+/// RgbAsArray,
+/// Rgb,
+/// |rgb: &Rgb| [rgb.red, rgb.green, rgb.blue],
+/// |value: [u8; 3]| -> Result<_, std::convert::Infallible> {
+/// Ok(Rgb {
+/// red: value[0],
+/// green: value[1],
+/// blue: value[2],
+/// })
+/// }
+/// );
+///
+/// //////////////////////////////////////////////////
+///
+/// // We define some colors to be used later
+///
+/// let green = Rgb {red: 0, green: 255, blue: 0};
+/// let orange = Rgb {red: 255, green: 128, blue: 0};
+/// let pink = Rgb {red: 255, green: 0, blue: 255};
+///
+/// //////////////////////////////////////////////////
+///
+/// // We can now use the `RgbAsArray` adapter with `serde_as`.
+///
+/// #[serde_with::serde_as]
+/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
+/// struct Colors {
+/// #[serde_as(as = "RgbAsArray")]
+/// one_rgb: Rgb,
+/// #[serde_as(as = "Vec<RgbAsArray>")]
+/// rgbs_in_vec: Vec<Rgb>,
+/// }
+///
+/// let data = Colors {
+/// one_rgb: orange,
+/// rgbs_in_vec: vec![green, pink],
+/// };
+/// let json = serde_json::json!({
+/// "one_rgb": [255, 128, 0],
+/// "rgbs_in_vec": [
+/// [0, 255, 0],
+/// [255, 0, 255]
+/// ]
+/// });
+///
+/// assert_eq!(json, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(json).unwrap());
+///
+/// //////////////////////////////////////////////////
+///
+/// // The types generated by `serde_conv` is also compatible with serde's with attribute
+///
+/// #[derive(Debug, PartialEq, Serialize, Deserialize)]
+/// struct ColorsWith {
+/// #[serde(with = "RgbAsArray")]
+/// rgb_with: Rgb,
+/// }
+///
+/// let data = ColorsWith {
+/// rgb_with: pink,
+/// };
+/// let json = serde_json::json!({
+/// "rgb_with": [255, 0, 255]
+/// });
+///
+/// assert_eq!(json, serde_json::to_value(&data).unwrap());
+/// assert_eq!(data, serde_json::from_value(json).unwrap());
+/// # }
+/// ```
+#[macro_export]
+macro_rules! serde_conv {
+ ($m:ident, $t:ty, $ser:expr, $de:expr) => {$crate::serde_conv!(pub(self) $m, $t, $ser, $de);};
+ ($vis:vis $m:ident, $t:ty, $ser:expr, $de:expr) => {
+ #[allow(non_camel_case_types)]
+ $vis struct $m;
+
+ #[allow(clippy::ptr_arg)]
+ impl $m {
+ $vis fn serialize<S>(x: &$t, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
+ where
+ S: $crate::serde::Serializer,
+ {
+ let y = $ser(x);
+ $crate::serde::Serialize::serialize(&y, serializer)
+ }
+
+ $vis fn deserialize<'de, D>(deserializer: D) -> ::std::result::Result<$t, D::Error>
+ where
+ D: $crate::serde::Deserializer<'de>,
+ {
+ let y = $crate::serde::Deserialize::deserialize(deserializer)?;
+ $de(y).map_err($crate::serde::de::Error::custom)
+ }
+ }
+
+ impl $crate::SerializeAs<$t> for $m {
+ fn serialize_as<S>(x: &$t, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
+ where
+ S: $crate::serde::Serializer,
+ {
+ Self::serialize(x, serializer)
+ }
+ }
+
+ impl<'de> $crate::DeserializeAs<'de, $t> for $m {
+ fn deserialize_as<D>(deserializer: D) -> ::std::result::Result<$t, D::Error>
+ where
+ D: $crate::serde::Deserializer<'de>,
+ {
+ Self::deserialize(deserializer)
+ }
+ }
+ };
+}