// build adapter with custom serialization names / grouping of (flattened) optional entries macro_rules! adapter { ( $adapter:ident => Option<$base:ident> { $( $(#[$field_meta:meta])* $field:ident: $field_ty:ty, )* } ) => { #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct $adapter { $( $(#[$field_meta])* #[serde(default, skip_serializing_if = "Option::is_none")] $field: Option<$field_ty>, )* } impl $adapter { pub fn serialize(value: &Option<$base>, serializer: S) -> Result where S: serde::Serializer, { Self::from(value.clone()).serialize(serializer) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, { <$adapter as serde::Deserialize>::deserialize(deserializer).map(Option::<$base>::from) } } impl From> for $adapter { fn from(base: Option<$base>) -> Self { if let Some(base) = base { Self { $($field: Some(base.$field),)* } } else { Self { $($field: None,)* } } } } impl From<$adapter> for Option<$base> { fn from(adapter: $adapter) -> Self { Option::Some($base { $($field: adapter.$field?,)* }) } } }; ( $adapter:ident => $base:ident { $( $(#[$field_meta:meta])* $field:ident: $field_ty:ty, )* } ) => { #[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct $adapter { $( $(#[$field_meta])* $field: $field_ty, )* } impl $adapter { pub fn serialize(value: &$base, serializer: S) -> Result where S: serde::Serializer, { Self::from(value.clone()).serialize(serializer) } pub fn deserialize<'de, D>(deserializer: D) -> Result<$base, D::Error> where D: serde::Deserializer<'de>, { <$adapter as serde::Deserialize>::deserialize(deserializer).map($base::from) } } impl From<$base> for $adapter { fn from(base: $base) -> Self { Self { $($field: base.$field,)* } } } impl From<$adapter> for $base { fn from(adapter: $adapter) -> Self { Self { $($field: adapter.$field,)* } } } }; }