Passing mutable objects across ffi and back

#1

Let’s say I have a rust object, and I want to pass ownership of that object outside of rust. I want to then allow the external interface to call back into a rust function that changes the object, and then eventually get back ownership in the rust layer.

I am thinking the following approach:

// this can be called multiple times when the c layer has ownership,
// but never twice at the same time
fn rust_function(ptr: *mut c_void) {
    let rust_object = Box::leak(Box::from_raw(ptr as *mut RustObject));
    // now we can preform operations on rust_object that modify it
}

fn main() {
    let rust_object_ptr = Box::into_raw(Box::new(RustObject::new()));

    // calls c code that will call back into rust using `rust_function`. 
    preform_external_operations(rust_object_ptr as *mut c_void, rust_function);

    // now i have ownership of my rust object back
    let rust_object = Box::from(rust_object_ptr);
}

Looking for clarification if this is sane, and if there might be a better way. Thanks in advance!

0 Likes

#2

Since managing the lifetime of RustObject is fully on Rust side (you never actually give up ownership – your main function is destroying the object, not C code), there’s no need to box anything at all. Also, I think that all pointers (and references) have compatible ABI, so rust_function can just take &mut RustObject.

extern "C" fn rust_function(ptr: &mut RustObject) {
    // now we can preform operations on rust_object that modify it
}

fn main() {
    let mut rust_object = RustObject::new();

    // calls c code that will call back into rust using `rust_function`. 
    preform_external_operations(
        (&mut rust_object) as *mut RustObject as *mut c_void,
        rust_function
    );
}

Please also note that you need extern "C" declaration on all C-callable functions, because there’s no guarantee that rust’s calling convention is the same as C’s.

2 Likes

#3

Thanks, ill try that out.

Please also note that you need extern "C" declaration on all C-callable functions, because there’s no guarantee that rust’s calling convention is the same as C’s.

Yup! I was trying to simplify the example (the library has it set up so that you can pass a safe funtion, and the extern “C” fn calls the safe function) :slight_smile:, thanks though!

0 Likes

#4

This seems to be true only for direct references to objects and not for references to trait objects (since the latter are fat pointers).

0 Likes