Repository navigation
Add byte_order="lsb" for little-endian bitfield structures - #121
Merged
Merged
Conversation
Every derived structure gets a rustdoc packing table and a Display implementation that shows its packed bytes and fields. The README and the crate docs now show both, with an example register and its output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Many formats number their bits inside little-endian words: C structures with bitfields, microcontroller registers, USB Power Delivery, LIFX. A field there that crosses a byte boundary next to smaller fields, like the 12-bit LIFX protocol number, is split around them in packed_struct's big-endian view of the bytes, so no field position could describe it (#29, #39, #92, #96). Little-endian words laid end to end form a single little-endian integer, so one struct attribute covers all of these formats. With byte_order="lsb", the derive packs the struct big-endian with the lsb0 positions and reverses all of its bytes. Integer fields use the opposite endianness internally and default to little-endian on the wire, nested types have their bytes reversed, and arrays are mirrored so their first element is at the lowest address. The rustdoc table and the Display output show the lsb0 positions. Structures without the attribute pack exactly as before. byte_order="lsb" requires bit_numbering="lsb0", and a big-endian field inside such a struct has to be byte-aligned. Both are compile errors, as is an invalid byte_order value. An oracle test checks integers of many widths, at many offsets, against a reference that writes them into a little-endian integer bit by bit. The LIFX example packs and unpacks the example packet from the LIFX docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Closes #29. Also addresses #39, #92 and #96.
Problem
packed_struct reads the packed bytes as one big-endian bit stream. Formats described as C bitfields on little-endian targets number their bits inside little-endian words instead. Examples are microcontroller registers, USB Power Delivery and LIFX. A field there that crosses a byte boundary next to smaller fields is split around them in the stream, so no
packed_fieldposition can describe it.LIFX's 12-bit
protocolfield is one example. Its low 8 bits are byte 2 and its high 4 bits are the low nibble of byte 3, with theaddressable/tagged/originflags in between.Change
Little-endian words laid end to end form a single little-endian integer, so one struct attribute covers all of these formats:
The derive packs the struct big-endian with the existing
lsb0code, then reverses all of its bytes:[u8; N]keeps its order on the wire.Displayoutput show thelsb0positions.Three cases are compile errors:
byte_order="lsb"withoutbit_numbering="lsb0", a big-endian field inside such a struct that isn't byte-aligned, and an invalidbyte_ordervalue.The README and crate docs replace the manual byte-swap recipe for little-endian registers with a "Little-endian bitfields" section. A separate commit documents the rustdoc packing table and the runtime
Displayoutput.Tests
packing_byte_order_lsb_oracle.rs: 300 generated cases. Integers of widths 1 to 64 at offsets 0–7 and 13, signed and unsigned, plus big-endian fields, are checked against a reference that writes each value into a little-endian integer bit by bit.packing_byte_order_lsb.rs: the struct from having a field with 12 bits #29 as written, arrays, nested structs at aligned and unaligned positions, an enum across a byte boundary, a USB PD power object as sent over the wire, and theDisplayoutput.packed_struct_examples/src/lifx.rs: the full LIFX message header and theSetColormessage. They pack and unpack the example packet from the LIFX docs byte for byte.cargo test --workspace, theno_stdtests,--no-default-featuresbuilds andcargo clippy --workspace --all-targetsall pass.🤖 Generated with Claude Code