Skip to content

Instantly share code, notes, and snippets.

@ssrlive
Last active April 25, 2023 08:50
Show Gist options
  • Save ssrlive/7f2ae64fa2b614fa5aa17fb48d85f86d to your computer and use it in GitHub Desktop.
Save ssrlive/7f2ae64fa2b614fa5aa17fb48d85f86d to your computer and use it in GitHub Desktop.
Rust FFI for C style callback
use std::{ffi::c_void, marker::PhantomData};

struct CBProxy<F, Sig>(PhantomData<(F, Sig)>);

impl<F, A1, A2, R> CBProxy<F, fn(A1, A2) -> R>
where
    F: FnMut(A1, A2) -> R,
{
    unsafe extern "C" fn cb(vp: *mut c_void, a1: A1, a2: A2) -> R {
        let fp = vp as *mut F;
        let f = &mut *fp;
        f(a1, a2)
    }
}

pub(crate) trait MakeCVoidCB<CF> {
    fn get_c_void_cb(&mut self) -> CF;
}

impl<F, A1, A2, R> MakeCVoidCB<unsafe extern "C" fn(*mut c_void, A1, A2) -> R> for F
where
    F: FnMut(A1, A2) -> R,
{
    fn get_c_void_cb(&mut self) -> unsafe extern "C" fn(*mut c_void, A1, A2) -> R {
        CBProxy::<F, fn(A1, A2) -> R>::cb
    }
}


let mut cb = |a, b| {todo!()};
let cbmp = &mut cb;
let ccb = cbmp.get_c_void_cb();
let cbvp = cbmp as *mut _ as *mut c_void;
let ret = f(self, cbvp, ccb);

另一个参考链接: https://gist.github.com/XeCycle/beeb34e9e1539cc314fbec04a3fbeaa8

use std::ffi::c_void;

struct CCb(unsafe extern "C" fn(i32, *mut c_void), *mut c_void);

impl CCb {
    unsafe fn call(self, arg: i32) {
        self.0(arg, self.1)
    }
}

#[no_mangle]
extern "C" fn test_rs_lib(cb: unsafe extern "C" fn(i32, *mut c_void), ctx: *mut c_void) {
    let ccb = CCb(cb, ctx);
    unsafe {
        ccb.call(42);
    }
}

test.c

#include <stdio.h>

void test_rs_lib(void (*cb)(int, void*), void*);

void my_cb(int a, void* ctx)
{
  *((int*)ctx) = a;
}

int main()
{
  int saved = 0;
  test_rs_lib(&my_cb, &saved);
  printf("%d\n", saved);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment