c-closures 0.3.0

General purpose way for Rust closures to cross an FFI boundary into C/C++. Use with `c-closures-build`.
Documentation

Purpose

This crate is for producing Rust closures that can cross an FFI boundary with no generic types. It provides support for any single argument signature, along with any return type, assuming both have valid representations in C/C++ and Rust.

Here's an example.

Safety concerns

Creating a Closure by itself can not cause undefined behavior, however the resulting structure is extremely dangerous. The C/C++ code may not validate arguments passed are of the correct type, which could lead to memory corruption and segfaulting. Closure should never be an argument to a safe function, nor should it be a public member of any structures passed into a safe function.

Usage in C/C++

To use this with a C/C++ library you'll need to include the header provided in the repo, rust_closures.h, then link to the assembly produced by rust_closures.c. If the C/C++ code is being linked into a Rust binary depending on this crate, then you don't need to worry about linking to rust_closures.c. Then you can accept the Closure type anywhere that you need to accept arbitrary Rust code.

Limitations

Closure can currently only accept a single argument, this can be worked around by making that argument a C/C++ class/struct containing multiple fields. Additionally it is strongly recommended that all types in the closure signature have a valid representation in C/C++ and Rust. Fat pointers are a common gotcha in this respect, remember slices and string slices are not a single pointer value.

This cannot be used to transfer ownership across FFI boundaries, as this crate cannot reasonably guarantee both sides are using the same memory allocator, or dispose of the types in the same way. If such transfer is required, you should copy the data into a new allocation, on the side of the FFI boundary it needs to live on. The major exception to this is types with the Copy marker trait, which are trivially cloned and require no disposal instructions.

In order to achieve this in such a general manner this crate leans heavily on heap allocations. Arguments, and return types are treated as data of arbitrary unknown length. If such heap allocations are unacceptable for your use case, consider authoring a similar structure with specific known types and involving no indirection.