Last active
January 5, 2018 18:51
-
-
Save SpaceManiac/62b88ad266c9264f4dcf362a98033e18 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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..