Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

macros

rust

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
like image 215
thelearnerofcode Avatar asked Oct 27 '25 05:10

thelearnerofcode


1 Answers

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>
    }
}
like image 51
kennytm Avatar answered Oct 28 '25 21:10

kennytm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!