So I am making a ECS based on simplecs.
I have a macro that generates a entity struct that looks like this:
($($name:ident : $component:ty,)*) => {
/// A collection of pointers to components
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub struct Entity {
$(
pub $name: Option<($component)>,
)*
children: Vec<Entity>
}
}
It is my goal to use serde to serialize the entity, but that left a bunch of ugly None values where the component should be. So I tried to implement a custom serializer that looks like this:
impl Serialize for Entity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut num_fields = 0;
$(
match self.$name {
Some => num_fields += 1,
None => {}
};
)*
let mut state = serializer.serialize_struct("Entity", num_fields)?;
// do serialize
state.end()
}
}
The serializer tries to access a field via a name supplied as a macro argument ($name), but when I go to compile this, I get this error
error[E0530]: match bindings cannot shadow tuple variants
|
| Some => {}
| ^^^^ cannot be named the same as a tuple variant
The syntax self.$name is correct to access the member variable. As @oli_obk-ker said in the question's comment, the error is due to using Some instead of Some(pattern).
match self.$name {
Some(_) => num_fields += 1,
// ^~~
None => {}
};
//
// even better, use `if self.$name.is_some() { num_fields += 1; }`.
However, you don't even need to write your own serialize. You could use the #[serde(skip_serializing_if = "f") attribute on a field, which causes the generated code avoid writing it out if f(&self.field) returns true.
($($name:ident : $component:ty,)*) => {
/// A collection of pointers to components
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Entity {
$(
#[serde(skip_serializing_if = "Option::is_none")] // <-- add this
pub $name: Option<($component)>,
)*
children: Vec<Entity>
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With