I'm trying to write a macro that generalizes serde_yaml deserialization for any struct so I don't have to rewrite the same thing over and over again. The only thing that is messign me up right now is the repetition inside a pattern.
Macro:
macro_rules! impl_struct_deserialization {
(
$struct_type: path {
$(
$field_name:ident : $field_type:path
),*
}
) => {
paste! {
impl<'de> Deserialize<'de> for $struct_type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
$(
[<$field_name:camel>]
),*
}
struct [<$struct_type Visitor>];
impl<'de> Visitor<'de> for [<$struct_type Visitor>] {
type Value = $struct_type;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(&("struct "
.to_owned()
.push_str(&stringify!($struct_type))
)
);
}
fn visit_map<V>(self, mut map: V) -> Result<$struct_type, V::Error>
where V: MapAccess<'de> {
$(let mut $field_name: Option<$field_type> = None;)*
while let Some(key) = map.next_key()? {
match key {
$(Field::[<$field_type:camel>] => {
if $field_name.is_some() {
return Err(serde::de::Error::duplicate_field(stringify!($field_name)));
}
$field_name = Some(map.next_value()?);
})*
}
}
$(
let $field_name = $field_name.ok_or_else(|| serde::de::Error::missing_field(stringify!($field_name)))?;
)*
Ok($struct_type::new($($field_name)*))
}
}
}
}
}
};
}
One of the calls:
impl_struct_deserialization!(
GBox {
center: Vec3f,
material: Material,
radius: f32
}
);
Error (repeats for every field apart from 1st):
Thank you!
UPD: used this as a reference
That specific error is due to a missing comma in a line near the bottom:
Ok($struct_type::new($($field_name),*))
// ^