1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

Remove some slightly overengineered stuff

This commit is contained in:
lucasmerlin
2026-04-23 17:28:22 +02:00
parent 495f714a0b
commit 5373b1ce41
3 changed files with 15 additions and 55 deletions

View File

@@ -87,8 +87,6 @@ pub struct Harness<'a, State: 'static = ()> {
queued_events: EventQueue, queued_events: EventQueue,
plugins: Vec<Box<dyn Plugin<State>>>, plugins: Vec<Box<dyn Plugin<State>>>,
pending_plugins: Vec<Box<dyn Plugin<State>>>,
in_dispatch: bool,
entry_location: Option<&'static std::panic::Location<'static>>, entry_location: Option<&'static std::panic::Location<'static>>,
consumed_event_locations: Vec<&'static std::panic::Location<'static>>, consumed_event_locations: Vec<&'static std::panic::Location<'static>>,
last_accesskit_update: Option<egui::accesskit::TreeUpdate>, last_accesskit_update: Option<egui::accesskit::TreeUpdate>,
@@ -181,8 +179,6 @@ impl<'a, State: 'static> Harness<'a, State> {
queued_events: Default::default(), queued_events: Default::default(),
plugins, plugins,
pending_plugins: Vec::new(),
in_dispatch: false,
entry_location: None, entry_location: None,
consumed_event_locations: Vec::new(), consumed_event_locations: Vec::new(),
last_accesskit_update: Some(initial_accesskit), last_accesskit_update: Some(initial_accesskit),
@@ -206,13 +202,12 @@ impl<'a, State: 'static> Harness<'a, State> {
/// Register a [`Plugin`] after construction. /// Register a [`Plugin`] after construction.
/// ///
/// See [`HarnessBuilder::with_plugin`] to register before the first frame runs. /// See [`HarnessBuilder::with_plugin`] to register before the first frame runs.
///
/// Calling this from inside a plugin hook is allowed — the new plugin is appended to
/// the list but does not receive the currently-dispatching hook; it starts firing on
/// the next dispatch.
pub fn add_plugin(&mut self, plugin: impl Plugin<State>) { pub fn add_plugin(&mut self, plugin: impl Plugin<State>) {
let boxed: Box<dyn Plugin<State>> = Box::new(plugin); self.plugins.push(Box::new(plugin));
if self.in_dispatch {
self.pending_plugins.push(boxed);
} else {
self.plugins.push(boxed);
}
} }
/// Borrow a registered plugin by type. Returns the first plugin of the matching type /// Borrow a registered plugin by type. Returns the first plugin of the matching type
@@ -246,11 +241,9 @@ impl<'a, State: 'static> Harness<'a, State> {
/// Advance the harness by one frame without firing plugin hooks. /// Advance the harness by one frame without firing plugin hooks.
/// ///
/// Use this from inside a plugin hook when the plugin needs to drive additional /// This is useful for running steps within a plugin, without ending in an infinite loop where
/// frames — e.g. an inspector plugin that blocks on user input and re-renders /// the plugin is called again.
/// after each injected event. Calling [`Self::step`] or [`Self::run`] from inside pub fn step_no_side_effects(&mut self) {
/// a hook would recurse infinitely through that plugin's own `after_step`.
pub fn advance_frame(&mut self) {
self._step_inner(false); self._step_inner(false);
} }
@@ -276,17 +269,13 @@ impl<'a, State: 'static> Harness<'a, State> {
return; return;
} }
let mut plugins = std::mem::take(&mut self.plugins); let mut plugins = std::mem::take(&mut self.plugins);
self.in_dispatch = true;
for p in &mut plugins { for p in &mut plugins {
f(p.as_mut(), self); f(p.as_mut(), self);
} }
self.in_dispatch = false; // Handle the case where a plugin is registered within some other plugin
let added = std::mem::take(&mut self.plugins);
self.plugins = plugins; self.plugins = plugins;
// Promote any plugins registered mid-dispatch to the end of the active list. self.plugins.extend(added);
if !self.pending_plugins.is_empty() {
let pending = std::mem::take(&mut self.pending_plugins);
self.plugins.extend(pending);
}
} }
/// Create a new Harness with the given ui closure and a state. /// Create a new Harness with the given ui closure and a state.
@@ -346,10 +335,6 @@ impl<'a, State: 'static> Harness<'a, State> {
/// update the Harness. /// update the Harness.
#[track_caller] #[track_caller]
pub fn step(&mut self) { pub fn step(&mut self) {
debug_assert!(
!self.in_dispatch,
"Harness::step called from inside a plugin hook — use Harness::advance_frame instead to avoid infinite recursion"
);
self.entry_location = Some(std::panic::Location::caller()); self.entry_location = Some(std::panic::Location::caller());
let events = std::mem::take(&mut *self.queued_events.lock()); let events = std::mem::take(&mut *self.queued_events.lock());
if events.is_empty() { if events.is_empty() {
@@ -381,7 +366,7 @@ impl<'a, State: 'static> Harness<'a, State> {
} }
/// Core frame advance. Does NOT fire plugin hooks — callable from within /// Core frame advance. Does NOT fire plugin hooks — callable from within
/// hooks via [`Self::advance_frame`] without recursing. /// hooks via [`Self::step_no_side_effects`] without recursing.
fn _step_inner(&mut self, sizing_pass: bool) { fn _step_inner(&mut self, sizing_pass: bool) {
self.input.predicted_dt = self.step_dt; self.input.predicted_dt = self.step_dt;
@@ -465,10 +450,6 @@ impl<'a, State: 'static> Harness<'a, State> {
} }
fn _try_run(&mut self, sleep: bool) -> Result<u64, ExceededMaxStepsError> { fn _try_run(&mut self, sleep: bool) -> Result<u64, ExceededMaxStepsError> {
debug_assert!(
!self.in_dispatch,
"Harness::run / Harness::try_run called from inside a plugin hook — use Harness::advance_frame instead to avoid infinite recursion"
);
self.dispatch(|p, h| p.before_run(h)); self.dispatch(|p, h| p.before_run(h));
let mut steps = 0; let mut steps = 0;

View File

@@ -34,10 +34,9 @@ use crate::{ExceededMaxStepsError, Harness};
/// # Re-entrancy /// # Re-entrancy
/// ///
/// Plugin hooks receive `&mut Harness`. Calling [`Harness::step`] / [`Harness::run`] / /// Plugin hooks receive `&mut Harness`. Calling [`Harness::step`] / [`Harness::run`] /
/// etc. from inside a hook is forbidden (it would recurse infinitely through your own /// etc. from inside a hook will recurse infinitely through your own `after_step`. If
/// `after_step`) and is caught by a `debug_assert!`. If a plugin needs to advance the /// a plugin needs to advance the harness from inside a hook — e.g. an inspector that
/// harness from inside a hook — e.g. an inspector that blocks on user input — use /// blocks on user input — use [`Harness::advance_frame`] instead.
/// [`Harness::advance_frame`] instead.
#[expect(unused_variables, reason = "default no-op impls")] #[expect(unused_variables, reason = "default no-op impls")]
pub trait Plugin<State = ()>: Send + Any { pub trait Plugin<State = ()>: Send + Any {
/// Called once at the start of every `run()` / `try_run()` / `try_run_realtime()` / /// Called once at the start of every `run()` / `try_run()` / `try_run_realtime()` /

View File

@@ -233,26 +233,6 @@ fn on_test_result_sees_panic() {
assert_eq!(last, Some("on_test_result:fail"), "log = {log:?}"); assert_eq!(last, Some("on_test_result:fail"), "log = {log:?}");
} }
/// Calling `Harness::step` from inside a plugin hook should panic in debug builds
/// (the `in_dispatch` guard).
#[cfg(debug_assertions)]
#[test]
#[should_panic(expected = "inside a plugin hook")]
fn reentrant_step_panics_in_debug() {
struct Misbehaver;
impl<S: 'static> Plugin<S> for Misbehaver {
fn after_step(&mut self, h: &mut Harness<'_, S>) {
// Forbidden: step from inside a hook.
h.step();
}
}
let mut harness = Harness::builder().with_plugin(Misbehaver).build_ui(|ui| {
ui.label("hi");
});
harness.step();
}
/// `on_snapshot` fires with an Err result for a missing snapshot. /// `on_snapshot` fires with an Err result for a missing snapshot.
#[cfg(feature = "snapshot")] #[cfg(feature = "snapshot")]
#[test] #[test]