aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/event_dispatcher
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/event_dispatcher')
-rw-r--r--crates/shirabe/src/event_dispatcher/event_dispatcher.rs39
1 files changed, 20 insertions, 19 deletions
diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
index 2a25eac8..80131e25 100644
--- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
+++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs
@@ -1205,25 +1205,21 @@ try {{
.push(listener);
}
- pub fn remove_listener(&mut self, listener: &Callable) {
- for (_event_name, priorities) in self.listeners.iter_mut() {
- for (_priority, listeners) in priorities.iter_mut() {
- let mut to_remove: Vec<usize> = Vec::new();
- for (index, candidate) in listeners.iter().enumerate() {
- let same = match (listener, candidate) {
- (Callable::String(a), Callable::String(b)) => a == b,
- // TODO(plugin): array callable identity (compare object refs)
- _ => false,
- };
- let array_obj_match = matches!(candidate, Callable::ArrayCallable(_, _))
- && matches!(listener, Callable::ArrayCallable(_, _));
- if same || array_obj_match {
- to_remove.push(index);
- }
- }
- for idx in to_remove.into_iter().rev() {
- listeners.remove(idx);
- }
+ /// PHP's parameter is `callable|object`; every caller in Composer and its test suite
+ /// passes an object, and no `Callable` shape holds a bare object, so the parameter is
+ /// narrowed to the object's cross-RPC identity (its P-table handle). Of PHP's two match
+ /// conditions only `$candidate[0] === $listener` can fire for an object listener; it maps
+ /// to phandle equality on `Callable::PhpMethod`.
+ pub fn remove_listener(&mut self, listener: &shirabe_php_rpc::PhpObjHandle) {
+ for priorities in self.listeners.values_mut() {
+ for listeners in priorities.values_mut() {
+ // TODO(plugin): an `ArrayCallable`'s object half is a `PhpMixed` without
+ // cross-RPC identity, so `$candidate[0] === $listener` is undecidable for it;
+ // only `PhpMethod` candidates are compared.
+ listeners.retain(|candidate| match candidate {
+ Callable::PhpMethod(handle, _) => handle.phandle != listener.phandle,
+ _ => true,
+ });
}
}
}
@@ -1791,6 +1787,7 @@ pub trait EventDispatcherInterface: std::fmt::Debug {
) -> anyhow::Result<i64>;
fn add_listener(&mut self, event_name: &str, listener: Callable, priority: i64);
fn add_subscriber(&mut self, subscriber: &dyn EventSubscriberInterface) -> anyhow::Result<()>;
+ fn remove_listener(&mut self, listener: &shirabe_php_rpc::PhpObjHandle);
fn has_event_listeners(&mut self, event: &dyn EventInterface) -> bool;
}
@@ -1831,6 +1828,10 @@ impl EventDispatcherInterface for EventDispatcher {
self.add_subscriber(subscriber)
}
+ fn remove_listener(&mut self, listener: &shirabe_php_rpc::PhpObjHandle) {
+ self.remove_listener(listener);
+ }
+
fn has_event_listeners(&mut self, event: &dyn EventInterface) -> bool {
self.has_event_listeners(event)
}