/seabridge

Experimental Rust-to-C++ binding generator, using Rust compiler APIs to ensure accurate and stable translation.

Primary LanguageRustMIT LicenseMIT

seabridge(siː brɪʤ) - next-gen tool for easy Rust / C++ interop

WARNING: This tool is in early research phase. It paritaly works, but it has some very rough edges and is nothing more than a tech demo ATM.

Since it is so early in developement, this README may not be up to date and is likelly riddled with spelling/other mistakes. Sorry. While I try to be clear about what is implemented and planned, it is important to note that many features are still quite buggy.

Seabridge is an experimental tool, which uses rich type information from the rust compiler to generate high-quality C++ bindings to Rust code.

Thanks to this unqiue, deep access to the internal state of the compiler, sebaridge can generate C++ bindings to all Rust types(DONE, bit buggy), functions(WIP, demangled + generic support + shims, still bit buggy and limited), and statics(WIP, no demangling yet).

This(in theory) will allow you to just use a Rust crate inside a C++ codebase, without much setup. The tool is also able to translate high level Rust concepts, like generics, into C++ equivalents(templates).

For most scenarios, you will not need to write any glue code(generics may require a bit of setup in some cases).

Solving ABI instability

Solving the quiestion of unstable layout:

In most case, the unstable layout of Rust types makes it impossible to generate stable and usable bindings to types not marked with #[repr(C)]. However, since seabridge uses the same layout calculations used by the corresponding version of the Rust compiler, the bindings it genrates match with the Rust layout of types.

As long as the bindings are generated for the right target, and the C++ code is recompiled when the Rust code / bindings change, seabridge can guarantee the memory layout of types on both side matches.

// Translated Box<i32> defintion, generated by seabridge
namespace alloc::boxed {
  // Generics translated into templates with specialization,
  // Aligement preserved using atributes.
  template < > struct __attribute__((aligned(8)))
  Box < int32_t, ::alloc::alloc::Global > {
    ::core::ptr::unique::Unique < int32_t > f0;
  };
}

However, this approach also comes with some limitations regarding generics. Rust generics must be instantiated(used) on the Rust side, since they will not get exported otherwise.

In practice, this is almost never a problem, since you will almost never use a Rust generic only on the C++ side. All generics used within function signatures / statics, and types used within those types will get exported correctly.

Keeping up with the everchanging ABI:

TODO: write about translating Rust ABI to C(implemented, but limited/flawed(unhandled egde cases) approach), and about generating C-to-Rust shims(WIP, should be rock-solid in theory).

High level translation

The ultimate goal of Seabridge is allowing you to forget that the code you are using was originaly written in Rust.

Seabrdige translates Rust generics into C++ templates(with some limitations), allowing you to use generic Rust types form C++:

#[no_mangle]
fn my_fn(args:(i32,f64,&[u8]))->Box<i32>{
	eprintln!("Recived args:{args:?}");
	Box::new(args.0)
}
#include <mycrate/includes/mycrate.hpp>
int main() {
	uint8_t* slice_content = (uint8_t*)"Hi Bob";
	// Create Rust slice
	RustSlice<uint8_t> slice;
	slice.ptr = slice_content;
	slice.len = 6;
	// Create Rust tuple
	RustTuple<int32_t,double,RustSlice> args = {8,3.14159,slice};
	// Just call a Rust function
	alloc::boxed::Box<int32_t> rust_box = my_crate::my_fn(args);

}

Seabridge will also(in the future!) translate Drop impls into C++ destructors.

LICENSE

Parts of Seabrdige's code come from rustc_codegen_clr, and, as such, it is licensed under the same license as it and the Rust compiler: MIT or Apache.