If a library requires that I give it ownership of a listener object that it later calls methods on, how do I best still retrieve what the listener receives from the library in my own code?

In Rust's Box2D bindings, the world struct has the following function:

pub fn set_contact_listener<L: ContactListener<U>>(&mut self, listener: Box<L>)

And then when bodies collide during the step function, methods like begin_contact will be called on the listener with information about the bodies that collided.

I would like to collect this information somewhere, but I'm not sure how to approach that. I can't just put it in a field of the struct I'm implementing ContactListener for, since I won't be able to read it after I call set_contact_listener as that will take ownership of the listener object.

One way I can think of is to give my ContactListener struct an Rc<RefCell<Vec<Contact>>> field which it would then push contact info on, and my code could own the other end and read the messages. But this seems like quite an inelegant solution: it's weird to imagine that the library authors really meant for it to be used in that way. If Rc<RefCell> was necessary, it would at least make sense to put it in the interface up-front.

Rc<RefCell<Thing>> is the safe single-threaded version of C's Thing *: the reference-counting guarantees that Thing is not dropped (preventing the UAF), and the RefCell prevents re-entrancy bugs such as iterator invalidation (and if it were Arc<RwLock<...>>, it would guarantee that it be multithread-safe).

Given the API of Box2D, it seems that in C, keeping track of .begin_contact() calls requires using something like a Thing * out-pointer. That's why in Rust, even if it is not pretty, it will be hard to come up with a 100% safe alternative to reference-counting + interior mutability.

1 Like