Skip to content

Swift SDK + Swift demo clients + Ninja game fixes/perf/UI polish#4509

Draft
avias8 wants to merge 28 commits intoclockworklabs:masterfrom
avias8:swift-integration
Draft

Swift SDK + Swift demo clients + Ninja game fixes/perf/UI polish#4509
avias8 wants to merge 28 commits intoclockworklabs:masterfrom
avias8:swift-integration

Conversation

@avias8
Copy link

@avias8 avias8 commented Mar 1, 2026

What

Native Swift SDK for SpacetimeDB, plus Swift code generation, two end-to-end Swift demo clients, and CI/E2E tooling in the monorepo.

This PR adds first-class Swift support via:

  • sdks/swift pure Swift package runtime
  • Swift backend in crates/codegen + CLI integration (spacetime generate --lang swift)
  • Swift demo clients:
    • demo/simple-module/client-swift
    • demo/ninja-game/client-swift
  • Swift-focused CI:
    • SDK/package build + test workflow
    • procedure callback E2E workflow
    • generated-binding drift check

Why

SpacetimeDB needed a native Swift client path for Apple platforms and realtime Swift UI/game workloads without relying on non-Swift client layers.

This PR enables:

  • Native iOS/macOS integration through Swift Package Manager
  • Typed Swift bindings generated from module schema
  • End-to-end validation against real local modules
  • CI enforcement that generated Swift bindings remain in sync with codegen

Branch Scope

Metric Value
Comparison base upstream/master
HEAD commit 973c6dcf9
Commits ahead 5
Non-merge commits 5
Files changed 86
Insertions 13,962
Deletions 28

Commit Structure

Order Commit Message
1 5bda437e1 swift-sdk: add native runtime package and tests
2 5b7881f5c codegen(swift): add generator backend and CLI integration
3 96bddcd76 demo(simple-module): add module, generated bindings, and Swift app
4 6cf0e66ca demo(ninja-game): add module, generated bindings, and Swift game client
5 973c6dcf9 ci(swift): add SDK workflow, E2E checks, and drift guard

Architecture

  • Wire protocol: v2.bsatn.spacetimedb client/server message support with BSATN binary serialization
  • Transport: URLSessionWebSocketTask with Sec-WebSocket-Protocol: v2.bsatn.spacetimedb
  • Concurrency:
    • @MainActor lifecycle for API/cache-facing state
    • utility-priority decode queue for server frame decoding
    • serialized outbound websocket send queue
  • Compression: frame decode support for None, Gzip, Brotli using Apple Compression + zlib
  • Cache:
    • ClientCache table registration by canonical wire table name
    • TableCache<T> row-byte keyed multiset model (no blanket Identifiable coupling)
  • Generation pipeline:
    • Rust codegen emits Swift row/table/reducer/procedure/module files
    • CLI language detection + Swift output support
    • drift checker regenerates demo bindings and diffs committed generated output

Features

  • Connect/disconnect with delegate callbacks
  • Auth token support on connection
  • SQL subscriptions (subscribe / unsubscribe / subscribe-all helper)
  • Reducer invocation via generated wrappers
  • Procedure invocation with typed decode callback variant
  • One-off queries (callback + async/await variants)
  • Automatic reconnection with configurable policy (max retries/backoff/jitter)
  • Configurable compression negotiation (None, Gzip, Brotli)
  • Generated module registration + table cache accessors

File Layout

sdks/swift/
├── Package.swift
├── README.md
├── Sources/SpacetimeDB/
│   ├── BSATN/
│   │   ├── BSATNEncoder.swift
│   │   └── BSATNDecoder.swift
│   ├── Cache/
│   │   ├── ClientCache.swift
│   │   └── TableCache.swift
│   ├── Network/
│   │   ├── ProtocolMessages.swift
│   │   ├── ServerMessageFrameDecoder.swift
│   │   └── SpacetimeClient.swift
│   ├── RuntimeTypes.swift
│   └── SpacetimeDB.swift
└── Tests/SpacetimeDBTests/
    ├── BSATNTests.swift
    ├── CacheTests.swift
    └── NetworkTests.swift

crates/
├── codegen/src/swift.rs
├── codegen/src/lib.rs
└── cli/src/subcommands/generate.rs

demo/simple-module/
├── spacetimedb/     # Rust module
└── client-swift/    # Swift package + generated bindings + app

demo/ninja-game/
├── spacetimedb/     # Rust module
└── client-swift/    # Swift package + generated bindings + app/resources

.github/workflows/
├── swift-sdk.yml
└── swift-procedure-e2e.yml

tools/
├── swift-procedure-e2e.sh
├── swift-procedure-e2e.md
└── check-swift-demo-bindings.sh

Test Coverage

Swift SDK tests: 37 tests across 3 test files (all passing).

Category Tests Coverage
BSATN 12 Primitive/product/sum/optional encode-decode, invalid-tag/invalid-bool guards, runtime special types
Cache 2 Client cache routing and idempotent registration behavior
Network/Protocol 23 Message encode/decode, subscription lifecycle, one-off/procedure callbacks, reconnect policy, compression frame decode, option-tag correctness

Validation Results (Executed 2026-03-02)

Area Command Result Notes
Swift SDK tests swift test --package-path sdks/swift ✅ PASS 37 passed, 0 failed
Simple demo build swift build --package-path demo/simple-module/client-swift ✅ PASS Build complete
Ninja demo build swift build --package-path demo/ninja-game/client-swift ✅ PASS Build complete
Codegen tests cargo test -p spacetimedb-codegen --test codegen ✅ PASS 4 passed
CLI generate tests cargo test -p spacetimedb-cli generate:: -- --nocapture ✅ PASS 24 passed
Binding drift tools/check-swift-demo-bindings.sh ✅ PASS Both demo generated dirs in sync
Procedure E2E tools/swift-procedure-e2e.sh ✅ PASS E2E OK (SleepOneSecondProcedure callback succeeded in ~1.04s)

Performance

No dedicated throughput/TPS benchmark suite is included in this PR write-up, so no benchmark claims are made here.

Observed from validation:

  • End-to-end generated procedure callback path succeeds (SleepOneSecondProcedure callback observed at ~1.04s, consistent with procedure behavior)

Bug Fixes Included

  • Option-tag decoding correctness in protocol models:
    • UnsubscribeApplied
    • SubscriptionError
  • Added runtime special types required by generated schemas:
    • Identity
    • ClientConnectionId
    • ScheduleAt
    • SpacetimeResult<Ok, Err>
  • Codegen compatibility hardening:
    • SATS Result<T,E> mapped to SpacetimeResult<T,E>
    • removed blanket Identifiable emission from generated types
    • table registration uses canonical wire table names
  • Cache/model compatibility hardening:
    • removed hard Identifiable generic constraint in Swift cache path
  • Generated artifact consistency fixes:
    • regenerated demo bindings
    • removed stale manual generated files
    • added missing generated files (Join.swift, CombatHitCooldown.swift)
  • CI/tooling hardening:
    • E2E script compiles dynamic SDK source list
    • added generated-binding drift guard to CI

Roadmap

Phase 1 — Swift SDK Core Runtime (completed baseline)

  • BSATN encode/decode
  • v2 protocol handling
  • websocket transport
  • reconnect policy
  • local cache layer

Phase 2 — Swift codegen and typed access (completed baseline)

  • spacetime generate --lang swift
  • generated row/reducer/procedure/table/module files
  • demo binding sync + CI drift checks

Phase 3 — Event/procedure surface expansion (in progress)

  • richer event context and callback ergonomics
  • additional typed convenience APIs

Phase 4 — Observability (planned)

  • structured logging options
  • connection/runtime metrics

Phase 5 — Platform/productization (planned)

  • packaging/distribution hardening
  • broader Apple integration polish
  • dedicated reproducible benchmark suite

Feature Parity

Other SDK columns are not fully re-audited in this pass; Swift column reflects this PR scope.

Feature Swift C# TypeScript Rust
BSATN Protocol done not audited in this pass not audited in this pass not audited in this pass
WebSocket Transport done not audited in this pass not audited in this pass not audited in this pass
Reconnection done not audited in this pass not audited in this pass not audited in this pass
Compression decode done not audited in this pass not audited in this pass not audited in this pass
Keep-Alive ping/pong planned not audited in this pass not audited in this pass not audited in this pass
Row Cache done not audited in this pass not audited in this pass not audited in this pass
Subscriptions done not audited in this pass not audited in this pass not audited in this pass
One-off Queries done not audited in this pass not audited in this pass not audited in this pass
Reducer Calls done not audited in this pass not audited in this pass not audited in this pass
Procedure Calls done not audited in this pass not audited in this pass not audited in this pass
Code Generation done not audited in this pass not audited in this pass not audited in this pass
Logging planned not audited in this pass not audited in this pass not audited in this pass
Metrics planned not audited in this pass not audited in this pass not audited in this pass
Framework Integration partial (SwiftUI demos) not audited in this pass not audited in this pass not audited in this pass

Dependencies

Swift runtime/package

  • Swift tools: 6.2
  • Platforms:
    • macOS 15+
    • iOS 17+
  • System frameworks:
    • Foundation
    • Compression
    • zlib
  • Third-party Swift package dependencies: none

Tooling/CI dependencies used for validation

  • Rust toolchain + Cargo
  • Local spacetime CLI built from this repo

Build

# Swift SDK tests
swift test --package-path sdks/swift

# Swift demo builds
swift build --package-path demo/simple-module/client-swift
swift build --package-path demo/ninja-game/client-swift

# Rust-side generation tests
cargo test -p spacetimedb-codegen --test codegen
cargo test -p spacetimedb-cli generate:: -- --nocapture

# Generated binding drift check
tools/check-swift-demo-bindings.sh

# Live procedure callback E2E
tools/swift-procedure-e2e.sh

Notes

  • tools/swift-procedure-e2e.sh publishes a local module and runs a live callback check.
  • If wasm-opt is unavailable, scripts continue with unoptimized wasm and still complete successfully.
  • changes.md is intentionally untracked and not part of branch commits.

@CLAassistant
Copy link

CLAassistant commented Mar 1, 2026

CLA assistant check
All committers have signed the CLA.

@avias8
Copy link
Author

avias8 commented Mar 1, 2026

Ninja Wars is a SwiftUI Game built using with the new Swift SDK

image image

@avias8 avias8 marked this pull request as draft March 2, 2026 16:30
@avias8
Copy link
Author

avias8 commented Mar 2, 2026

Still working on this pull request. A shout out to #4471 and https://github.com/AndroidPoet, who taught me a lot as I was working on the Swift SDK. Thank you for your work!

@avias8 avias8 force-pushed the swift-integration branch from 849bbbc to 1f31ac8 Compare March 2, 2026 20:10
@avias8 avias8 force-pushed the swift-integration branch from 1f31ac8 to 973c6dc Compare March 2, 2026 20:15
avias8 added 16 commits March 2, 2026 14:29
- Removed @mainactor bottleneck from SpacetimeClient and TableCache
- Implemented in-place dictionary mutations and optimized snapshotting (O(N))
- Added specialized BSATN primitive serialization (U32, U64, I64)
- Implemented BSATN manual fast-paths for hot-path types
- Improved memory efficiency with zero-copy Data slicing
- Achieved ~420x speedup in cache operations
…dware decompression

- Convert `BSATNReader` and `BSATNStorage` to zero-allocation `~Copyable` structs with Swift 6 Typed Throws.
- Add `BSATNFastCopyable` array memcpy optimizations for primitive arrays on little-endian targets.
- Replace `UnfairLock` with `Synchronization.Mutex` and eliminate `@unchecked Sendable` across caching and networking layers for strict concurrency.
- Switch `ServerMessageFrameDecoder` from `zlib` to Apple's native `Compression` framework for hardware-accelerated GZIP decoding.
- Update codegen to conform generated table row structs to `Identifiable` when a primary key is defined.
avias8 added 7 commits March 2, 2026 21:55
…ead optimizations

- crates/codegen/src/swift.rs: Add SIMD Type Mapping. Rust codegen now detects mathematical types (Vector2, Vector3, Vector4, Quaternion) and generates native Apple `simd_float` and `simd_quatf` structs to utilize hardware vector registers.
- TableCache/ClientCache: Implement bulk operations (handleBulkInsert, handleBulkDelete, handleBulkUpdate). This eliminates lock contention by mutating the dictionary in bulk per network frame.
- SpacetimeClient: Route heavy GZIP/Brotli decompression and BSATN decoding to a dedicated `.utility` QoS DispatchQueue to maximize efficiency core usage and prevent thermal throttling while unblocking the WebSocket IO thread.
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.

2 participants