(L2.1) Automatic conversion and interfaces

While Rust may be rapidly gaining popularity, many code bases are still primarily written in C. It is therefore important to make sure Rust is as painless as possible to introduce into an existing C code base. The foreign function interface options provided by Rust make communicating between C and Rust easier. If you want to translate C code to Rust, you can use C2Rust to speed this process along.

Automatic Conversions

Automatic conversion from C to Rust is possible, if not yet perfected. The current state-of-the art tool is C2Rust. More Information about the automatic conversion from C to Rust can be found in the presentation on Migrating From Unsafe Languages to Rust.

Interfaces

To call Rust from C or C from Rust, all you need are the correct bindings of the desired functions. Such bindings are simply the function headers expressed in the language you want to call them from. When a Rust binding of a C function is desired, one must create a Rust binding from a C header. For example, the C function header below:

void function(int i);

The following binding is needed to call the function from Rust:

#![allow(unused)]
fn main() {
extern "C" {
    pub fn function(i: ::std::os::raw::c_int);
}
}

Rust provides types that are identical to C types in the standard library to make interoperability between C and Rust easier. To create a Rust binding that represents a C function, it is necessary to add extern "C" to let the Rust compiler know you will be linking to external code. Bindings can not only be made for functions but also for structs. In the case of structs, it is important to add #[repr(C)] as it makes sure the alignment, size, and order of fields are the same as in C.

When creating a C binding from Rust code, you need to add some information to the Rust function. The compiler needs to be told not to mangle the function name, so the attribute #[no_mangle] must be added. The keyword extern "C" must be added to the function header to make sure that this function can be correctly used by a C program.

#![allow(unused)]
fn main() {
#[no_mangle]
pub extern "C" fn function(i: i32);
}

The following binding is needed to call the function from C:

void function(int i);

Creating bindings for your interfaces so C and Rust can talk to each other is banal work and can be done in an automated fashion. Bindgen was introduced to create Rust bindings from your C code. All you have to do to create such a binding is provide a C header file that contains all that should be callable from Rust code. Creating C bindings from Rust can also be automated with the tool cbindgen. Cbindgen needs some more help than bindgen, some configuration information must be provided. This can either be achieved by adding a cbindgen.toml file, or by adding a build.rs file (which is a Rust build script) with a cbingen builder. The documentation offers examples of configuration options.