Unconvenient listener API
I've started adding support for proxies in my wip branch. While doing so I'm hitting limitation of the current closures-based listener API.
See this FIXME. In order for the callbacks to be called, we need to ensure that the NodeListener
stays alive. This is tricky for two reasons:
-
NodeListener
's lifetime is bound to theProxyNode
object, so we need to ensure thatnode
stay alive as well. It's always tricky in Rust to store an object and a borrow on it all together; see for example all the magic rental has to do to implement such pattern. - The listener closures are
Fn
and notFnMut
(because the underlying C callbacks may be reentrant), so the closure cannot mutably borrow a container, say aVec
, who would hold the objects to keep them alive.
The first issue can addressed in two ways:
-
NodeListener
could ensureProxyNode
stays alive be keeping a strong ref on hit rather than a borrow. A bit like we did forContext
which keeps a ref onLoop
now. - We could remove the
NodeListener::Drop
implementation so dropping a listener would no longer automatically destroy thespa_hook
, disconnecting the callback. Instead we could have an explicitdisconnect
API onNode
orNodeListener
to remove it. The hook would also be destroyed whenNode
is drop.
The second issue can be workaround by wrapping the objects container with a RefCell
but that makes things harder for the users.
Or maybe we should stop using closures at all? We could for example require user to pass an object implementing a specific trait when registering and call those methods as callbacks. Didn't give this a try yet so maybe it won't actually solve all those issues.
So different options to consider. Ideally I'd like to use the same pattern for all the listener APIs so it would be good to have a generic solution.
@ryuukyu : what do you think about all this?
@slomo : we already discussed some of this a few weeks ago, so if you have any advice it's very welcome as usual. :)