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 /// # extern crate serde;
16 /// # extern crate serde_json;
17 /// # #[macro_use]
18 /// # extern crate serde_with;
19 /// #
20 /// # use serde::Deserialize;
21 /// #
22 /// // Setup the types
23 /// #[derive(Deserialize, Debug)]
24 /// struct S {
25 ///     #[serde(flatten, deserialize_with = "deserialize_t")]
26 ///     t: T,
27 /// }
28 ///
29 /// #[derive(Deserialize, Debug)]
30 /// struct T {
31 ///     i: i32,
32 /// }
33 ///
34 /// // The macro creates custom deserialization code.
35 /// // You need to specify a function name and the field name of the flattened field.
36 /// flattened_maybe!(deserialize_t, "t");
37 ///
38 ///
39 /// # fn main() {
40 /// // Supports both flattened
41 /// let j = r#" {"i":1} "#;
42 /// assert!(serde_json::from_str::<S>(j).is_ok());
43 ///
44 /// // and non-flattened versions.
45 /// let j = r#" {"t":{"i":1}} "#;
46 /// assert!(serde_json::from_str::<S>(j).is_ok());
47 ///
48 /// // Ensure that the value is given
49 /// let j = r#" {} "#;
50 /// assert!(serde_json::from_str::<S>(j).is_err());
51 ///
52 /// // and only occurs once, not multiple times.
53 /// let j = r#" {"i":1,"t":{"i":1}} "#;
54 /// assert!(serde_json::from_str::<S>(j).is_err());
55 /// # }
56 /// ```
57 #[macro_export]
58 macro_rules! flattened_maybe {
59     // TODO Change $field to literal, once the compiler version is bumped enough.
60     ($fn:ident, $field:expr) => {
61         fn $fn<'de, T, D>(deserializer: D) -> Result<T, D::Error>
62         where
63             T: serde::Deserialize<'de>,
64             D: serde::Deserializer<'de>,
65         {
66             #[derive(serde::Deserialize)]
67             struct Both<T> {
68                 #[serde(flatten)]
69                 flat: Option<T>,
70                 #[serde(rename = $field)]
71                 not_flat: Option<T>,
72             }
73 
74             let both: Both<T> = serde::Deserialize::deserialize(deserializer)?;
75             match (both.flat, both.not_flat) {
76                 (Some(t), None) | (None, Some(t)) => Ok(t),
77                 (None, None) => Err(serde::de::Error::missing_field($field)),
78                 (Some(_), Some(_)) => Err(serde::de::Error::custom(concat!(
79                     "`",
80                     $field,
81                     "` is both flattened and not"
82                 ))),
83             }
84         }
85     };
86 }
87