rust-galmon-web/src/api/adapter_macro.rs

107 lines
2.2 KiB
Rust

// 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<S>(value: &Option<$base>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Self::from(value.clone()).serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<$base>, D::Error>
where
D: serde::Deserializer<'de>,
{
<$adapter as serde::Deserialize>::deserialize(deserializer).map(Option::<$base>::from)
}
}
impl From<Option<$base>> 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<S>(value: &$base, serializer: S) -> Result<S::Ok, S::Error>
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,)*
}
}
}
};
}