We're interested in building re-useable components for sync- and storage-related browser functionality - things like storing and syncing passwords, working with bookmarks and signing in to your Firefox Account.
And of course, we want to do this in a way that's convenient, maintainable, and difficult to mess up.
In an aspirational world, we could get this kind of easy cross-language interop for
free using wasm_bindgen and
webassembly interface types -
imagine writing an API in Rust, annotating it with some
compiling it into a webassembly bundle, and being able to import and use that bundle
from any target language, complete with a rich high-level API!
That kind of tooling is not available to shipping applications today, but that doesn't mean we can't take a small step in that general direction while the Rust and Wasm ecosystem continues to evolve.
Using UniFFI, you can:
- Implement your software component as a
cdylibcrate in Rust; let's say the code is in
- Specify the desired component API using an Interface Definition Language (specifically, a variant of WebIDL) in a separate file like
uniffi-bindgen scaffolding ./src/lib.udlto generate a bunch of boilerplate rust code that exposes this API as a C-compatible FFI layer, and include it as part of your crate.
cargo buildyour crate as normal to produce a shared library.
uniffi-bindgen generate ./src/lib.udl -l kotlinto generate a Kotlin library that can load your shared library and expose it to Kotlin code using your nice high-level component API!
-l pythonto produce bindings for other languages.
There are plenty of potential ways to solve this problem, and the one that's right for us might not be right for you. You can read a little more about the considerations and trade-offs that lead to the current approach in our Architecture Decision Records, starting with this motivational document.
We hope UniFFI will be useful to you! But if you're considering it for your project then here are some tradeoffs you should keep in mind:
- UniFFI makes it easy to produce "good enough" bindings into Rust from several different target languages. If you want to call Rust code from just one foreign language, there may be a language-specific bindings tool that provides more features and better performance.
- The project is evolving fast, because it's being developed concurrently with its primary consumers. You should be prepared for frequent releases and non-trivial API churn (but we'll use semantic versioning to signal breaking changes).
- UniFFI doesn't provide an end-to-end packaging solution for your Rust code and its generated bindings.
For example, it'll help you generate Kotlin bindings to call into Rust, but it won't help you with
compiling the Rust code to run on Android or with packaging the bindings into an
.aarbundle (but it might be useful as a building-block for such a tool!).
We also have a list of design principles that might help you decide whether this project is a good fit for your needs.