Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
31 changes: 19 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,27 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint & Format Check
runs-on: macOS-26
env:
DEVELOPER_DIR: "/Applications/Xcode_26.0.app/Contents/Developer"
steps:
- uses: actions/checkout@v4
- name: Swift Version
run: xcrun swift --version
- name: Install SwiftLint
run: brew install swiftlint --quiet
- name: Install swift-format
run: brew install swiftformat --quiet
- name: SwiftLint
run: swiftlint --strict --config .swiftlint.yml .
- name: Swift Format Check
run: swiftformat --lint-only --config .swiftformat.conf . --strict
test:
name: ${{ matrix.name }}
runs-on: ${{ matrix.runsOn }}
needs: lint
env:
DEVELOPER_DIR: "/Applications/${{ matrix.xcode }}.app/Contents/Developer"
strategy:
Expand All @@ -35,19 +53,8 @@ jobs:
- uses: actions/checkout@v4
- name: Swift Version
run: xcrun swift --version
- name: Install SwiftLint
run: brew install swiftlint --quiet
- name: Install swift-format
run: |
brew install swiftformat --quiet
- name: Install xcbeautify
run: |
brew install xcbeautify --quiet
- name: SwiftLint
run: swiftlint --strict --config .swiftlint.yml .
- name: Swift Format Check
run: |
swiftformat --lint-only --config .swiftformat.conf . --strict
run: brew install xcbeautify --quiet
- name: Run Tests
run: |
set -o pipefail && \
Expand Down
8 changes: 7 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ let package = Package(
.target(
name: "BinaryParseKitCommons",
dependencies: [.product(name: "BinaryParsing", package: "swift-binary-parsing")],
swiftSettings: [.enableExperimentalFeature("LifetimeDependence"), .strictMemorySafety()],
swiftSettings: [
.enableExperimentalFeature("LifetimeDependence"),
.enableExperimentalFeature("Lifetimes"),
.strictMemorySafety(),
],
),
.target(name: "BinaryParseKit", dependencies: ["BinaryParseKitMacros"], swiftSettings: [
.enableExperimentalFeature("LifetimeDependence"),
.enableExperimentalFeature("Lifetimes"),
.strictMemorySafety(),
]),
.executableTarget(
Expand All @@ -55,6 +60,7 @@ let package = Package(
],
swiftSettings: [
.enableExperimentalFeature("LifetimeDependence"),
.enableExperimentalFeature("Lifetimes"),
.strictMemorySafety(),
],
),
Expand Down
72 changes: 62 additions & 10 deletions Sources/BinaryParseKit/BinaryParseKit.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// The Swift Programming Language
// https://docs.swift.org/swift-book

import BinaryParseKitCommons
@_exported public import BinaryParseKitCommons
public import BinaryParsing

// MARK: - Skip Parsing
Expand Down Expand Up @@ -32,7 +32,7 @@ public import BinaryParsing
@attached(peer)
public macro skip(byteCount: ByteCount, because: String) = #externalMacro(
module: "BinaryParseKitMacros",
type: "SkipParsingMacro",
type: "EmptyPeerMacro",
)

// MARK: - Field Parsing
Expand All @@ -53,7 +53,7 @@ public macro skip(byteCount: ByteCount, because: String) = #externalMacro(
/// }
/// ```
@attached(peer)
public macro parse() = #externalMacro(module: "BinaryParseKitMacros", type: "ByteParsingMacro")
public macro parse() = #externalMacro(module: "BinaryParseKitMacros", type: "EmptyPeerMacro")

/// Parses a field with a specific endianness.
///
Expand All @@ -76,7 +76,7 @@ public macro parse() = #externalMacro(module: "BinaryParseKitMacros", type: "Byt
/// }
/// ```
@attached(peer)
public macro parse(endianness: Endianness) = #externalMacro(module: "BinaryParseKitMacros", type: "ByteParsingMacro")
public macro parse(endianness: Endianness) = #externalMacro(module: "BinaryParseKitMacros", type: "EmptyPeerMacro")

/// Parses a field with a specific byte count.
///
Expand All @@ -101,7 +101,7 @@ public macro parse(endianness: Endianness) = #externalMacro(module: "BinaryParse
@attached(peer)
public macro parse(byteCount: ByteCount) = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

/// Parses a field with a byte count determined by another field's value.
Expand All @@ -128,7 +128,7 @@ public macro parse(byteCount: ByteCount) = #externalMacro(
@attached(peer)
public macro parse<R, V: BinaryInteger>(byteCountOf: KeyPath<R, V>) = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

/// Parses a field with both specific byte count and endianness.
Expand All @@ -153,7 +153,7 @@ public macro parse<R, V: BinaryInteger>(byteCountOf: KeyPath<R, V>) = #externalM
@attached(peer)
public macro parse(byteCount: ByteCount, endianness: Endianness) = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

/// Parses a field with byte count from another field and specific endianness.
Expand Down Expand Up @@ -182,7 +182,7 @@ public macro parse(byteCount: ByteCount, endianness: Endianness) = #externalMacr
@attached(peer)
public macro parse<R, V: BinaryInteger>(byteCountOf: KeyPath<R, V>, endianness: Endianness) = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

/// Parses all remaining bytes in the data stream.
Expand All @@ -208,7 +208,7 @@ public macro parse<R, V: BinaryInteger>(byteCountOf: KeyPath<R, V>, endianness:
@attached(peer)
public macro parseRest() = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

/// Parses all remaining bytes with a specific endianness.
Expand All @@ -235,7 +235,7 @@ public macro parseRest() = #externalMacro(
@attached(peer)
public macro parseRest(endianness: Endianness) = #externalMacro(
module: "BinaryParseKitMacros",
type: "ByteParsingMacro",
type: "EmptyPeerMacro",
)

// MARK: - Struct Parsing
Expand Down Expand Up @@ -278,3 +278,55 @@ public macro ParseStruct() = #externalMacro(
module: "BinaryParseKitMacros",
type: "ConstructStructParseMacro",
)

// MARK: - Parse Enum

@attached(extension, conformances: BinaryParseKit.Parsable, names: arbitrary)
public macro ParseEnum() = #externalMacro(
module: "BinaryParseKitMacros",
type: "ConstructEnumParseMacro",
)

// MARK: - Enum Case Parsing

@attached(peer)
public macro match() = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro match(byte: UInt8) = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro match(bytes: [UInt8]) = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro matchAndTake() = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro matchAndTake(byte: UInt8) = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro matchAndTake(bytes: [UInt8]) = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)

@attached(peer)
public macro matchDefault() = #externalMacro(
module: "BinaryParseKitMacros",
type: "EmptyPeerMacro",
)
2 changes: 1 addition & 1 deletion Sources/BinaryParseKit/BinaryParserKitError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
// Created by Larry Zeng on 7/17/25.
//

enum BinaryParserKitError: Error {
public enum BinaryParserKitError: Error {
case failedToParse(String)
}
1 change: 0 additions & 1 deletion Sources/BinaryParseKit/BuiltInExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//
// Created by Larry Zeng on 7/16/25.
//
import BinaryParseKitCommons
import BinaryParsing

extension UInt8: @retroactive ExpressibleByParsing {}
Expand Down
9 changes: 8 additions & 1 deletion Sources/BinaryParseKit/CustomExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
//
// Created by Larry Zeng on 7/16/25.
//
import BinaryParseKitCommons
import BinaryParsing

// MARK: - Floating Point Conformances
Expand Down Expand Up @@ -89,6 +88,14 @@ extension Int: EndianParsable {
}
}

// MARK: - MatchableRawValue

public extension MatchableRawRepresentable where Self.RawValue == UInt8 {
func bytesToMatch() -> [UInt8] {
[rawValue]
}
}

// MARK: - RawRepresentable

//
Expand Down
39 changes: 39 additions & 0 deletions Sources/BinaryParseKit/EnumParseUtils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// EnumParseUtils.swift
// BinaryParseKit
//
// Created by Larry Zeng on 11/7/25.
//
import BinaryParsing

/// Matches the given bytes in the input parser span.
/// - Warning: This function is used to `@parseEnum` macro and should not be used directly.
@inlinable
public func __match(_ bytes: borrowing [UInt8], in input: inout BinaryParsing.ParserSpan) -> Bool {
if bytes.isEmpty { return true }

do {
try input._checkCount(minimum: bytes.count)
} catch {
return false
}

let toMatch = unsafe input.bytes.extracting(first: bytes.count).withUnsafeBytes(Array.init)
return toMatch == bytes
}

/// - Warning: This function is used to `@parse` macro and should not be used directly.
@inlinable
public func __assertParsable(_: (some Parsable).Type) {}

/// - Warning: This function is used to `@parse` macro and should not be used directly.
@inlinable
public func __assertSizedParsable(_: (some SizedParsable).Type) {}

/// - Warning: This function is used to `@parse` macro and should not be used directly.
@inlinable
public func __assertEndianParsable(_: (some EndianParsable).Type) {}

/// - Warning: This function is used to `@parse` macro and should not be used directly.
@inlinable
public func __assertEndianSizedParsable(_: (some EndianSizedParsable).Type) {}
10 changes: 7 additions & 3 deletions Sources/BinaryParseKit/ParsableProtocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public protocol EndianParsable {
/// - input: A mutable parser span containing the binary data to parse
/// - endianness: The byte order to use when parsing multi-byte values
/// - Throws: `ThrownParsingError` if parsing fails
@lifetime(&input)
@_lifetime(&input)
init(parsing input: inout ParserSpan, endianness: Endianness) throws(ThrownParsingError)
}

Expand Down Expand Up @@ -71,7 +71,7 @@ public protocol EndianSizedParsable {
/// - endianness: The byte order to use when parsing multi-byte values
/// - byteCount: The number of bytes to read from the input
/// - Throws: `ThrownParsingError` if parsing fails
@lifetime(&input)
@_lifetime(&input)
init(parsing input: inout ParserSpan, endianness: Endianness, byteCount: Int) throws(ThrownParsingError)
}

Expand Down Expand Up @@ -116,7 +116,7 @@ public protocol SizedParsable {
/// - input: A mutable parser span containing the binary data to parse
/// - byteCount: The number of bytes to read from the input
/// - Throws: `ThrownParsingError` if parsing fails
@lifetime(&input)
@_lifetime(&input)
init(parsing input: inout ParserSpan, byteCount: Int) throws(ThrownParsingError)
}

Expand All @@ -142,3 +142,7 @@ public extension SizedParsable {
self = result
}
}

public protocol MatchableRawRepresentable: RawRepresentable {
func bytesToMatch() -> [UInt8]
}
16 changes: 15 additions & 1 deletion Sources/BinaryParseKitClient/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import BinaryParseKit
import BinaryParsing

extension [UInt8]: SizedParsable {
@lifetime(&input)
@_lifetime(&input)
public init(parsing input: inout ParserSpan, byteCount: Int) throws(ThrownParsingError) {
var subSpan = try input.sliceSpan(byteCount: byteCount)
self.init(parsingRemainingBytes: &subSpan)
Expand Down Expand Up @@ -44,3 +44,17 @@ print("Version: \(header.version)") // 1
print("File Size: \(header.fileSize)") // 5
print("Content: \(String(bytes: header.content, encoding: .utf8)!)") // "Hello"
print("Footer: \(header.footer)")

@ParseEnum
enum Channel {
@match(byte: 0x00)
case internet
@match(byte: 0x01)
case satellite
@match(byte: 0x02)
case pigeon
}

let channel = try Channel(parsing: [0x02])

print("Channel: \(channel)") // pigeon
4 changes: 2 additions & 2 deletions Sources/BinaryParseKitMacros/BinaryParseKitMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import SwiftSyntaxMacros
@main
struct BinaryParseKitPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
ByteParsingMacro.self,
SkipParsingMacro.self,
EmptyPeerMacro.self,
ConstructStructParseMacro.self,
ConstructEnumParseMacro.self,
]
}
20 changes: 0 additions & 20 deletions Sources/BinaryParseKitMacros/Macros/ByteParsingMacro.swift

This file was deleted.

Loading