Skip to content

Instantly share code, notes, and snippets.

@SpaceManiac
Last active January 5, 2018 18:51
Show Gist options
  • Save SpaceManiac/62b88ad266c9264f4dcf362a98033e18 to your computer and use it in GitHub Desktop.
Save SpaceManiac/62b88ad266c9264f4dcf362a98033e18 to your computer and use it in GitHub Desktop.
#![allow(non_camel_case_types)]
use std::mem;
// The Situation
struct ffi_Object;
type ffi_Callback = unsafe extern fn(*mut ffi_Object) -> u32;
extern fn ffi_push_callback(_: *mut ffi_Object, _: ffi_Callback) {}
// Dummy wrapper
struct Object {
ptr: *mut ffi_Object
}
impl Object {
fn new() -> Object {
// initialize ffi_Object here
Object { ptr: std::ptr::null_mut() }
}
fn from_ptr(ptr: *mut ffi_Object) -> Object {
Object { ptr: ptr }
}
fn push_callback(&mut self, cb: ffi_Callback) {
ffi_push_callback(self.ptr, cb);
}
}
impl Drop for Object {
fn drop(&mut self) {
// destroy ffi_Object here
}
}
// The Solution
fn wrap_callback<F: Fn(&mut Object) -> u32>(_: F) -> ffi_Callback {
assert!(mem::size_of::<F>() == 0);
unsafe extern fn wrapped<F: Fn(&mut Object) -> u32>(ptr: *mut ffi_Object) -> u32 {
let mut object = Object::from_ptr(ptr);
let result = mem::transmute::<_, &F>(&())(&mut object);
mem::forget(object);
result
}
wrapped::<F>
}
// Usage
fn our_callback(_: &mut Object) -> u32 {
0
}
fn main() {
let mut object = Object::new();
let wrapped: ffi_Callback = wrap_callback(our_callback);
object.push_callback(wrapped);
}
@evilactually
Copy link

hmm... what's the point, ffi already takes an object and still takes same object after you wrapped it. I thought this is about associating arbitrary user data with callbacks that take none... actually this is possible in Haskell because it can generate temporary dispatch addresses for closures and you can capture whatever user state you want in there... I guess internally it creates a kind of a jump table, not a system programming language huh? But I forget details, just remember I had to release these pointers, otherwise it get all leaky..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment