[x-post] How do I integrate Rust into other projects?


#1

Someone recently posted a pretty interesting question on Reddit so I thought I’d post it here as well to get the most answers.

Rust is already able to interoperate with other languages quite well by exposing/consuming a C interface, however other than a (fairly detailed) page in The Book there aren’t many resources available on integrating Rust into a multilingual project.

For example, if a company wanted to integrate a Rust module into its product, what kinds of things would it need to know? Are there any guides on doing this? Are there any best practices to know, and how do I handle errors ergonomically?

It would be really cool if there were a Rust FFI book in a similar vein to Learning Rust With Entirely Too Many Linked Lists that could walk you through an example from start to end and answer some of those questions, explaining the thought process going on behind the scenes.

Adding to the questions posed by the OP, what extra resources/documentation/tools are needed to help make it easy to use Rust alongside other projects? And how could I add to or update my FFI Guide to help address these issues?

I quite like the idea of stepping someone through the entire process of integrating a Rust module into a multilingual project from the very beginning, but can’t think of any non-trivial or contrived projects. Sadly I can’t use anything from work because of IP and copyright reasons.


#2

For me the key things needed are:

  • How to produce a shared library from Cargo (there are other ways, but I wouldn’t recommend them. This one is simplest and gives full power of Rust).
  • Box::from_raw/Box::into_raw, ptr.as_ref() and ref as *const _, slice::from_raw_parts
  • Various conversions between C strings and Rust strings and paths. There arer confusingly many combinations of these types, each taking slightly different from* or new method, and there’s awful pitfall of temporary CStr::as_ptr().
  • bindgen
  • build.rs, *-sys crates, cc, pkg-config crates

#3

I spent an embarrassingly large amount of time just trying to pass strings (representing filenames) from another language into Rust. Apparently what the winapi calls “unicode” strings is actually UTF-16 and the best way for managing strings is to accept a pointer into some buffer of u16 (i.e. the UTF-16 string), then use String::from_utf16() to create your own copy to do whatever with.

On the flip side, working with arrays of primitives and arrays of POD types (roughly speaking, Copy types) is surprisingly pleasant. You just accept a pointer to the first element and its length then construct a slice using slice::from_raw_parts() and the borrow checker does the rest :slight_smile:


#4

I just created a new issue for my FFI guide, with the goal of transforming it from a collection of useful tips into more of an extended tutorial style (kinda like @Gankro’s excellent linked lists tutorial). In this case, it could take the form of a REST client (probably a C++/Qt GUI) which uses something like reqwest under the hood.

If people have anything in particular they’d like me to explore then let me know in the issue. I’d particularly like to hear from the docs team because creating a better FFI story would really lower the barrier to entry for established companies.

https://github.com/Michael-F-Bryan/rust-ffi-guide/issues/40


#5

Apparently what the winapi calls “unicode” strings is actually UTF-16

If only it were that simple… winapi strings are not even valid UTF-16!

The standard library has functions for dealing with Windows’ unfortunate encoding, which you can read about here. That is a link to the nightly documentation because it appears that the module docstring was only just recently added about a month ago, even though the module itself has been there since 1.0.