let's make a rust wrapper library and a C header for my normal "inner" rust library, so that my C program can take advantage of rust's standard library.
For example, if we have normal rust function:
pub fn kork(zork: u64) -> bool
Then we would generate this Rust wrapper library code:
#[no_mangle] pub extern "C" fn kork_extern(zork: u64) -> bool { inner_lib::kork(zork) }
However, when structs and enums get involved, there's a twist: C should only see sized, opaque structs for those. Let's assume that C can know the size of Rust structs via preprocessor #define's handed in via command line.
For example, this function:
struct MyRustStruct {
// Arbitrary fields here
}
pub fn bork(splork_raw: MyRustStruct) -> MyRustStruct
would have a rust wrapper like this:
#[repr(C)]
pub struct MyRustStruct_extern([u8; std::mem::size_of::<MyStruct>()]);
#[no_mangle]
pub extern "C" fn bork_extern(
splork_raw: *const MyRustStruct_extern,
result_raw: *mut MyRustStruct_extern) {
let splork_ref: &MyRustStruct = &*(splork_raw as *const MyRustStruct);
let result_struct = bork(*splork_ref);
(result_raw as *mut MyRustStruct).write(result_struct);
}
and a C header file like this:
#ifndef RUST_WRAPPER_H
#define RUST_WRAPPER_H
#pragma pack(1)
#include <stdint.h>
// MyRustStruct_extern_SIZE must be handed in via command line
#ifndef MyRustStruct_extern_SIZE
#error "MyRustStruct_extern_SIZE must be defined"
#endif
typedef struct {
uint8_t data[MyRustStruct_extern_SIZE];
} MyRustStruct_extern;
void bork_extern(
MyRustStruct_extern* splork_raw,
MyRustStruct_extern* result_raw);
#endif /* RUST_WRAPPER_H */
Now another example:
pub fn bloop(path: &Path) -> Vec<u8>
The Rust wrapper code would look like:
#[repr(C)]
pub struct Path_extern([u8; std::mem::size_of::<Path>()]);
#[repr(C)]
pub struct VecU8_extern([u8; std::mem::size_of::<Vec<u8>>()]);
#[no_mangle]
pub extern "C" fn bloop_extern(
path_raw: *const Path_extern,
result_raw: *mut VecU8_extern) {
let path_ref: &Path = &*(path_raw as *const Path);
let result_struct = bloop(*path_ref);
let result_ptr: *mut VecU8_extern = result_raw as *mut VecU8_extern;
result_ptr.write(result_struct);
}
and the C header would look like this:
#ifndef RUST_WRAPPER_H
#define RUST_WRAPPER_H
#pragma pack(1)
#include <stdint.h>
// Path_extern_SIZE must be handed in via command line
#ifndef Path_extern_SIZE
#error "Path_extern_SIZE must be defined"
#endif
typedef struct {
uint8_t data[Path_extern_SIZE];
} Path_extern;
// VecU8_extern_SIZE must be handed in via command line
#ifndef VecU8_extern_SIZE
#error "VecU8_extern_SIZE must be defined"
#endif
typedef struct {
uint8_t data[VecU8_extern_SIZE];
} VecU8_extern;
void bloop_extern(
Path_extern* splork_raw,
VecU8_extern* result_raw);
#endif /* RUST_WRAPPER_H */