Poperton
Poperton

Reputation: 2127

How can I pass a pointer to itself to C++ so it can perform a callback?

I've defined a way to pass my Rust object to C++ so it can call this Rust object back:

extern "C" {
    pub fn zlmedia_set_parent(zl_media: *mut ZLInstance, parent: Box<ZLMedia>);
}

pub fn new_boxed(url: &str) -> Box<ZLMedia> {
    let c_url = CString::new(url).expect("CString::new failed");
    let p = Box::new(ZLMedia {
        zl_media: unsafe { zlmedia_new(c_url.into_raw()) },
        url: url.to_string(),
    });
    unsafe {
        zlmedia_set_parent(p.as_ref().zl_media, p);
    }
    p
}

The problem is that I can't pass the Box to C++ because I move it here:

unsafe {
    zlmedia_set_parent(p.as_ref().zl_media, p);
}

How can I pass a Box to itself to C++ and still return it in the new? I don't really need to move it, because it goes to a C++ function.

Upvotes: 4

Views: 236

Answers (1)

Peter Hall
Peter Hall

Reputation: 58695

If you want the ZLMedia to be owned by the Rust code then you can pass a pointer to it rather then the box itself.

use std::borrow::Borrow as _;

extern "C" {
     pub fn zlmedia_set_parent(zl_media: *mut ZLInstance, parent: *const ZLMedia);
}

pub fn new_boxed(url: &str) -> Box<ZLMedia> {
    let c_url = CString::new(url).expect("CString::new failed");
    let p = Box::new(ZLMedia {
        zl_media: unsafe { zlmedia_new(c_url.into_raw()) },
        url: url.to_string(),
    });
    unsafe {
        zlmedia_set_parent(p.as_ref().zl_media, p.borrow() as *const ZLMedia);
    }
    p
}

If the C++ code dereferences the pointer after the box is dropped, it will trigger Undefined Behaviour. If the C++ code tries to free the pointer then it's also UB. It's up to you to make sure that these things don't happen.

Upvotes: 1

Related Questions