Rust's Great Interoperability

0: Rust on 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 all modern languages.

What's the advantage of Rust for this purpose over, say, C or C++?

  1. C - An oldie and a goldie, C allows almost any language out there to bind to it. The problem is C has no real package manager (outside of maybe clib), and many programmers prefer more feature-full, quickly incremented languages these days.
  2. C++ - The LAH of programming languages, C++ is fast and efficient, if not a little violent. The problem is C++ has almost-nonexistent support for bindings.
  3. Rust - Though it's a newbie, Rust is hella fast, beautiful, and loved by developers. It rivals C/C++ in almost every way; most importantly for this discussion, it has a C ABI, meaning it can be called from every language that can also call C.

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 efficient and easily integrable with applications written in other languages.

1: Creating an App

Much of the work I do is done in Crystal, a compiled language with Ruby-like syntax. Crystal allows me prototype applications and write scripts very quickly, just like Ruby or Bash, while being extremely fast. There are some applications (read: APIs) that would be better written in another language (read: Rust), but that I want to interface with apps written 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}!"

Luckily, this is only 3 lines of Rust.

400: Invalid request

But this function, as is, cannot be read by other languages when compiled. For that, the function must be extended with a C interface, which requires the libc crate.

All that must be done is to include libc, create an function definition along the C ABI, and wrap the function with C types.

Observe that a c_char pointer is used for passing strings - this is because Rust strings are different from those of other languages.

400: Invalid request

In Cargo.toml, specify the build to be a dynamic library so it can be accessed by other processes.

400: Invalid request

And now,

2: Bind the Library

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

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

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

400: Invalid request

And compile to print “Hello, world!”.

Analytics By visiting this site, you agree to its use of Cloudflare Analytics. No identifiable information is transmitted to Cloudflare. See Cloudflare Analytics user privacy.