Expand description
§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.
§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.
Macros§
- rebind_
closure - Rebinds a
Closure
from this crate to aClosure
type defined externally. If you use bindgen to make bindings to C/C++ functions accepting thisClosure
type then the bindings won’t be defined in terms ofc_closures
, instead your functions will want an instance of your ownClosure
definition. This macro provides a convenient way to rebind them.
Structs§
- Closure
- A general purpose closure type defined in C code which can be created in Rust.
Traits§
- Closure
Marker Trait - This trait identifies instances of the
Closure
type fromrust_closures.h
. In Rust land, there will be multiple instances of this type that we need to be able to cast from one to another. This trait helps us determine which of these casts are safe. To implement this useBindgenBuilderExt::c_closures_enhancements
fromc-closures-build
on yourbindgen::Builder
. - From
Closure ArgPointer - Provides a general purpose way to deref a structure from a C void pointer. Auto implemented for
Copy
types.
Functions§
- closure_
call ⚠ - Calls the inner code. The return value of this may have come from
Rust, meaning you can not free it. However it must be freed. When
you’re done with the return value, pass it back to Rust with
closure_release_return_value
so that the memory isn’t leaked. If you won’t be using the return value, instead callclosure_call_with_no_return
. - closure_
call_ ⚠with_ no_ return - Calls the inner code and cleans up the returned value, if any.
- closure_
release ⚠ - Release data associated with this closure, must be called when done with Closure to avoid memory leaking.
- closure_
release_ ⚠return_ value - Cleans up the value returned by calling this Closure. Do not attempt to free the returned pointer yourself.