Skip to content

Conversation

@miDeb
Copy link
Member

@miDeb miDeb commented Nov 21, 2025

The intention behind this macro is to facilitate generating zerocopy-able enums, by generating a padded variant of the enum while having to write the minimum amount of code manually.

Example:

padded_enum! {
    (size = 5) // Tag(1) + MaxPayload(4)

    #[derive(Debug, Clone, Copy, PartialEq)]
    #[repr(u8)]
    pub enum MyProto {
        // 1 + 4 + 0 = 5
        #[pad(0)]
        Move{dist: u32},
        
        // 1 + 1 + 3 = 5
        #[pad(3)]
        Jump{height: u8},

        // 1 + 0 + 4 = 5
        #[pad(4)]
        Stop
    }
}

This creates a new enum MyProtoPadded, which adds an [u8; N] array to each variant corresponding to the value provided in #pad[N]. Sadly, automatically determining the appropriate padding to add is not possible in a macro. The (size = ...) annotation at the beginning adds an assertion enforcing that the generated enum has the expected size, making it more obvious if something doesn't add up.

My hope is that this makes the transformation of messages from rust enums to bytes and vice versa a bit easier, because the standard IntoBytes/TryFromBytes is implemented for the Padded version of the enum.

The intention behind this macro is to facilitate generating zerocopy-able enums,
by generating a padded variant of the enum while having to write the minimum amount of code manually.
Copy link
Member

@raffael0 raffael0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like this macro, however I'm missing the larger context.
Would you use this for the Message enum?
Or instead for the genericCommand enum?

Another question I have is how this would then be serialized, because right now the only tag we are sending over the wire is the command_id:

pub struct CanMessageData {
    pub data_info: CanMessageDataInfo,
    pub command_id: u8,
    pub data: [u8; 62],
}

Would the tag then be the command id, and the data the rest?

Thanks!

@miDeb
Copy link
Member Author

miDeb commented Nov 23, 2025

Yeah, so ideally I wanted to use it on both enums, but on the Message enum it is more tricky because you would have to extract the channel id from the bitfield and then write it to its own byte. After that you could deserialize the Message directly from the bytes, I think.

I now added it for the GenericChannel only, I think it does reduce the amount of code there by a bit, so I'd say it's worth it.

@miDeb miDeb marked this pull request as ready for review November 23, 2025 01:23
Copy link
Member

@raffael0 raffael0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice work. Looks great!

Feel free to merge when ready

Comment on lines +140 to +144
// ---------------------------------------------------------
// Unit Tests
// ---------------------------------------------------------
#[cfg(test)]
mod tests {
Copy link
Member

@raffael0 raffael0 Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since your macro supports explicitly setting the tags. Can you add a test for that?

@raffael0
Copy link
Member

I added a github automation for automatic compilation/testing. Please rebase before merging

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants