diff --git a/crates/egui_kittest/src/lib.rs b/crates/egui_kittest/src/lib.rs index e3d53b941..07f0f9fee 100644 --- a/crates/egui_kittest/src/lib.rs +++ b/crates/egui_kittest/src/lib.rs @@ -220,19 +220,22 @@ impl<'a, State: 'static> Harness<'a, State> { pub fn plugin>(&self) -> Option<&P> { self.plugins .iter() - .find_map(|p| p.as_any().downcast_ref::

()) + .find_map(|p| (&**p as &dyn std::any::Any).downcast_ref::

()) } /// Mutably borrow a registered plugin by type. pub fn plugin_mut>(&mut self) -> Option<&mut P> { self.plugins .iter_mut() - .find_map(|p| p.as_any_mut().downcast_mut::

()) + .find_map(|p| (&mut **p as &mut dyn std::any::Any).downcast_mut::

()) } /// Remove and return the first plugin of the given type. pub fn take_plugin>(&mut self) -> Option> { - let idx = self.plugins.iter().position(|p| p.as_any().is::

())?; + let idx = self + .plugins + .iter() + .position(|p| (&**p as &dyn std::any::Any).is::

())?; let boxed = self.plugins.remove(idx); let raw: *mut dyn Plugin = Box::into_raw(boxed); // SAFETY: `is::

()` confirmed the concrete type is `P`. Fat-to-thin pointer diff --git a/crates/egui_kittest/src/plugin.rs b/crates/egui_kittest/src/plugin.rs index fed1964e7..dcad4e60b 100644 --- a/crates/egui_kittest/src/plugin.rs +++ b/crates/egui_kittest/src/plugin.rs @@ -22,11 +22,15 @@ use crate::{ExceededMaxStepsError, Harness}; /// fn after_step(&mut self, _harness: &mut Harness<'_, S>) { /// // ... /// } -/// fn as_any(&self) -> &dyn std::any::Any { self } -/// fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } /// } /// ``` /// +/// # Downcasting +/// +/// [`Any`] is a supertrait, so [`Harness::plugin`] / [`Harness::plugin_mut`] / +/// [`Harness::take_plugin`] downcast registered plugins back to their concrete type via +/// trait upcasting. No boilerplate needed on your end. +/// /// # Re-entrancy /// /// Plugin hooks receive `&mut Harness`. Calling [`Harness::step`] / [`Harness::run`] / @@ -35,7 +39,7 @@ use crate::{ExceededMaxStepsError, Harness}; /// harness from inside a hook — e.g. an inspector that blocks on user input — use /// [`Harness::advance_frame`] instead. #[expect(unused_variables, reason = "default no-op impls")] -pub trait Plugin: Send + 'static { +pub trait Plugin: Send + Any { /// Called once at the start of every `run()` / `try_run()` / `try_run_realtime()` / /// `run_ok()` invocation, before the first step. fn before_run(&mut self, harness: &mut Harness<'_, State>) {} @@ -85,12 +89,6 @@ pub trait Plugin: Send + 'static { /// called [`install_panic_hook`]. Without the hook, the variant still flips to /// `Fail` but both fields are `None`. fn on_test_result(&mut self, harness: &mut Harness<'_, State>, result: TestResult<'_>) {} - - /// Downcast support — implement as `self`. - fn as_any(&self) -> &dyn Any; - - /// Downcast support — implement as `self`. - fn as_any_mut(&mut self) -> &mut dyn Any; } /// Location of a panic — a `std::panic::Location` stripped of its borrow so it can be diff --git a/crates/egui_kittest/tests/plugin.rs b/crates/egui_kittest/tests/plugin.rs index 0154b3223..33f92f71d 100644 --- a/crates/egui_kittest/tests/plugin.rs +++ b/crates/egui_kittest/tests/plugin.rs @@ -71,12 +71,6 @@ impl Plugin for CountingPlugin { TestResult::Fail { .. } => "on_test_result:fail", }); } - fn as_any(&self) -> &dyn std::any::Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } } /// Lifecycle ordering: a simple run+drop cycle fires the expected hooks in order. @@ -141,12 +135,6 @@ fn advance_frame_skips_hooks() { h.advance_frame(); } } - fn as_any(&self) -> &dyn std::any::Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } } let log: Log = Arc::default(); @@ -188,12 +176,6 @@ fn mid_dispatch_registration_is_deferred() { h.add_plugin(latecomer); } } - fn as_any(&self) -> &dyn std::any::Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } } let log: Log = Arc::default(); @@ -263,12 +245,6 @@ fn reentrant_step_panics_in_debug() { // Forbidden: step from inside a hook. h.step(); } - fn as_any(&self) -> &dyn std::any::Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn std::any::Any { - self - } } let mut harness = Harness::builder().with_plugin(Misbehaver).build_ui(|ui| {