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