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