Repository navigation
let DekuBitField fields join a bit-field run with bit_field - #694
Open
Simon-Calbert-Aerospacelab wants to merge 2 commits into
Open
Simon-Calbert-Aerospacelab wants to merge 2 commits into
Simon-Calbert-Aerospacelab wants to merge 2 commits into
Conversation
wcampbell0x2a
previously approved these changes
Nov 1, 2026
Simon-Calbert-Aerospacelab
dismissed
wcampbell0x2a’s stale review
via
November 2, 2026 07:31
f9eb9b8
Simon-Calbert-Aerospacelab
force-pushed
the
perf/batch-enum-bit-fields
branch
from
November 2, 2026 07:31
6357860 to
f9eb9b8
Compare
Contributor
Author
|
@wcampbell0x2a Thanks for the approval, I just did a rebased to fix the small conflicts. |
wc0x2b
approved these changes
Nov 2, 2026
wcampbell0x2a
approved these changes
Nov 2, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
#677 made deku read a group of neighbouring bit fields with a single call instead of one call per field. That only works for plain integers and
bool.Real headers are mostly flags, and a protocol crate usually models a flag as an enum rather than a
u8. When the derive meets a field typedOcfFlag, it only sees a type name and can't know how many bits it takes, so the group stops there. In a CCSDS TM primary header (11 fields, 5 of them enums), that means 8 calls instead of 1.The fix
Two small pieces let an enum tell the derive its width:
A new trait,
DekuBitField, that gives a type's width in bits and converts it from and to raw bits. You can derive it:A field attribute,
#[deku(bit_field)], that lets such a field join the group:With this, the whole 48-bit header becomes one read and one write.
Why an attribute on the field
The derive can't check whether a type implements a trait, so the field has to say so. If a marked type doesn't implement
DekuBitField, you get an ordinary "trait bound not satisfied" error pointing at that field.What happens when the width isn't known in advance
The derive groups fields before it knows the enum widths. So the generated code makes the final choice at compile time:
u8fields) also keeps one call per field, because that is faster for plain bytes.Safety
A batched read accepts and rejects exactly the same ids as a normal read. The "no matching variant" error comes from the same code in both cases. The one difference is on input too short for the whole group: the batched read reports
Incompletebefore checking any id, where the normal read may report the bad id first.A batched write rejects the same values a normal write does: for a derived enum, an
idtoo wide forbitsis a compile error, and a hand-writtento_bit_runreturns the error itself. In debug builds, ato_bit_runthat returns bits above its width is caught by an assertion.Results
bebits, 128 headers per iteration, same struct with and without the attribute:The write gain is the larger one because, without batching, each field is spliced into the output bit by bit. With batching, the fields are combined into one integer and written once.
Structs that don't use
bit_fieldare not affected: their generated code is identical tomaster.Reproduce with
cargo bench --bench bebits --all-features.Tests
-D warnings, all examples, and theno_stdbuilds pass locally.What
DekuBitFieldcan be used onWith
#[derive(DekuBitField)]: simple enums only. The derive accepts an enum whose value is just its id on the wire:id(id = 1orid = "0x01") that fits inbits;id_typeisu8,u16,u32oru64, andbits, if set, is an integer literal from 1 up to that width;Msb0(the default), and an id wider than 8 bits must be big-endian or take its endian from context.Anything that needs more than the id is refused with a compile error naming the rule:
id_pat,default, a variantreaderorwriter,magic,bytes,seek_*, or anidtaken from context.By hand: any type. A struct, a newtype, or a more complex enum can implement the trait itself:
The type must also keep its normal
DekuRead/DekuWritewith anEndiancontext. When a group can't be batched, the generated code falls back to that normal read or write for each field.Where it applies. A
bit_fieldis only batched when the struct holding it is explicitly big-endian and usesMsb0. In any other struct, the field is read and written on its own, as before.