Skip to content

Instantly share code, notes, and snippets.

@gliheng
Created November 26, 2018 07:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gliheng/86bbcc1254e7e192eecc09b825a1534e to your computer and use it in GitHub Desktop.
Save gliheng/86bbcc1254e7e192eecc09b825a1534e to your computer and use it in GitHub Desktop.
Rust ffi with C
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
void hello()
{
printf("Hello world!\n");
}
int add(int i) {
return i + 1;
}
typedef bool (*BoolCallback)(void* /* user data */);
typedef (*VoidCallback)();
void pass_bool_cbk(BoolCallback cbk) {
printf("BoolCallback called: %d\n", cbk((void*)0));
}
void pass_void_cbk(VoidCallback cbk) {
printf("VoidCallback called\n", cbk());
}
void pass_string(char* s) {
printf("C got string %s\n", s);
}
typedef struct {
char* name;
BoolCallback cbk;
} NamedCallback;
void pass_struct(NamedCallback* st) {
printf("Got struct named: %s\n", st->name);
printf("Call it: %d\n", st->cbk((void*)0));
}
typedef struct {
char* name;
union {
unsigned int health;
};
unsigned int age;
} Warrior;
void pass_struct_with_union(Warrior* st) {
printf("Got warriro named: %s with level %d age %d\n", st->name, st->health, st->age);
}
extern crate libc;
use libc::{c_int, c_void, c_char};
use std::ffi::CString;
use std::cell::RefCell;
use std::ptr::{null_mut};
type BoolCallback = extern fn(*const c_void) -> bool;
type VoidCallback = extern fn();
#[link(name="hello")]
extern {
fn hello();
fn add(n: c_int) -> c_int;
fn pass_string(s: *const c_char);
fn pass_bool_cbk(f: BoolCallback);
fn pass_void_cbk(f: VoidCallback);
fn pass_struct(st: *const NamedCallback);
fn pass_struct_with_union(st: *const Warrior);
}
#[repr(C)]
struct NamedCallback {
name: *const c_char,
callback: BoolCallback,
}
extern fn bool_callback(_: *const c_void) -> bool {
true
}
#[repr(C)]
struct Warrior {
name: *const c_char,
level: u32,
age: u32,
}
thread_local!(static CALLBACK: RefCell<*mut c_void> = RefCell::new(null_mut()));
extern "C" fn wrapper<F>()
where F: FnMut()
{
CALLBACK.with(|z| {
let closure = *z.borrow_mut() as *mut F;
unsafe {
(*closure)();
}
});
}
fn pass_cbk_closure<F>(callback: F)
where F: FnMut() {
CALLBACK.with(|log| { *log.borrow_mut() = &callback as *const _ as *mut c_void; });
unsafe {
pass_void_cbk(wrapper::<F>);
}
}
fn main() {
unsafe {
hello();
println!("add result {}", add(3));
pass_string(CString::new("wtf").unwrap().into_raw());
pass_bool_cbk(bool_callback);
pass_cbk_closure(|| {
println!("Void callback into rust");
});
// This does not work
// call_cbk(Box::new(||false));
let st = NamedCallback{
name: CString::new("biubiu").unwrap().into_raw(),
callback: bool_callback,
};
pass_struct(&st);
let st = Warrior {
name: CString::new("Hanzo").unwrap().into_raw(),
level: 99,
age: 33,
};
pass_struct_with_union(&st);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment