Skip to content

Conversation

@scottmarchant
Copy link

Summary

This PR adds support for compiling sqlite-nio to wasm using the Swift SDK for WebAssembly.

This PR is part of a larger effort by a company called PassiveLogic to enable broad support for Swift WebAssembly.

Details

  • Dynamically configure sqlite thread safety constructs depending on the WASM SDK being used. Some variation include support for pthreads, but the official distributions do not. The configuration dynamically supports either situation, and leaves all other platforms and configurations unaffected.
  • Adds new dependency on NIOAsyncRuntime for WASM builds only, which provides a WASM-compatible alternative for NIOPosix (which does not compile to wasm).
  • Removed unused import NIOPosix and import NIOCore imports that introduced non-required dependencies on NIOPosix
  • Fixed issue with SQLITE_INTEGER not working correctly on wasm builds. It reverted to a 32 bit integer, since wasm builds are currently 32 bit. Set up a new SQLiteDataIntegerType that handles the integer typing from a centralized definition.
  • Update documentation exports to include new NIOAsyncRuntime.

Testing done

  • Verified unit tests still pass
  • Verified no new warnings are created
  • Verified swift build --swift-sdk swift-6.2.2-RELEASE_wasm --target SQLiteNIO completes without errors. Latest official Swift release.
  • Verified swift build --swift-sdk swift-6.3-DEVELOPMENT-SNAPSHOT-2025-12-07-a_wasm --target SQLiteNIO completes without errors. This is the latest daily snapshot of the swift toolchain.
  • Verified a third-party executable can build this library as part of a larger wasm executable, and run sqlite in the browser.
  • Verified these changes compile in CI. See https://github.com/PassiveLogic/sqlite-nio/actions/runs/20151748120/job/57845890248?pr=1. Note that the android builds time out starting an emulator, which appears to be a pre-existing issue unrelated to these changes.

Usage notes

The current Swift 6.2.x breaks certain wasm executors that make testing wasm executables like this impossible. To fully test this running in the browser, recommend using Swift 6.3.x or later.

Impact Risk

There is a chance the changes to the manifest and exports could be a breaking change somewhere, if downstream dependencies relied on those pieces for their one and only intrinsic inclusion of the entire NIO dependency beyond NIOCore.

There are solutions to narrow the scope to just wasm compilation for those changes, if that is an issue. But I chose to leave them this way since it is a little cleaner solution.

@codecov
Copy link

codecov bot commented Dec 12, 2025

Codecov Report

❌ Patch coverage is 80.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 70.88%. Comparing base (2ab6138) to head (bf7b024).

Files with missing lines Patch % Lines
Sources/SQLiteNIO/SQLiteData.swift 75.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #98   +/-   ##
=======================================
  Coverage   70.88%   70.88%           
=======================================
  Files          10       10           
  Lines         965      965           
=======================================
  Hits          684      684           
  Misses        281      281           
Files with missing lines Coverage Δ
Sources/SQLiteNIO/SQLiteConnection.swift 69.09% <ø> (ø)
Sources/SQLiteNIO/SQLiteDatabase.swift 20.00% <ø> (ø)
Sources/SQLiteNIO/SQLiteStatement.swift 95.06% <100.00%> (ø)
Sources/SQLiteNIO/SQLiteData.swift 75.00% <75.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines 4 to 14
#if _pointerBitWidth(_64)
// We use Int instead of Int64 on 64 bit systems primarily for
// backwards compatibility, since prior code versions have used Int here.
public typealias SQLiteDataIntegerType = Int // 64-bit platform, Int = 64 bits
#elseif _pointerBitWidth(_32)
public typealias SQLiteDataIntegerType = Int64 // On 32-bit platforms, we want to use 64 bit integers.
#else
// If you hit errors here, you may simply need to add
// a new architectural bit size above (eg. _128) when that
// exists.
//
// Or if the following proposal for pointerBitWidth ever lands in a
// published Swift version, then the above conditionals may
// need adjusted:
//
// https://forums.swift.org/t/pitch-pointer-bit-width-compile-time-conditional/59572
#error("Unsupported integer size")
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sqlite-no has (obviously) not previously supported 32-bit runtime environments. I'm not familiar enough with Wasm to know whether 32-bit is an environment we should be expecting to encounter on a regular basis?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gwynne At the moment, the swift for WebAssembly SDK only supports 32 bit. 64 bit support is on the roadmap, but will probably be a while. I'm pretty sure that all the other officially supported swift platforms besides wasm are 32 bit. Except maybe Swift Embedded, but supporting Swift Embedded would likely be a long haul in sqlite-nio.

Package.swift Outdated
import PackageDescription

let wasiPlatform: [Platform] = [.wasi]
let nonWASIPlatforms: [Platform] = [.macOS, .macCatalyst, .iOS, .tvOS, .watchOS, .visionOS, .driverKit, .linux, .windows, .android, .openbsd]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really not a fan of having to manually list out every "not that one" platform like this, but I know SwiftPM, ever its eternally helpful self, provides no way of avoiding it (my kingdom for condition: .when(notPlatforms: [...])...).

I'm also not sure how I feel about adding a new third-party dependency here. @0xTim can you chime in on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely can't add a dependency without a stable API yet for sure. Realistically what we should do is migrate SQLiteNIO off NIO entirely to AsyncSequence<ArraySlice<UInt8>> and custom executors. There's nothing that requires NIO anymore with modern Swift Concurrency

Copy link
Author

@scottmarchant scottmarchant Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xTim @gwynne Agreed, this isn't my favorite way to do this, either. But like Gwynne mentioned, not a lot of better alternatives currently. There isn't currently an allCases option, since each of these are static properties in a struct, rather than an enum. To your point, it is easy for this list to grow out of date. For example, I copied this from the swift-package-manager source a few months ago, and since then .freeBSD was added. As swift grows in popularity, this will be more and more of a problem. I can only assume at some point someone will either change that to an enum, or else add an allCases convenience that centralizes lists like this. A .when(notPlatforms: [...])...) would be really helpful here obviously. Since none of those are options, I'm not sure there is a better way. But I would love to use any better alternative solutions that don't break wasm compilation.

A few things to note here:

  • None of the changes in this PR change the publicly advertised supported platforms. Lines 10-13 in the manifest remain untouched.
  • This pattern here matches similar approaches used in the swift-nio manifest

The worst case problem I can think of with this implementation is that a platform not included in this list won't get the NIOPosix dependency, and won't be able to compile. Since all of the platforms officially supported sqlite-nio are already included in this list, this would only be a problem for new platforms, and there is no advertised promise of support for those platforms. If it manifests as a problem, it would be trivial to submit a PR to add a new platform to the list.

I suppose I could try to refactor NIO completely out, but that was a bit out of scope of my original goal to support wasm. The current PR changeset should leave existing platform support unaffected. A larger refactor to completely remove NIO and transition to Swift Concurrrency would bring the risk of affecting existing usage of sqlite-nio.

One thing to note, my introduction of nio-async-runtime here is essentially a port to Swift Concurrency. I ran benchmarks comparing performance of nio-async-runtime compared to NIOPosix, and NIOPosix did show significantly better performance in the benchmarks I ran. I'm not sure how it would affect end-to-end performance, but figured I would mention it. There is a risk with transitioning from NIOPosix to Swift Concurrency that performance will decrease. With this PR, that is a non-issue, because all platforms except WASI still use NIOPosix.

Happy to look into any option here, appreciate the great review and feedback! Any thoughts or requests here? 😁

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a sanity check on this list, this is also the full list on Swift 5.10. Since the swift-tools-version in this manifest is 5.10, we probably wouldn't want to add the new .freeBSD platform here, since 5.10 versions of SPM wouldn't work. But all of these options are defined in the 5.10 release of SPM

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored this a little to improve the maintenance and clarity. Please let me know if any other changes or improvements can be made.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@0xTim This now relies on a semver-stable release of nio-async-runtime. Please let me know if there is anything else I can do to improve this PR. 🎉

@gwynne gwynne requested a review from 0xTim December 12, 2025 01:46
Copy link
Author

@scottmarchant scottmarchant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gwynne @0xTim I believe I have addressed all feedback, other than the last few comments that I've left unresolved pending your response. Please let me know if there is anything I can do to help move this forward 🎉

Package.swift Outdated
import PackageDescription

let wasiPlatform: [Platform] = [.wasi]
let nonWASIPlatforms: [Platform] = [.macOS, .macCatalyst, .iOS, .tvOS, .watchOS, .visionOS, .driverKit, .linux, .windows, .android, .openbsd]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I refactored this a little to improve the maintenance and clarity. Please let me know if any other changes or improvements can be made.

@scottmarchant
Copy link
Author

Moving this to draft while I upstream NIOAsyncRuntime into swift-nio.

@scottmarchant scottmarchant marked this pull request as draft January 15, 2026 23:38
@scottmarchant scottmarchant force-pushed the feat/swift-wasm-support-v2 branch 2 times, most recently from de29676 to b72dc95 Compare January 16, 2026 18:46
@scottmarchant scottmarchant force-pushed the feat/swift-wasm-support-v2 branch 3 times, most recently from ef563aa to aba49b8 Compare January 30, 2026 00:17
@scottmarchant scottmarchant force-pushed the feat/swift-wasm-support-v2 branch from aba49b8 to 312bd20 Compare January 30, 2026 00:34
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.

3 participants