Rust's Great Interoperability

February 7, 2018

0: Rust (with the) Rocks

You can find a lot of discussions online on why Rust is great - it’s beautiful, memory safe, and faster than the Tesla Roadster Remember when Elon launched his into space? - but perhaps my favorite thing about Rust is its fantastic FFI, which allows for interoperability with almost any modern language.

But so do C/C++!

Do they? Let’s quickly examine these Big ThreeNo, not the law :

  1. C - An oldie and a goldie, C allows for native bindings to almost any language that is out there. The problem is C has no real package manager (outside of maybe clib), and few programmers want to write C for production-level code these days.
  2. C++ - The LAH of programming languages, C++ is fast and efficient even if a little violent. The problem is C++ has almost-nonexistent support for bindings.
  3. Rust - One of the newest players to the game, Rust is hella fast, beautiful, and loved by most. Its community is growing quickly, and the memory safety and zero-cost abstractions it provides are favorable for building powerful applications quickly. Best of all, it has a C ABI, which means it can bound to almost every modern language out there.

So yeah, maybe I’m just really edgy and want to do the cool new thing, but Rust is a great option for developing safe applications that need to be really efficient and easily integrable with applications in other languages.

1: Creating an App

Much of the work I do is done in Crystal, a compiled Ruby-like language. Crystal allows me prototype applications and write scripts very quickly, just like Ruby or Bash, and comes with the added benefit of being extremely fast. There are some applications (read: APIs) that would be better written in another language (read: Rust), but that I still want to use with Crystal. And so, bindings come into play For Python, Ruby, and JavaScript (Node), Rust’s FFI is cleanly outlined. For Crystal it is not, but I was able to figure it out even without any documentation, so the process I describe is probably similar for other languages you would like to integrate with Rust. .

Imagine we want to create a variable greeting function,

hello(name) -> "Hello, #{name}!"

This is a fairly trivial thing to do; in fact, it’s only 3 lines of Rust.

But this function, as is, cannot be read by other languages when compiled. To do that, this function must be extended with a C interface, which requires the libc crateAll that must be done is to include libc, create an unmangled C ABI function definition, and wrap the function around C types. Observe that a c_char pointer is used for strings - this is because only Rust can interpret Rust Strings. .

There is a minor adjustment to be made to Cargo.toml as well - the crate being built must be a dynamic library so that it can be accessed by other processes.

And now,

2: Bind the Library

Crystal allows linking to C functions and types via a lib declaration. As mentioned, Rust supports the C ABI, we can also link Rust functions!

Suppose that our builds a dylib to target/release/hello.dylib, relative to the current path. Then we can bind the library in four lines:

Note that must be used to build the char pointer returned by LibHello.hello

And compile to print “Hello, world!”.

<< All Posts :squid: