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

Bitfield Integration in Structs #1497

Open
shilonic opened this issue Jul 7, 2024 · 5 comments
Open

Bitfield Integration in Structs #1497

shilonic opened this issue Jul 7, 2024 · 5 comments
Labels
customer-request Documents customer requests.

Comments

@shilonic
Copy link

shilonic commented Jul 7, 2024

Edits by maintainers:

bitflags/bitflags#326 (comment) suggests that there's no way to support zerocopy, but I think we can work around that.

cc @KodrAus @qwandor

IIUC, the problem is that:

  • bitflags will need to have a zerocopy_0_N feature for each zerocopy 0.N version
  • The emitted code will need to contain #[cfg_attr(feature = "zerocopy_0_N", derive(...)]
  • These attributes will be emitted into the caller's crate, where feature = "zerocopy_0_N" isn't set, and so it won't have the intended behavior

However, I think we can work around this by instead modifying bitflags so that certain internals of its macros are gated by #[cfg(feature = "zerocopy_0_N")]. That way, the code emitted into the caller's crate will simply have #[derive(...)] attributes which are already correctly chosen.

The naive solution requires the caller to also depend on zerocopy so that derive-emitted code can refer to zerocopy. A more ergonomic solution depends on supporting a #[zerocopy(crate = ...)] attribute (#11) so that only bitflags needs to take a zerocopy dependency (which it then re-exports).


Original text by @shilonic:

I'm currently working on a project that requires integrating bitfields into structs while maintaining zero-copy functionality. I believe adding native support for bitfield fields would enhance the usability and flexibility of the zero-copy crate.
I have tried integrating the bitfield crate and modular-bitfield, but using these options requires two levels of validation:

  • One to ensure the struct is correctly constructed from a zerocopy perspective.
  • Another for validating the bitfields.

Questions:
What is the best way to integrate bitfields into structs using this crate?
Are there existing patterns or recommendations for handling bitfields efficiently in a zero-copy context?

@shilonic shilonic added the customer-request Documents customer requests. label Jul 7, 2024
@joshlf
Copy link
Member

joshlf commented Aug 1, 2024

We don't have any special support for bitfields, nor any plans to add that support.

However, as part of the TryFromBytes trait (#5), we plan to eventually support "custom validators". When calling a conversion method like try_ref_from_bytes, zerocopy first validates that the bytes are a valid instance of the Rust type (ie, that constructing the type does not constitute undefined behavior). If this validation passes, then the user's custom validator is called, and it is given the opportunity to accept or reject the instance. If the custom validator returns an error, try_ref_from_bytes also returns an error.

Would that give you the support you need?

@ianthetechie
Copy link

I have a similar request. I think the approach would work at least in theory for everything I've run into. If zercopy could explicitly support bitfields, that'd be nice, but understood that this isn't your focus.

I am in fact already using bitfields extensively and it works well for the most part, but have a few edge cases. I'm using the bitfield_struct crate, and deriving TryFromBytes fails when used on an enum with a numeric representation.

Example enum:

#[derive(TryFromBytes, Debug)]
#[repr(u8)]
pub enum IntBackedEnum {
    FirstVariant = 0,
    SecondVariant = 0,
    // Some other variants, with gaps across the u8 space...
}

Trivial bitfield struct:

#[derive(TryFromBytes)]
#[bitfield(u8)]
struct MyBitfield {
    // We're bit packing and only care about 6 bits!
    #[bits(6)]
    enum_value: IntBackedEnum
    #[bits(2)]
    other_field: u8, // You get the idea...
}

Could be that I'm holding it wrong, but I get the following errors in this situation:

no variant or associated item named `from_bits` found for enum `IntBackedEnum` in the current scope
no variant or associated item named `into_bits` found for enum `IntBackedEnum` in the current scope
attempted to take value of method `other_field` on type `MyBitfield`

@joshlf
Copy link
Member

joshlf commented Oct 11, 2024

@ianthetechie I believe you've run into #388. Try putting #[bitfield(u8)] above #[derive(TryFromBytes)] and see if it works?

@ianthetechie
Copy link

Thanks for the quick feedback @joshlf! I attempted that as well, but still end up with (extremely similar; only varying in count?) errors 😅 I'll continue the discussion and post an MRE over in #388.

@qwandor
Copy link

qwandor commented Oct 15, 2024

bitflags now supports custom derives via bitflags/bitflags#348 which provides a reasonable workaround to this with just a bit of extra boilerplate, so I don't need anything else for zerocopy for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customer-request Documents customer requests.
Projects
None yet
Development

No branches or pull requests

4 participants