Skip to content

boltffi/boltffi

Repository files navigation

BoltFFI

A high-performance multi-language bindings generator for Rust. Up to 1,000x faster than UniFFI. Up to 450x faster than wasm-bindgen.

Quick links: User Guide | Tutorial | Getting Started

Performance

vs UniFFI (Swift/Kotlin)

Benchmark BoltFFI UniFFI Speedup
noop <1 ns 1,416 ns >1000x
echo_i32 <1 ns 1,416 ns >1000x
counter_increment (1k calls) 1,083 ns 1,388,895 ns 1,282x
generate_locations (1k structs) 4,167 ns 1,276,333 ns 306x
generate_locations (10k structs) 62,542 ns 12,817,000 ns 205x

vs wasm-bindgen (WASM)

Benchmark BoltFFI wasm-bindgen Speedup
1k particles 29,886 ns 13,532,530 ns 453x
100 particles 3,117 ns 748,287 ns 240x
1k locations 21,931 ns 4,037,879 ns 184x
1k trades 42,015 ns 5,781,767 ns 138x
100 locations 2,199 ns 283,753 ns 129x

Full benchmark code: benchmarks

Why BoltFFI?

Serialization-based FFI is slow. UniFFI serializes every value to a byte buffer. wasm-bindgen materializes every struct as a JavaScript object. That overhead shows up even when you're making tens or hundreds of FFI calls per second.

BoltFFI uses zero-copy where possible. Primitives pass as raw values. Structs with primitive fields pass as pointers to memory both sides can read directly. WASM uses a wire buffer format that avoids per-field allocation. Only strings and collections go through encoding.

What it does

Mark your Rust types with #[data] and functions with #[export]:

use boltffi::*;

#[data]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

#[export]
pub fn distance(a: Point, b: Point) -> f64 {
    let dx = b.x - a.x;
    let dy = b.y - a.y;
    (dx * dx + dy * dy).sqrt()
}

Run boltffi pack:

boltffi pack apple
# Produces: ./dist/apple/YourCrate.xcframework + Package.swift

boltffi pack android
# Produces: ./dist/android/jniLibs/*.so + Kotlin bindings

boltffi pack wasm
# Produces: ./dist/wasm/pkg/*.wasm + TypeScript bindings + npm package

Use it from Swift, Kotlin, or TypeScript:

let d = distance(a: Point(x: 0, y: 0), b: Point(x: 3, y: 4)) // 5.0
val d = distance(a = Point(x = 0.0, y = 0.0), b = Point(x = 3.0, y = 4.0)) // 5.0
import { distance } from 'your-crate';
const d = distance({ x: 0, y: 0 }, { x: 3, y: 4 }); // 5.0

The generated bindings use each language's idioms. Swift gets async/await. Kotlin gets coroutines. TypeScript gets Promises. Errors become native exceptions.

Supported languages

Language Status
Swift Full support
Kotlin Full support
WASM/TypeScript Full support
Python Planned
C# Planned
Ruby Planned

Want another language? Open an issue.

Installation

cargo install boltffi_cli

Add to your Cargo.toml:

[dependencies]
boltffi = "0.1"

[lib]
crate-type = ["staticlib", "cdylib"]

Documentation

Alternative tools

Other tools that solve similar problems:

  • UniFFI - Mozilla's binding generator, uses serialization-based approach
  • Diplomat - Focused on C/C++ interop
  • cxx - Safe C++/Rust interop

Contributing

Contributions are warmly welcomed 🙌

License

BOLTFFI is released under the MIT license. See LICENSE for more information.

About

A high-performance multi-language bindings generator for Rust, up to 1,000x faster than UniFFI. Ship Rust libraries that feels native to Swift, Kotlin, and more

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors