Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
dbd3bea
Layout bitmask parsing
FlickerSoul Nov 28, 2025
44285d5
WIP
FlickerSoul Dec 29, 2025
f5e7412
Integration tests
FlickerSoul Dec 29, 2025
ee4d91c
Clean up
FlickerSoul Dec 30, 2025
eb9f546
More efficient RawBits operation
FlickerSoul Dec 30, 2025
4027fb8
Add RawBitsConvertible
FlickerSoul Jan 4, 2026
f3cf5aa
Printing WIP
FlickerSoul Jan 4, 2026
8304cd5
Test bitmasks printing
FlickerSoul Jan 5, 2026
1062b85
More tests
FlickerSoul Jan 6, 2026
5d2c65d
Fix macro comment generation issue
FlickerSoul Jan 6, 2026
e3773bb
Refactor tests
FlickerSoul Jan 6, 2026
165e3e1
Refactor test suite
FlickerSoul Jan 6, 2026
18ec6e4
Remove redundant support
FlickerSoul Jan 6, 2026
dd52ec1
Fix typo
FlickerSoul Jan 6, 2026
93ddd9a
Fix parsing false positive errors
FlickerSoul Jan 6, 2026
0966295
Add bench mark
FlickerSoul Jan 6, 2026
32d6bd9
Improve parsing utility
FlickerSoul Jan 6, 2026
35406d0
Update XCode scheme
FlickerSoul Jan 6, 2026
16daea6
Remove redundant tests
FlickerSoul Jan 6, 2026
0a9159b
Remove RawBits in parsing
FlickerSoul Jan 6, 2026
e66e042
Fix false positive diagnostics
FlickerSoul Jan 6, 2026
268e402
Throw error when RawBitsInteger is smaller than required bit count
FlickerSoul Jan 6, 2026
c6b09ac
Edge case testing
FlickerSoul Jan 6, 2026
e4684eb
Use borrowing instead of inout in matching
FlickerSoul Jan 7, 2026
6b69d85
Refactor
FlickerSoul Jan 7, 2026
8c4e37a
Add more utility tests
FlickerSoul Jan 7, 2026
c01667d
Replace dynamic dispatch with static
FlickerSoul Jan 7, 2026
a98c220
Speed up parsing
FlickerSoul Jan 7, 2026
6c5fcea
Clean up bench mark and test benchmarks
FlickerSoul Jan 7, 2026
c9f211a
Fix tests
FlickerSoul Jan 7, 2026
d88bed7
Fix tests
FlickerSoul Jan 7, 2026
8cd11ec
Add benchmark CI
FlickerSoul Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Benchmark
on:
workflow_run:
workflows: ["CI"]
types:
- completed
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
jobs:
benchmark:
name: Run Benchmarks
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: macOS-26
env:
DEVELOPER_DIR: "/Applications/Xcode_26.0.app/Contents/Developer"
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Swift Version
run: xcrun swift --version
- name: Install jemalloc
run: |
echo "/opt/homebrew/bin:/usr/local/bin" >> $GITHUB_PATH
brew install jemalloc
- name: Run Parsing Benchmarks
run: |
xcrun swift package benchmark --format markdown >> $GITHUB_STEP_SUMMARY
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ jobs:
env:
DEVELOPER_DIR: "/Applications/Xcode_26.0.app/Contents/Developer"
steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@v6
- name: Swift Version
run: xcrun swift --version
- name: Install SwiftLint
Expand Down Expand Up @@ -59,7 +60,7 @@ jobs:
run: |
set -o pipefail && \
xcodebuild test \
-scheme BinaryParseKit-Package \
-scheme BinaryParseKit \
-destination 'platform=macOS' \
-skipMacroValidation | xcbeautify --renderer github-actions

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-docc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
DEVELOPER_DIR: "/Applications/Xcode_26.1.app/Contents/Developer"
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Swift Version
run: xcrun swift --version
- name: Build DocC
Expand Down
6 changes: 0 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@ repos:
language: system
types: [swift]
stages: [pre-commit]
- id: swiftlint fix
name: SwiftLintFix
entry: swiftlint . --fix --config .swiftlint.yml
language: system
types: [swift]
stages: [pre-commit]
- id: swiftlint check
name: SwiftLintCheck
entry: swiftlint . --strict --config .swiftlint.yml
Expand Down
4 changes: 3 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ identifier_name:
- j
- x
- y
allowed_symbols: ["_"]
allowed_symbols: ["_", " "]
cyclomatic_complexity:
warning: 20
error: 25
type_name:
allowed_symbols: [" "]
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,34 @@
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ParsingBenchmarks"
BuildableName = "ParsingBenchmarks"
BlueprintName = "ParsingBenchmarks"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PrintingBenchmarks"
BuildableName = "PrintingBenchmarks"
BlueprintName = "PrintingBenchmarks"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand All @@ -43,15 +71,18 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:TestPlans/All.xctestplan"
default = "YES">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/Product.xctestplan">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/Macro.xctestplan">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/All.xctestplan"
default = "YES">
reference = "container:TestPlans/BenchmarkTypes.xctestplan">
</TestPlanReference>
</TestPlans>
<Testables>
Expand All @@ -75,6 +106,26 @@
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BenchmarkCommonsTests"
BuildableName = "BenchmarkCommonsTests"
BlueprintName = "BenchmarkCommonsTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BenchmarkTypesTests"
BuildableName = "BenchmarkTypesTests"
BlueprintName = "BenchmarkTypesTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
Expand All @@ -87,6 +138,16 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "PrintingBenchmarks"
BuildableName = "PrintingBenchmarks"
BlueprintName = "PrintingBenchmarks"
ReferencedContainer = "container:">
</BuildableReference>
</BuildableProductRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
Expand All @@ -103,15 +164,16 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BinaryParseKitClient"
BuildableName = "BinaryParseKitClient"
BlueprintName = "BinaryParseKitClient"
BlueprintIdentifier = "PrintingBenchmarks"
BuildableName = "PrintingBenchmarks"
BlueprintName = "PrintingBenchmarks"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
Expand Down
18 changes: 16 additions & 2 deletions .swiftpm/xcode/xcshareddata/xcschemes/BinaryParseKit.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,22 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:TestPlans/All.xctestplan"
default = "YES">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/Product.xctestplan">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/Macro.xctestplan">
</TestPlanReference>
<TestPlanReference
reference = "container:TestPlans/BenchmarkTypes.xctestplan">
</TestPlanReference>
</TestPlans>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand Down
15 changes: 15 additions & 0 deletions Benchmarks/BenchmarkTypes/BaselineParsable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// BaselineParsable.swift
// BinaryParseKit
//
// Created by Larry Zeng on 1/6/26.
//

import Foundation

/// Protocol for types that provide a baseline parsing implementation for benchmarking.
public protocol BaselineParsable {
/// Parses the type from raw data without bounds checking.
/// Used as a baseline for performance comparison in benchmarks.
static func parseBaseline(_ data: Data) -> Self
}
52 changes: 52 additions & 0 deletions Benchmarks/BenchmarkTypes/BenchmarkBitmaskComplex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// BenchmarkBitmaskComplex.swift
// BinaryParseKit
//
// Created by Larry Zeng on 1/6/26.
//

import BinaryParseKit
import BinaryParsing
import Foundation

@ParseBitmask
public struct BenchmarkBitmaskComplex: Equatable, Sendable, BaselineParsable {
public typealias RawBitsInteger = UInt32

@mask(bitCount: 1)
public var flag1: UInt8

@mask(bitCount: 3)
public var priority: UInt8

@mask(bitCount: 4)
public var nibble: UInt8

@mask(bitCount: 8)
public var byte: UInt8

@mask(bitCount: 16)
public var word: UInt16

public init(flag1: UInt8, priority: UInt8, nibble: UInt8, byte: UInt8, word: UInt16) {
self.flag1 = flag1
self.priority = priority
self.nibble = nibble
self.byte = byte
self.word = word
}

/// Baseline parsing - direct 32-bit extraction without bound checking
@inline(__always)
public static func parseBaseline(_ data: Data) -> BenchmarkBitmaskComplex {
data.withUnsafeBytes { ptr in
let bits = UInt32(bigEndian: ptr.load(as: UInt32.self))
let flag1 = UInt8((bits >> 31) & 0x01)
let priority = UInt8((bits >> 28) & 0x07)
let nibble = UInt8((bits >> 24) & 0x0F)
let byte = UInt8((bits >> 16) & 0xFF)
let word = UInt16(bits & 0xFFFF)
return BenchmarkBitmaskComplex(flag1: flag1, priority: priority, nibble: nibble, byte: byte, word: word)
}
}
}
35 changes: 35 additions & 0 deletions Benchmarks/BenchmarkTypes/BenchmarkBitmaskSimple.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// BenchmarkBitmaskSimple.swift
// BinaryParseKit
//
// Created by Larry Zeng on 1/6/26.
//

import BinaryParseKit
import BinaryParsing
import Foundation

@ParseBitmask
public struct BenchmarkBitmaskSimple: Equatable, Sendable, BaselineParsable {
public typealias RawBitsInteger = UInt8

@mask(bitCount: 1)
public var flag: UInt8

@mask(bitCount: 7)
public var value: UInt8

public init(flag: UInt8, value: UInt8) {
self.flag = flag
self.value = value
}

/// Baseline parsing - direct bit extraction without bound checking
@inline(__always)
public static func parseBaseline(_ data: Data) -> BenchmarkBitmaskSimple {
let byte = data[data.startIndex]
let flag = (byte >> 7) & 0x01
let value = byte & 0x7F
return BenchmarkBitmaskSimple(flag: flag, value: value)
}
}
49 changes: 49 additions & 0 deletions Benchmarks/BenchmarkTypes/BenchmarkEnumComplex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// BenchmarkEnumComplex.swift
// BinaryParseKit
//
// Created by Larry Zeng on 1/6/26.
//

import BinaryParseKit
import BinaryParsing
import Foundation

@ParseEnum
public enum BenchmarkEnumComplex: Equatable, Sendable, BaselineParsable {
@matchAndTake(byte: 0x01)
@parse(endianness: .big)
case withInt16(Int16)

@matchAndTake(byte: 0x02)
@parse(endianness: .big)
case withUInt32(UInt32)

@matchAndTake(byte: 0x03)
@parse(endianness: .big)
@parse(endianness: .big)
case withTwoValues(Int16, UInt16)

@matchDefault
case unknown

/// Baseline parsing - direct parsing without bound checking
@inline(__always)
public static func parseBaseline(_ data: Data) -> BenchmarkEnumComplex {
let byte = data[data.startIndex]
switch byte {
case 0x01:
let value = Int16(bigEndian: data.withUnsafeBytes { $0.loadUnaligned(fromByteOffset: 1, as: Int16.self) })
return .withInt16(value)
case 0x02:
let value = UInt32(bigEndian: data.withUnsafeBytes { $0.loadUnaligned(fromByteOffset: 1, as: UInt32.self) })
return .withUInt32(value)
case 0x03:
let arg1 = Int16(bigEndian: data.withUnsafeBytes { $0.loadUnaligned(fromByteOffset: 1, as: Int16.self) })
let arg2 = UInt16(bigEndian: data.withUnsafeBytes { $0.loadUnaligned(fromByteOffset: 3, as: UInt16.self) })
return .withTwoValues(arg1, arg2)
default:
return .unknown
}
}
}
Loading
Loading