BoltFFI

BoltFFI is a tool that generates foreign-language bindings from Rust libraries. It fits the practice of consolidating business logic in a single Rust library while targeting multiple platforms, making it simpler to develop and maintain a cross-platform codebase. BoltFFI helps you ship a Rust library to any platform: run boltffi pack and get ready-to-use native libraries and bindings. The generated wrappers handle type conversion, memory management, and error propagation across the language boundary.

The generated bindings are native code that uses each language’s idioms. Swift bindings use structured concurrency with async/await. Kotlin bindings use coroutines. WASM bindings integrate with JavaScript async. Errors become native exceptions. Types map to their platform equivalents. The result is code you can use natively, without dealing with pointers or manual memory management.

BoltFFI uses a zero-copy approach where possible. Primitives and structs containing only primitives pass across the boundary without serialization. Complex types like strings and collections use a wire format.

BoltFFI architecture diagram
RustSource
use boltffi::*;

#[data]
pub struct Point {
  pub lat: f64,
  pub lng: f64,
}

#[export]
pub fn distance(from: Point, to: Point) -> f64 {
  let dlat = to.lat - from.lat;
  let dlng = to.lng - from.lng;
  (dlat * dlat + dlng * dlng).sqrt()
}
// Generated Swift
public struct Point {
  public var lat: Double
  public var lng: Double
}

func distance(from: Point, to: Point) -> Double

// Usage
let d = distance(from: a, to: b)

How it works

  1. Add boltffi as a dependency
  2. Mark types with #[data] and functions with #[export]
  3. Run boltffi pack --apple or boltffi pack --android
  4. Import the generated framework in your project

BoltFFI scans your code for the annotations, generates C FFI functions, and produces language-specific wrappers that call them. Primitives and simple structs pass directly across the boundary without copying. Complex types use a wire format that both sides understand.

Performance

Primitives pass as raw values. Structs with primitive fields pass as pointers. Only strings and nested collections go through encoding.

Benchmarks on Apple Silicon, compared to UniFFI:

OperationBoltFFIUniFFISpeedup
Primitive (i32, f64)<1 ns625 ns
Small string42 ns1,958 ns47x
1,000 structs1,958 ns1,195,354 ns611x
10,000 i32 values1,291 ns1,991,146 ns1,542x

Full benchmark code: bench_demo.

Supported languages

BoltFFI has full support for Swift and Kotlin. All features documented in this manual work for both languages. Adding support for more languages is in progress.

LanguageStatus
SwiftSupported
KotlinSupported
WASMIn progress
PythonIn progress
C#In progress

If you want a language added or considered, open an issue.

What you can export

  • Primitives, strings, structs, enums, Option, Result, Vec, HashMap
  • Sync and async functions
  • Closures and callback traits
  • Classes with methods
  • Async streams
  • Rust errors as exceptions

See Types for the full mapping, or Getting Started to set up a project.