Skip to content

Swift Binding Generation via UniFFI #431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

Conversation

narner
Copy link

@narner narner commented Aug 14, 2025

Summary

Adds optional Swift binding generation using Mozilla's UniFFI behind a feature flag. Non-breaking, minimal changes
(~300 lines).

Approach

Uses Mozilla's UniFFI to automatically generate Swift bindings from Rust:

  • UniFFI handles FFI complexity and type conversions
  • Rust core remains the single source of truth
  • Generated bindings expose safe Swift APIs that call into compiled Rust

Changes

This PR will add 4 new files behind #[cfg(feature = "uniffi")]:

  • src/uniffi_bindings.rs (~60 lines) - Thin Rust wrapper exposing functions to UniFFI
  • src/tiktoken.udl (~25 lines) - UniFFI interface definition
  • uniffi.toml (~5 lines) - UniFFI config
  • build_xcframework.sh - Build script to build the Rust library for Apple platforms and bundle it into a cross-platform XCFramework

Usage

For Swift Developers

You can either add the XCFramework to your project directly, or use the Swift package I created: TiktokenSwift, which includes prebuilt bindings, tests, documentation, and an example project.To add the Swift package:

// Package.swift
dependencies: [
	.package(url: "https://github.com/nicholasarner/TiktokenSwift", from: "1.0.0")
]

Swift API Example

let encoder = try Tiktoken(encoding: "cl100k_base")
let tokens = encoder.encode(text: "Hello world")
let decoded = encoder.decodeBytes(tokens: tokens)

Supports all encodings: cl100k_base, o200k_base, r50k_base, p50k_base

For Maintainers/Contributors

To regenerate bindings from source, first make sure you install the required Rust targets:

rustup target add aarch64-apple-ios      # iOS devices
rustup target add aarch64-apple-ios-sim  # iOS Simulator (Apple Silicon)
rustup target add x86_64-apple-ios       # iOS Simulator (Intel)
rustup target add aarch64-apple-darwin   # macOS (Apple Silicon)
rustup target add x86_64-apple-darwin    # macOS (Intel)


To build just the cross-device Rust framework, run:

cargo build --release --features uniffi

To generate the bindings, run:

uniffi-bindgen generate src/tiktoken.udl --language swift

To build the frameworks, generate the bindings, and package everything together as an XCFramework, run:

./build_xcframework.sh

Testing

  • ✅ All existing Rust tests pass
  • ✅ Swift package includes comprehensive test suite
  • ✅ Tested on iOS 13+, macOS 10.15+
  • ✅ XCFramework ~5MB (includes compiled Rust library)

Impact

  • Feature flag means zero impact when disabled
  • Swift package maintained separately
  • No changes to existing Rust functionality
  • UniFFI approach could enable other language bindings in future

narner added 7 commits August 5, 2025 12:20
- Create minimal UniFFI interface definition (tiktoken.udl)
- Implement Rust wrapper for UniFFI compatibility
- Use byte arrays directly for non-UTF8 token support
- Expose only essential tokenization methods
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