Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make #[derive(IntoBytes)] accept more types #2064

Open
joshlf opened this issue Nov 15, 2024 · 2 comments
Open

Make #[derive(IntoBytes)] accept more types #2064

joshlf opened this issue Nov 15, 2024 · 2 comments

Comments

@joshlf
Copy link
Member

joshlf commented Nov 15, 2024

No description provided.

@HonbraDev
Copy link

Would #1112 also apply to dynamically-sized enums? I think I have a usecase for borrowing an enum with non-uniform field sizes as a byte slice but am not 100% sure I have the correct mindset, though I can already do this the other way around and interpret an appropriately-sized byte slice as a packet enum.

// `Packet` has inter-field padding
// the trait `PaddingFree<Packet, true>` is not implemented for `()`
// consider using `zerocopy::Unalign` to lower the alignment of individual fields
// consider adding explicit fields where padding would be
// consider using `#[repr(packed)]` to remove inter-field padding
// the trait `PaddingFree<Packet, false>` is implemented for `()`
// see issue #48214
#[derive(IntoBytes, KnownLayout)]
#[repr(u8)]
enum Packet {
    DoSomething = 0x10,
    DoSomethingWithValue([u8; 4]) = 0x20,
}

fn expected_behavior() {
    assert_eq!(Packet::DoSomething.as_bytes(), &[0x10]);
    assert_eq!(
        Packet::DoSomethingWithValue([0x12, 0x34, 0x56, 0x78]).as_bytes(),
        &[0x20, 0x12, 0x34, 0x56, 0x78],
    );
}

@jswrenn
Copy link
Collaborator

jswrenn commented Nov 18, 2024

Unfortunately, no. "DST" in #1112 refers to types whose length is only known at runtime, and to which pointers carry extra length metadata. It wouldn't apply to your example, because Packet's size is known at runtime, and IntoBytes is a property of the entire type.

As the error message suggests, you can probably get your code to compile by adding an explicit padding field to Packet::DoSomething:

#[derive(IntoBytes, KnownLayout)]
#[repr(u8)]
enum Packet {
    DoSomething { _padding: [u8; 4] } = 0x10,
    DoSomethingWithValue([u8; 4]) = 0x20,
}

...but calling .as_bytes will still return all five bytes for Packet::DoSomething.

To work around this, you'll want to define your own "as bytes" mechanism that builds atop zerocopy's. Something like:

impl Packet {
    fn as_data_bytes(&self) -> &[u8] {
        let len = match self {
            Self::DoSomething { .. } => 1,
            Self::DoSomethingWithValue { .. } => 5,
        };
        &self.as_bytes()[..len]
    }
}

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

No branches or pull requests

3 participants