Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds Little Endian (LSB-first) parsing support to bitmask operations in BinaryParseKit. The default behavior remains Big Endian (MSB-first), but users can now opt into Little Endian parsing by specifying bitEndian: .little in the @ParseStruct, @ParseEnum, and @ParseBitmask macros.
Key changes:
- Introduces
RawBitsSpanstruct for efficient bit-level operations without copying - Updates
ExpressibleByRawBitsprotocol to useRawBitsSpaninstead of raw integer types - Adds
bitEndianparameter to parsing macros with validation for.bigor.littlevalues - Comprehensive test coverage for both big and little endian scenarios
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Sources/BinaryParseKit/Utils/RawBitsSpan.swift | New core type for representing bit spans with efficient slicing operations |
| Sources/BinaryParseKit/Protocols/BitmaskParsable.swift | Updated protocol to use RawBitsSpan instead of RawBitsInteger |
| Sources/BinaryParseKit/Utils/ParsingUtils.swift | Refactored utility functions to work with RawBitsSpan and support bitEndian parameter |
| Sources/BinaryParseKitMacros/Macros/Supports/MacroAccessorVisitor.swift | Added bitEndian configuration extraction and validation |
| Sources/BinaryParseKitMacros/Macros/Supports/Utilities.swift | Updated mask group generation to support big/little endian slicing |
| Tests/BinaryParseKitTests/Utils.swift | New utility for creating ParserSpan from integers |
| Tests/BinaryParseKitTests/Parsing/*.swift | Comprehensive test updates with little endian test cases |
| Benchmarks/* | Updated benchmarks to use new RawBitsSpan API |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
0abc760 to
1170023
Compare
1170023 to
6134727
Compare
df48034 to
0f46507
Compare
0f46507 to
0216cdb
Compare
3cf076f to
a880fce
Compare
a880fce to
d7d6fd0
Compare
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.
Goal
This PR adds LSB parsing support to bitmask.
The bitmask parsing is defaulted to MSB (BE). To opt in LSB (LE) parsing, one needs to specify in the
@ParseStrucut,@ParseEnum, and@ParseBitmaskmacro withbitEndian: .little.Design
This PR replaces the old RawBitsInteger-based approach with a new RawBitsSpan type and uses it to enable endianness-aware bit-level parsing.
RawBitsSpan
RawBitsSpan is a ~Escapable, ~Copyable span type that provides a zero-copy view into a contiguous byte buffer with bit-level granularity. It tracks a _bitOffset and _bitCount into an underlying Span.
Key operations:
load(as:bitCount:)— extracts bits as a right-aligned fixed-width integerextracting(first:)/extracting(last:)— non-mutating sub-span extractionslicing(first:)/slicing(last:)— mutating extraction that consumes bits from the spanThis replaces the previous design where all bits were pre-extracted into a FixedWidthInteger (RawBitsInteger associated type). The span-based approach removes the 64/128-bit size limit, avoids copying bits into an integer container, and decouples conforming types from a specific integer width.
Endianness flow
The bitEndian parameter flows through the system as follows:
- Big endian (default): span starts at bit offset 0, fields are sliced with
__slicing(unchecked: (), first:), consuming from MSB toward LSB- Little endian: span starts at bit offset totalBytes * 8 - totalBits, fields are sliced with
__slicing(unchecked: (), last:), consuming from LSB toward MSB__createFromBitsadjusts the span whenfieldRequestedBitCount > typeBitCount, extracting from first (big) or last (little) to select the significant bitsExpressibleByRawBits protocol change
The protocol no longer has an associated
RawBitsIntegertype. The initializer now takes borrowing RawBitsSpan:Conformances for
Bool,UInt8,Int8, and other integer types extract only the bits they need via RawBitsSpan.load().Other changes
__maskParsingandExtractBitsAsIntegerTests/MaskParsingTests(superseded byRawBitsSpanand new tests)MacroConfigurationVisitor,extractMacroConfiguration)