Skip to content

feat: NativeConcurrency package trait — NIO-free Swift-concurrency backend for SQLiteNIO#2

Draft
scottmarchant wants to merge 10 commits into
feat/khasmPAL-2026from
feat/native-concurrency-trait
Draft

feat: NativeConcurrency package trait — NIO-free Swift-concurrency backend for SQLiteNIO#2
scottmarchant wants to merge 10 commits into
feat/khasmPAL-2026from
feat/native-concurrency-trait

Conversation

@scottmarchant

Copy link
Copy Markdown
Collaborator

What

Adds a NativeConcurrency package trait to SQLiteNIO: an opt-in, NIO-free Swift-concurrency backend for the connection/query surface.

  • Package@swift-6.1.swift (versioned traits manifest): declares three traits — NIO (member of the default trait set), NativeConcurrency, and Freestanding. Pre-6.1 toolchains never see this file and keep resolving the plain Package.swift, so nothing changes for them.
  • NIO stays the default trait: a consumer that specifies nothing gets the existing NIO/EventLoopFuture-based API, byte-identical to today.
  • --traits NativeConcurrency re-keys the sources (#if NativeConcurrency) from EventLoopFuture/EventLoop-threaded APIs onto plain async/await: SQLiteConnection, SQLiteDatabase, hooks, custom functions, statement/data conversion paths.
  • NativeConcurrencyLockedBox (Sources/SQLiteNIO/NativeConcurrencyLock.swift): a small mutex-backed box that replaces NIOLockedValueBox for the connection's shared mutable state under the NativeConcurrency flavor, preserving the thread-safety guarantees without pulling in NIOConcurrencyHelpers.

Why

Staged fork-internally ahead of a possible upstream proposal: it lets Swift-concurrency-native (and Embedded/WASI-leaning) consumers drop the NIO dependency surface entirely while keeping one source tree, selected purely through SwiftPM package traits.

Verification

  • Default flavor: swift build and swift test green — the default (NIO) trait build is unchanged behavior.
  • swift build --traits NativeConcurrency: green, with no NIO event-loop surface in the built module (no EventLoopFuture in the NativeConcurrency-keyed API).
  • Shared-state safety under the new flavor goes through the NativeConcurrencyLockedBox shim.

Branch shape

The head branch carries the fork's embedded-port lineage this trait conversion was built on (NIO-free data/connection paths, Embedded-only gating, PassiveLogic swift-nio fork reference), topped by the trait conversion commit itself. Base is the fork's feat/khasmPAL-2026 at exactly the revision khasm pins, so the diff is precisely the embedded-port + trait work.

🤖 Generated with Claude Code

scottmarchant and others added 10 commits June 16, 2026 10:32
NIOPosix carries a resource bundle whose generated accessor imports Foundation, unavailable on the embedded WASI target; gate it to non-WASI and rely on NIOAsyncRuntime there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
EmbeddedWASI drops all swift-nio products (NIOCore/NIOPosix/NIOAsyncRuntime/NIOFoundationCompat), leaving CSQLite + swift-log for a NIO-free Swift-Concurrency SQLite driver. SwiftNIO (default) is unchanged. Non-breaking for older toolchains.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… trait)

Gate NIOCore/NIOPosix/NIOFoundationCompat on .when(platforms: nonWASIPlatforms); remove NIOAsyncRuntime. On WASI only CSQLite + swift-log remain, for a NIO-free Swift-Concurrency driver gated with #if os(WASI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…able)

On WASI the blob case stores [UInt8] instead of ByteBuffer (NIOCore is elided). The Encodable conformance moves to a #if !hasFeature(Embedded) extension since Encoder is unavailable in Embedded Swift (still present on regular WASI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…exports

SQLiteStatement binds/reads blobs via [UInt8] (withUnsafeBytes / append) instead of ByteBuffer on WASI. Exports.swift re-exports only SwiftNIO types, so it's gated entirely on #if !os(WASI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…WASI

Gate the NIO EventLoopFuture/NIOThreadPool connection and the hook subsystem behind #if !os(WASI); add SQLiteConnection+WASI.swift, a Swift-Concurrency connection over CSQLite (blocking calls run inline since wasm is single-threaded; no EventLoop/threadpool/hooks/pool). The WASI SQLiteDatabase protocol has only non-generic requirements (logger + async query) so it remains usable as 'any SQLiteDatabase' under Embedded Swift; withConnection stays on the concrete connection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or types on WASI

SQLiteError: LocalizedError moved to a #if !os(WASI) extension. SQLiteDataConvertible: ByteBuffer/Data/Date conformances gated, [UInt8] blob conformance added for WASI. SQLiteDataType: gate the any-Encodable serialize (Embedded). SQLiteRow/SQLiteCustomFunction: gate reflection-based Array.description, any-Error interpolation, and ByteBuffer blob result handling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for khasm)

The embedded port previously selected the NIO-free Swift-Concurrency
driver with `#if os(WASI)` and dropped SwiftNIO for every WASI build.
khasm's shipping regular-wasm flavor, however, runs SQLiteNIO on WASI
with NIO (NIOAsyncRuntime event loops, ByteBuffer blobs), so the
wasi-wide gate would have changed the shipping data path.

- Source gates `#if os(WASI)` -> `#if hasFeature(Embedded)` for every
  gate the embedded port introduced (regular WASI is restored to the
  feat/khasmPAL-2026 base behavior: NIO protocol, ByteBuffer blob,
  NIOAsyncRuntime substitution). Pre-existing os(WASI) gates inside the
  NIO connection are untouched.
- Exports.swift: base NIO re-exports restored, wrapped in
  `#if !hasFeature(Embedded)`.
- Package.swift: base NIO products restored (incl. NIOAsyncRuntime on
  wasi); the whole NIO stack is dropped only with KHASM_EMBEDDED=1
  (manifests cannot see hasFeature; matches khasm's manifest gating).

Verified: embedded SDK build (KHASM_EMBEDDED=1) green; native green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ot the local clone

Transitive path deps override URL declarations by identity in a
consuming root graph (khasm), and the local ../swift-nio clone carries
the vestigial Option-1/2 embedded-NIO commits whose os(WASI) gates would
change regular-WASI NIO behavior. Under KHASM_EMBEDDED=1 the NIO
products are dropped, so the embedded build never compiles NIO from
either source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ckend

Add SwiftPM traits via a versioned Package@swift-6.1.swift (base manifest
restored byte-identical to the branch base for older toolchains):

- traits: `NIO` (default; keeps the SwiftNIO backend exactly as today) and
  `NativeConcurrency` (NIO-free backend: async/await connection, [UInt8]
  blobs, no EventLoopFuture/ByteBuffer/NIOThreadPool). NIO products carry
  `.when(traits: ["NIO"])`; the KHASM_EMBEDDED env conditional is gone.
- Source: the NIO-swap gates are re-keyed from `#if hasFeature(Embedded)`
  to `#if NativeConcurrency` (blob representation, protocol split, async
  connection, hooks, re-exports). Genuine Embedded language-limit gates
  (Encodable, LocalizedError, reflection descriptions, error interpolation,
  Date/Foundation) stay on `hasFeature(Embedded)`.
- New on the NativeConcurrency path (it can now build on multithreaded
  hosts): `NativeConcurrencyLockedBox` (os_unfair_lock on Darwin,
  pthread_mutex elsewhere, direct access on single-threaded Embedded WASI)
  guarding the connection handle and row collection, and a [UInt8]-based
  `Data: SQLiteDataConvertible` when Foundation is present without NIO.
- SQLiteConnection+WASI.swift renamed to SQLiteConnection+NativeConcurrency.swift.
- VendorSQLite plugin: `nonisolated(unsafe)` on its verbose flag (plugins
  compile in Swift 6 mode under the tools-6.1 manifest).

Verified: default `swift build` + `swift test` (55/55) unchanged;
`swift build --traits NativeConcurrency` green on native macOS with zero
NIO symbols in the built objects.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant