1 /// Support deserializing from flattened and non-flattened representation
2 ///
3 /// When working with different serialization formats, sometimes it is more idiomatic to flatten
4 /// fields, while other formats prefer nesting. Using `#[serde(flatten)]` only the flattened form
5 /// is supported.
6 ///
7 /// This helper creates a function, which support deserializing from either the flattened or the
8 /// nested form. It gives an error, when both forms are provided. The `flatten` attribute is
9 /// required on the field such that the helper works. The serialization format will always be
10 /// flattened.
11 ///
12 /// # Examples
13 ///
14 /// ```rust
15 /// # use serde::Deserialize;
16 /// #
17 /// // Setup the types
18 /// #[derive(Deserialize, Debug)]
19 /// struct S {
20 ///     #[serde(flatten, deserialize_with = "deserialize_t")]
21 ///     t: T,
22 /// }
23 ///
24 /// #[derive(Deserialize, Debug)]
25 /// struct T {
26 ///     i: i32,
27 /// }
28 ///
29 /// // The macro creates custom deserialization code.
30 /// // You need to specify a function name and the field name of the flattened field.
31 /// serde_with::flattened_maybe!(deserialize_t, "t");
32 ///
33 /// # fn main() {
34 /// // Supports both flattened
35 /// let j = r#" {"i":1} "#;
36 /// assert!(serde_json::from_str::<S>(j).is_ok());
37 ///
38 /// // and non-flattened versions.
39 /// let j = r#" {"t":{"i":1}} "#;
40 /// assert!(serde_json::from_str::<S>(j).is_ok());
41 ///
42 /// // Ensure that the value is given
43 /// let j = r#" {} "#;
44 /// assert!(serde_json::from_str::<S>(j).is_err());
45 ///
46 /// // and only occurs once, not multiple times.
47 /// let j = r#" {"i":1,"t":{"i":1}} "#;
48 /// assert!(serde_json::from_str::<S>(j).is_err());
49 /// # }
50 /// ```
51 #[macro_export]
52 macro_rules! flattened_maybe {
53     ($fn:ident, $field:literal) => {
54         fn $fn<'de, T, D>(deserializer: D) -> ::std::result::Result<T, D::Error>
55         where
56             T: $crate::serde::Deserialize<'de>,
57             D: $crate::serde::Deserializer<'de>,
58         {
59             use ::std::option::Option::{self, None, Some};
60             use ::std::result::Result::{self, Err, Ok};
61             use $crate::serde;
62 
63             #[derive($crate::serde::Deserialize)]
64             #[serde(crate = "serde")]
65             pub struct Both<T> {
66                 #[serde(flatten)]
67                 flat: Option<T>,
68                 #[serde(rename = $field)]
69                 not_flat: Option<T>,
70             }
71 
72             let both: Both<T> = $crate::serde::Deserialize::deserialize(deserializer)?;
73             match (both.flat, both.not_flat) {
74                 (Some(t), None) | (None, Some(t)) => Ok(t),
75                 (None, None) => Err($crate::serde::de::Error::missing_field($field)),
76                 (Some(_), Some(_)) => Err($crate::serde::de::Error::custom(concat!(
77                     "`",
78                     $field,
79                     "` is both flattened and not"
80                 ))),
81             }
82         }
83     };
84 }
85