diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-09 00:09:08 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-09 00:09:20 +0900 |
| commit | 436e12381dd79e419dce755718be17b66d73e17f (patch) | |
| tree | 09dc809c64efe407b4049695341519ce26c411b3 /crates/shirabe/src/event_dispatcher | |
| parent | 1c0eb589741de4aa52ef941ff9315b34dbe48aa0 (diff) | |
| download | php-shirabe-436e12381dd79e419dce755718be17b66d73e17f.tar.gz php-shirabe-436e12381dd79e419dce755718be17b66d73e17f.tar.zst php-shirabe-436e12381dd79e419dce755718be17b66d73e17f.zip | |
feat(event-dispatcher): unify event dispatch via EventInterface trait
Extract a superclass-trait EventInterface from the base Event.
pool_builder's PrePoolCreateEvent stays deferred: its constructor needs
owned, non-cloneable Request and repository boxes the builder only holds
by reference (owned-payload blocker). The event is plugin-only, so its
construction is re-tagged TODO(plugin).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/event_dispatcher')
| -rw-r--r-- | crates/shirabe/src/event_dispatcher/event.rs | 34 | ||||
| -rw-r--r-- | crates/shirabe/src/event_dispatcher/event_dispatcher.rs | 112 |
2 files changed, 68 insertions, 78 deletions
diff --git a/crates/shirabe/src/event_dispatcher/event.rs b/crates/shirabe/src/event_dispatcher/event.rs index 81ab921..f04839f 100644 --- a/crates/shirabe/src/event_dispatcher/event.rs +++ b/crates/shirabe/src/event_dispatcher/event.rs @@ -21,6 +21,10 @@ impl Event { } } + pub fn from_name(name: String) -> Self { + Event::new(name, Vec::new(), IndexMap::new()) + } + pub fn get_name(&self) -> &str { &self.name } @@ -41,3 +45,33 @@ impl Event { self.propagation_stopped = true; } } + +pub trait EventInterface: std::fmt::Debug { + fn get_name(&self) -> &str; + fn get_arguments(&self) -> &Vec<String>; + fn get_flags(&self) -> &IndexMap<String, PhpMixed>; + fn is_propagation_stopped(&self) -> bool; + fn stop_propagation(&mut self); +} + +impl EventInterface for Event { + fn get_name(&self) -> &str { + &self.name + } + + fn get_arguments(&self) -> &Vec<String> { + &self.args + } + + fn get_flags(&self) -> &IndexMap<String, PhpMixed> { + &self.flags + } + + fn is_propagation_stopped(&self) -> bool { + self.propagation_stopped + } + + fn stop_propagation(&mut self) { + self.propagation_stopped = true; + } +} diff --git a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs index affecdd..a9da6e8 100644 --- a/crates/shirabe/src/event_dispatcher/event_dispatcher.rs +++ b/crates/shirabe/src/event_dispatcher/event_dispatcher.rs @@ -24,6 +24,7 @@ use crate::composer::PartialComposerWeakHandle; use crate::dependency_resolver::Transaction; use crate::dependency_resolver::operation::OperationInterface; use crate::event_dispatcher::Event; +use crate::event_dispatcher::EventInterface; use crate::event_dispatcher::EventSubscriberInterface; use crate::event_dispatcher::ScriptExecutionException; use crate::installer::BinaryInstaller; @@ -118,9 +119,9 @@ impl EventDispatcher { pub fn dispatch( &mut self, event_name: Option<&str>, - event: Option<Event>, + event: Option<&mut dyn EventInterface>, ) -> anyhow::Result<i64> { - let event = match event { + match event { None => { let name = event_name.ok_or_else(|| { anyhow::anyhow!(InvalidArgumentException { @@ -130,12 +131,11 @@ impl EventDispatcher { code: 0, }) })?; - Event::new(name.to_string(), Vec::new(), IndexMap::new()) + let mut event = Event::new(name.to_string(), Vec::new(), IndexMap::new()); + self.do_dispatch(&mut event) } - Some(e) => e, - }; - - self.do_dispatch(event) + Some(event) => self.do_dispatch(event), + } } /// Dispatch a script event. @@ -216,7 +216,7 @@ impl EventDispatcher { } /// Triggers the listeners of an event. - fn do_dispatch(&mut self, event: Event) -> anyhow::Result<i64> { + fn do_dispatch(&mut self, event: &mut dyn EventInterface) -> anyhow::Result<i64> { if Platform::get_env("COMPOSER_DEBUG_EVENTS").is_some() { // TODO(plugin): PackageEvent / CommandEvent / PreCommandRunEvent specialization // requires polymorphic dispatch; the simple Event branch is sufficient for now. @@ -235,13 +235,13 @@ impl EventDispatcher { ); } - let listeners = self.get_listeners(&event); + let listeners = self.get_listeners(&*event); - self.push_event(&event)?; + self.push_event(&*event)?; let autoloaders_before = spl_autoload_functions(); - let result = self.do_dispatch_body(&event, listeners); + let result = self.do_dispatch_body(&*event, listeners); // finally block self.pop_event(); @@ -279,7 +279,11 @@ impl EventDispatcher { result } - fn do_dispatch_body(&mut self, event: &Event, listeners: Vec<Callable>) -> anyhow::Result<i64> { + fn do_dispatch_body( + &mut self, + event: &dyn EventInterface, + listeners: Vec<Callable>, + ) -> anyhow::Result<i64> { let mut return_max = 0_i64; for callable in listeners { let mut r#return: i64 = 0; @@ -471,14 +475,7 @@ impl EventDispatcher { flags, ); // TODO(plugin): script_event.set_originating_event(event.clone()) - match self.dispatch( - Some(&script_name), - Some(Event::new( - script_name.clone(), - script_event.inner_args_for_dispatch(), - script_event.inner_flags_for_dispatch(), - )), - ) { + match self.dispatch(Some(&script_name), Some(&mut script_event)) { Ok(v) => r#return = v, Err(e) => { if e.downcast_ref::<ScriptExecutionException>().is_some() { @@ -857,30 +854,16 @@ impl EventDispatcher { Ok(return_max) } - fn do_dispatch_script(&mut self, event: ScriptEvent) -> anyhow::Result<i64> { - // TODO(plugin): proper polymorphic dispatch — currently delegate to base Event path. - let base = Event::new( - event.get_inner().get_name().to_string(), - event.get_inner().get_arguments().clone(), - event.get_inner().get_flags().clone(), - ); - self.do_dispatch(base) + fn do_dispatch_script(&mut self, mut event: ScriptEvent) -> anyhow::Result<i64> { + self.do_dispatch(&mut event) } - fn do_dispatch_package(&mut self, event: PackageEvent) -> anyhow::Result<i64> { - // TODO(plugin): preserve PackageEvent identity for `instanceof` checks above. - let base = Event::new(event.get_name().to_string(), Vec::new(), IndexMap::new()); - self.do_dispatch(base) + fn do_dispatch_package(&mut self, mut event: PackageEvent) -> anyhow::Result<i64> { + self.do_dispatch(&mut event) } - fn do_dispatch_installer(&mut self, event: InstallerEvent) -> anyhow::Result<i64> { - // TODO(plugin): preserve InstallerEvent identity for `instanceof` checks above. - let base = Event::new( - event.get_inner_name().to_string(), - Vec::new(), - IndexMap::new(), - ); - self.do_dispatch(base) + fn do_dispatch_installer(&mut self, mut event: InstallerEvent) -> anyhow::Result<i64> { + self.do_dispatch(&mut event) } fn execute_tty(&self, exec: &str) -> anyhow::Result<i64> { @@ -936,7 +919,7 @@ impl EventDispatcher { &self, class_name: &str, method_name: &str, - event: &Event, + event: &dyn EventInterface, ) -> anyhow::Result<PhpMixed> { if self.io.is_verbose() { self.io.write_error3( @@ -969,7 +952,7 @@ impl EventDispatcher { todo!("dynamic static method invocation requires plugin runtime") } - fn event_needs_to_output(&self, event: &Event) -> bool { + fn event_needs_to_output(&self, event: &dyn EventInterface) -> bool { // do not output the command being run when using `composer exec` as it is fairly obvious the user is running it if event.get_name() == "__exec_command" { return false; @@ -1031,7 +1014,7 @@ impl EventDispatcher { } /// Retrieves all listeners for a given event - fn get_listeners(&mut self, event: &Event) -> Vec<Callable> { + fn get_listeners(&mut self, event: &dyn EventInterface) -> Vec<Callable> { let script_listeners: Vec<Callable> = if self.run_scripts { self.get_script_listeners(event) } else { @@ -1071,14 +1054,14 @@ impl EventDispatcher { } /// Checks if an event has listeners registered - pub fn has_event_listeners(&mut self, event: &Event) -> bool { + pub fn has_event_listeners(&mut self, event: &dyn EventInterface) -> bool { let listeners = self.get_listeners(event); listeners.len() > 0 } /// Finds all listeners defined as scripts in the package - fn get_script_listeners(&self, event: &Event) -> Vec<Callable> { + fn get_script_listeners(&self, event: &dyn EventInterface) -> Vec<Callable> { let composer = self.composer(); let composer = composer.borrow_partial(); let package = composer.get_package(); @@ -1128,7 +1111,7 @@ impl EventDispatcher { } /// Push an event to the stack of active event - fn push_event(&mut self, event: &Event) -> anyhow::Result<i64> { + fn push_event(&mut self, event: &dyn EventInterface) -> anyhow::Result<i64> { let event_name = event.get_name().to_string(); if self.event_stack.iter().any(|n| n == &event_name) { return Err(anyhow::anyhow!(RuntimeException { @@ -1227,7 +1210,11 @@ impl EventDispatcher { "unsupported".to_string() } - fn make_autoloader(&mut self, event: &Event, callable: &Callable) -> anyhow::Result<()> { + fn make_autoloader( + &mut self, + event: &dyn EventInterface, + callable: &Callable, + ) -> anyhow::Result<()> { let composer = self.composer(); // TODO(plugin): full autoloader rebuild on plugin-supplied callables — currently a stub. let Some(composer) = composer.as_full() else { @@ -1334,34 +1321,3 @@ impl EventDispatcher { } } } - -// TODO(plugin): re-export the `Event::name`-only constructor `Event::new` PHP variant so callers -// can build an `Event` from just a name, mirroring `new Event($eventName)`. -impl Event { - pub fn from_name(name: String) -> Self { - Event::new(name, Vec::new(), IndexMap::new()) - } -} - -// Convenience accessors that ScriptEvent doesn't currently expose for the base Event fields. -// TODO(plugin): replace with proper getters once ScriptEvent grows them. -impl ScriptEvent { - fn get_inner(&self) -> &Event { - unimplemented!("ScriptEvent::get_inner — Phase B") - } - - fn inner_args_for_dispatch(&self) -> Vec<String> { - Vec::new() - } - - fn inner_flags_for_dispatch(&self) -> IndexMap<String, PhpMixed> { - IndexMap::new() - } -} - -// Convenience accessor for InstallerEvent's underlying name. -impl InstallerEvent { - fn get_inner_name(&self) -> &str { - unimplemented!("InstallerEvent::get_inner_name — Phase B") - } -} |
