Skip to content

Add LSB parsing support to bitmask#29

Merged
FlickerSoul merged 21 commits intomainfrom
feat/rawbits-span-endian
Jan 28, 2026
Merged

Add LSB parsing support to bitmask#29
FlickerSoul merged 21 commits intomainfrom
feat/rawbits-span-endian

Conversation

@FlickerSoul
Copy link
Owner

@FlickerSoul FlickerSoul commented Jan 9, 2026

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 @ParseBitmask macro with bitEndian: .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 integer
  • extracting(first:) / extracting(last:) — non-mutating sub-span extraction
  • slicing(first:) / slicing(last:) — mutating extraction that consumes bits from the span

This 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:

  1. Declaration — user specifies bitEndian: .little on the macro attribute
  2. Macro expansion — MacroConfigurationVisitor extracts the value and stores it in AccessorInfo
  3. Code generation — the macro generates RawBitsSpan initialization and field slicing calls:
    - 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
  4. Runtime — __createFromBits adjusts the span when fieldRequestedBitCount > typeBitCount, extracting from first (big) or last (little) to select the significant bits

ExpressibleByRawBits protocol change

The protocol no longer has an associated RawBitsInteger type. The initializer now takes borrowing RawBitsSpan:

public protocol ExpressibleByRawBits {
    init(bits: borrowing RawBitsSpan) throws
}

Conformances for Bool, UInt8, Int8, and other integer types extract only the bits they need via RawBitsSpan.load().

Other changes

  • CI updated to use Swiftly
  • Benchmarks disabled by default
  • Removed __maskParsing and ExtractBitsAsIntegerTests / MaskParsingTests (superseded by RawBitsSpan and new tests)
  • Refactored macro utility naming (MacroConfigurationVisitor, extractMacroConfiguration)
  • Added comprehensive test coverage for both endianness modes across bitmask, enum, and struct parsing

Copilot AI review requested due to automatic review settings January 9, 2026 20:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 RawBitsSpan struct for efficient bit-level operations without copying
  • Updates ExpressibleByRawBits protocol to use RawBitsSpan instead of raw integer types
  • Adds bitEndian parameter to parsing macros with validation for .big or .little values
  • 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.

@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch 5 times, most recently from 0abc760 to 1170023 Compare January 10, 2026 02:55
@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch from 1170023 to 6134727 Compare January 10, 2026 02:59
@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch 4 times, most recently from df48034 to 0f46507 Compare January 28, 2026 12:09
@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch from 0f46507 to 0216cdb Compare January 28, 2026 12:59
@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch from 3cf076f to a880fce Compare January 28, 2026 18:12
@FlickerSoul FlickerSoul force-pushed the feat/rawbits-span-endian branch from a880fce to d7d6fd0 Compare January 28, 2026 18:15
@FlickerSoul FlickerSoul enabled auto-merge (squash) January 28, 2026 19:31
@FlickerSoul FlickerSoul merged commit ff1e5a8 into main Jan 28, 2026
2 checks passed
@FlickerSoul FlickerSoul deleted the feat/rawbits-span-endian branch January 28, 2026 19:39
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

Successfully merging this pull request may close these issues.

2 participants