swift-primitives/swift-builder-primitives
A shared, macro-free result-builder grammar for declarative element collection — Builder<Component>, one generic @resultBuilder that any growable family composes to get its X { 1; 2; if c { … } } DSL without re-authoring the grammar.
Quick Start
The cleanest path is the Buildable protocol. Conform a growable family by supplying empty construction (Initiable's init()) and one neutral grow operation, add(_:). In exchange the family receives the declarative init(@Builder<Element> …) for free — the accumulator type never appears in the family's own code:
import Builder_Primitives
extension Set.Ordered: Buildable {
// init() is the set's empty construction (Initiable)
public mutating func add(_ element: consuming Element) {
_ = self.insert(element) // per-family grow: dedup on insert
}
}
let s = Set<Int>.Ordered {
1
2
2 // the dedup happens in `add`, not in the grammar
if useThree { 3 }
}Per-family behaviour (a set's deduplication, a dictionary's key-merge, a sorted container's ordered placement) lives in add(_:), exactly where it would at any other call site. The grammar is identical across every family — it only collects elements, in order.
A family that does not conform to Buildable can reference Builder directly as the build attribute on an initializer and drain the collected buffer itself:
import Builder_Primitives
struct Bag {
var storage: Buffer<Storage<Int>.Contiguous<Memory.Heap<Int>>>.Linear
init(@Builder<Int> _ content: () -> Buffer<Storage<Int>.Contiguous<Memory.Heap<Int>>>.Linear) {
self.storage = content()
}
}
let bag = Bag {
1
2
if useThree { 3 }
if useThree { 4 } else { 99 }
if #available(macOS 10.15, *) { 5 }
}The full build* grammar — sequencing, if, if/else, if #available — is inherited; the family writes none of it.
Move-only (~Copyable) elements compose declaratively too — the grammar consumes and moves rather than copies:
struct FileHandle: ~Copyable { /* … */ }
struct Handles: ~Copyable {
var storage: Buffer<Storage<FileHandle>.Contiguous<Memory.Heap<FileHandle>>>.Linear
init(@Builder<FileHandle> _ content: () -> Buffer<Storage<FileHandle>.Contiguous<Memory.Heap<FileHandle>>>.Linear) {
self.storage = content()
}
}For Copyable elements, an array literal or any Swift.Sequence collects in one statement:
let ints = Bag {
1
[3, 5] // array literal
6...8 // range
}Installation
dependencies: [
.package(url: "https://github.com/swift-primitives/swift-builder-primitives.git", branch: "main")
].target(
name: "App",
dependencies: [
.product(name: "Builder Primitives", package: "swift-builder-primitives"),
]
)Requires Swift 6.3.1 and macOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26 (or the matching Linux / Windows toolchain).
Architecture
Two library products. Depends on four primitives: swift-buffer-linear-primitives, swift-initialization-primitives, swift-storage-primitives, and swift-memory-heap-primitives (the verbose Storage.Contiguous<Memory.Heap> accumulator requires each as a direct dependency).
| Product | Target | When to import | |---------|--------|----------------| | Builder Primitives | Sources/Builder Primitives/ | Whenever a type composes the shared collection grammar via @Builder<Component>, or conforms to Buildable. | | Builder Primitives Test Support | Tests/Support/ | In test targets that need the toy consumer fixtures. |
Accumulator
Builder collects into Buffer<Storage<Component>.Contiguous<Memory.Heap<Component>>>.Linear — the lowest-level growable, ~Copyable-capable linear storage in the ecosystem, below every collection family. It is deliberately not Swift.Array (which requires Component: Copyable) and not a concrete family container (which would couple the grammar to one family). A composing family drains the returned buffer into its own structure.
What the grammar does not support
forloops. Swift's result-builder transform lowers aforloop throughbuildArray(_: [partial])— aSwift.Arrayof the partial result. The partial result isBuffer<Storage<Component>.Contiguous<Memory.Heap<Component>>>.Linear, which is itself~Copyable, so that array is illegal for anyComponent. Use an array literal or aSwift.Sequence(forCopyableelements), or imperative construction.~Escapablecomponents. The accumulator stores its elements, which requires them to beEscapable; a collect-and-return grammar inherently escapes the collected values.
This package ships only the grammar (Builder) and the grow-and-build capability (Buildable). Per-family DSL integrations are a separate, later workstream.
Foundation-free.
Platform Support
| Platform | Status | |----------|--------| | macOS 26 | Full support | | Linux | Full support | | Windows | Full support | | iOS / tvOS / watchOS / visionOS | Supported |
Community
License
Apache 2.0. See LICENSE.md.
Package Metadata
Repository: swift-primitives/swift-builder-primitives
Default branch: main
README: README.md