https://github.com/mhayes853/swift-stream-parsing
Byte-by-byte parsing in Swift.
https://github.com/mhayes853/swift-stream-parsing
json json-parser json5 macros parsing swift
Last synced: 2 months ago
JSON representation
Byte-by-byte parsing in Swift.
- Host: GitHub
- URL: https://github.com/mhayes853/swift-stream-parsing
- Owner: mhayes853
- License: mit
- Created: 2025-12-26T06:40:23.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-02-13T05:04:26.000Z (4 months ago)
- Last Synced: 2026-02-13T13:26:50.515Z (4 months ago)
- Topics: json, json-parser, json5, macros, parsing, swift
- Language: Swift
- Homepage:
- Size: 13.7 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Swift Stream Parsing
[](https://github.com/mhayes853/swift-stream-parsing/actions/workflows/ci.yml)
[](https://swiftpackageindex.com/mhayes853/swift-stream-parsing)
[](https://swiftpackageindex.com/mhayes853/swift-stream-parsing)
A Swift toolkit for type-safe incremental parsing.
## Overview
`JSONDecoder` and `Codable` are powerful tools when you need to decode structured JSON bytes, however both of those tools require the entire data payload to be present at decode time.
This is especially problematic for applications such as streaming structured data from LLMs. For example, the FoundationModels framework has its own set of interfaces for incrementally streaming structured data.
This library offers a dedicated interface for incremental parsing with built-in JSON support.
## Quick Start
First, you create a struct that uses the `@StreamParseable` macro, and then you can begin parsing!
```swift
import StreamParsing
@StreamParseable
struct Profile {
var id: Int
var name: String
var isActive: Bool
}
let json = """
{
"id": 4,
"name": "Blob",
"isActive": true
}
"""
let partials: [Profile.Partial] = try json.utf8
.partials(of: Profile.Partial.self, from: .json())
for partial in partials {
print(partial)
}
// Prints:
// Profile.Partial(id: nil, name: nil, isActive: nil)
// ...
// Profile.Partial(id: Optional(4), name: nil, isActive: nil)
// ...
// Profile.Partial(id: Optional(4), name: Optional("B"), isActive: nil)
// Profile.Partial(id: Optional(4), name: Optional("Bl"), isActive: nil)
// Profile.Partial(id: Optional(4), name: Optional("Blo"), isActive: nil)
// Profile.Partial(id: Optional(4), name: Optional("Blob"), isActive: nil)
// ...
// Profile.Partial(id: Optional(4), name: Optional("Blob"), isActive: Optional(true))
```
The `@StreamParseable` macro generates a `Partial` struct with all optional members.
```swift
extension Profile: StreamParsingCore.StreamParseable {
struct Partial: StreamParsingCore.StreamParseableValue,
StreamParsingCore.StreamParseable {
typealias Partial = Self
var id: Int.Partial?
var name: String.Partial?
var isActive: Bool.Partial?
init(
id: Int.Partial? = nil,
name: String.Partial? = nil,
isActive: Bool.Partial? = nil
) {
self.id = id
self.name = name
self.isActive = isActive
}
static func initialParseableValue() -> Self {
Self()
}
static func registerHandlers(
in handlers: inout some StreamParsingCore.StreamParserHandlers
) {
handlers.registerKeyedHandler(forKey: "id", \.id)
handlers.registerKeyedHandler(forKey: "name", \.name)
handlers.registerKeyedHandler(forKey: "isActive", \.isActive)
}
}
}
```
Additionally, all stored members on an `@StreamParseable` must also conform to the `StreamParseable` protocol. Naturally, the `@StreamParseable` macro handles the protocol conformance for you.
You can also parse partials from an AsyncSequence of bytes or byte chunks.
```swift
struct AsyncJSONBytesSequence: AsyncSequence {
typealias Element = UInt8
// ...
}
let partials = AsyncJSONBytesSequence(...)
.partials(of: Profile.Partial.self, from: .json())
for try await profilePartial in partials {
print(profilePartial)
}
```
## Parsers
The library comes with built-in JSON and YAML parsers. You can pass a custom configuration to either parser to customize key decoding behavior.
### JSON
```swift
let configuration = JSONStreamParserConfiguration(
syntaxOptions: [.comments, .trailingCommas],
keyDecodingStrategy: .convertFromSnakeCase
)
let partials: [Profile.Partial] = try json.utf8
.partials(of: Profile.Partial.self, from: .json(configuration: configuration))
```
### YAML
```swift
let yaml = """
id: 4
name: Blob
isActive: true
"""
let partials: [Profile.Partial] = try yaml.utf8
.partials(of: Profile.Partial.self, from: .yaml())
let configuration = YAMLStreamParserConfiguration(
keyDecodingStrategy: .convertFromSnakeCase
)
let snakeCaseYAML = """
id: 4
name: Blob
is_active: true
"""
let partials = try snakeCaseYAML.utf8.partials(
of: Profile.Partial.self,
from: .yaml(configuration: configuration)
)
```
## Traits
While the core library itself has 0 dependencies, you can enable the following package traits to integrate with additional dependencies:
- `StreamParsingSwiftCollections` interops the library with types from Swift Collections.
- `StreamParsingFoundation` interops the library with types from Foundation (enabled by default).
- `StreamParsingTagged` interops the library with `Tagged`.
- `StreamParsingCoreGraphics` interops the library with CoreGraphics types (enabled by default).
## Documentation
The documentation for releases and main are available here.
* [StreamParsing (main)](https://swiftpackageindex.com/mhayes853/swift-stream-parsing/main/documentation/streamparsing/)
* [StreamParsing (0.x.x)](https://swiftpackageindex.com/mhayes853/swift-stream-parsing/~/documentation/streamparsing/)
* [StreamParsingCore (main)](https://swiftpackageindex.com/mhayes853/swift-stream-parsing/main/documentation/streamparsingcore/)
* [StreamParsingCore (0.x.x)](https://swiftpackageindex.com/mhayes853/swift-stream-parsing/~/documentation/streamparsingcore/)
## Installation
You can add Swift Stream Parsing to an Xcode project by adding it to your project as a package.
> [https://github.com/mhayes853/swift-stream-parsing](https://github.com/mhayes853/swift-stream-parsing)
> [!NOTE]
> Xcode 26.4 is required for using traits directly in Xcode projects.
If you want to use Swift Stream Parsing in a [SwiftPM](https://swift.org/package-manager/) project, it’s as simple as adding it to your `Package.swift`:
```swift
dependencies: [
.package(
url: "https://github.com/mhayes853/swift-stream-parsing",
from: "0.5.0",
// You can omit the traits if you don't need any of them.
traits: ["StreamParsingSwiftCollections"]
),
]
```
## License
This library is licensed under the MIT License. See [LICENSE](LICENSE) for details.