thelearnerofcode
thelearnerofcode

Reputation: 346

What does the error `cannot be named the same as a tuple variant` mean?

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

Upvotes: 4

Views: 1911

Answers (1)

kennytm
kennytm

Reputation: 523274

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>
    }
}

Upvotes: 7

Related Questions