GithubHelp home page GithubHelp logo

tchigher / uniffi-rs Goto Github PK

View Code? Open in Web Editor NEW

This project forked from mozilla/uniffi-rs

0.0 0.0 0.0 1.95 MB

a multi-language bindings generator for rust

License: Mozilla Public License 2.0

Rust 66.64% Kotlin 7.97% Python 6.77% Swift 6.44% C++ 11.38% WebIDL 0.81%

uniffi-rs's Introduction

uniffi - a multi-language bindings generator for rust

This is a little experiment in building cross-platform components in Rust, based on things we've learned in the mozilla/application-services project.

It's currently at the "basic prototype" stage - the core idea seems to work, but there are a lot of missing details and it needs a lot of polish. We're currently focussed on making it useable for a real shipping component.

If this sounds interesting to you, please dive in! You can:

What?

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.

We want to write the code for these components once, in Rust. We want to easily re-use these components from all the different languages and on all the different platforms for which we build browsers, which currently includes JavaScript for PCs, Kotlin for Android, and Swift for iOS.

And of course, we want to do this in a way that's convenient, maintainable, and difficult to mess up.

How?

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 #[wasm_bindgen] macros, 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 cdylib crate in Rust; let's say the code is in ./src/lib.rs.
  • Specify the desired component API using an Interface Definition Language (specifically, a variant of WebIDL) in a separate file like ./src/lib.udl.
  • Run uniffi-bindgen scaffolding ./src/lib.udl to generate a bunch of boilerplate rust code that exposes this API as a C-compatible FFI layer.
    • Update ./src/lib.rs to include!() this scaffolding code as part of your crate.
  • cargo build your crate as normal to produce a shared library.
  • Run uniffi-bindgen generate ./src/lib.udl -l kotlin to generate a Kotlin library that can load your shared library and expose it to Kotlin code using your nice high-level component API!
    • Try passing -l swift or -l python to produce bindings for other languages.

For a concrete example, check out ./examples/arithmetic/ for a small but fully-functional crate built in this style.

Why?

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.

Status

This is all very experimental and incomplete, but we do have some basic examples working, implementing functions and datatypes in Rust and manipulating them from Kotlin, Swift, and Python. Take a look in the ./examples/ directory to see them in action.

Component Interface

In addition to writing your component functionality as a rust crate, you will need to provide an abstract description of your component's API using a variant of WebIDL.

This turns out to be a bit of an awkward fit, but good enough for a first version. In the future we may be able to generate the Interface Definition from annotations on the Rust code (in the style of wasm_bindgen or perhaps the cxx crate) rather than from a separate UDL (Uniffi Definition Language) file.

The code for defining a component interface lives in ./uniffi_bindgen/src/interface/mod.rs and is currently the best source of truth for syntax and semantics of the UDL.

Things that are implemented so far:

  • Primitive numeric types, equivalents to those offered by Rust (u32, f64, etc).
  • Strings (which are always UTF-8, like Rust's String).
  • C-style enums (just the discriminant, no associated data).
  • C-style structs containing named fields (we call these records).
  • Sequences of all of the above (like Rust's Vec<T>).
  • Optional instances of all of the above (like Rust's Option<T>).
  • Stand-alone functions.
  • Simple stateful objects with callable methods.
  • Basic error reporting.

Things that are not implemented yet:

  • Enums with associated data.
  • Union types.
  • Efficient access to binary data (like Rust's Vec<u8>).
  • Passing object references to functions or methods.
  • Callbacks

Things that are unlikely to ever be implemented (but I guess you never know..!)

  • Fancy generics.
  • Fancy lifetimes.
  • Closures

Rust Scaffolding

To expose the Rust code to foreign languages, we must first "flatten" it into a C-compatible FFI layer that can be compiled into a dynamic library, then loaded from the foreign language. We call the code for generating this FFI layer the "scaffolding", the code for which lives in ./uniffi_bindgen/src/scaffolding.rs. The current implementation uses askama for templating because it seems to give nice integration with the Rust type system.

Currently, you need to generate the scaffolding code from the UDL file and then include!() it into the lib.rs or your crate. You can generate it by hand using the uniffi_bindgen CLI, like this:

uniffi-bindgen scaffolding ./src/example.udl

Or you can use the generate_scaffolding(udl_file: &str) function in ./uniffi_build/src/lib.rs to do this automatically from your crate's build.rs file.

If the definitions in your UDL file do not match the Rust code you've written for your component, you will get an error when trying to compile the crate. We've made some modest effort to ensure that the compilation errors will help point you in the right direction, but for now, you may have to do a little digging to figure out the source of the mis-match.

Foreign Language Bindings

We support generating code for Kotlin and Swift, as well as some partial support for Python. The generated code works but contains some known inefficiencies, which we'll work on over time. The code for the different foreign languages lives under ./uniffi_bindgen/src/bindings/.

You can generate the bindings from the UDL by using the uniffi_bindgen CLI, like this:

uniffi-bindgen generate src/arithmetic.udl -l kotlin

Or -l swift for swift, or -l python for python.

It's up to you to combine the generated foreign-language code and the compiled rust crate into a suitable format for distribution (e.g. a .jar or android package for Kotlin).

Code of Conduct

Please check the project's code of conduct.

uniffi-rs's People

Contributors

rfk avatar eoger avatar jhugman avatar linabutler avatar leplatrem avatar vladikoff avatar gankra avatar mhammond avatar nnethercote avatar nilslice avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.