Repository: bevyengine/bevy
File: crates/bevy_app/src/app.rs (Rust)

Code before:
                    if !plugin.ready(self) {
                        state = PluginsState::Adding;
                        break;
                    }
                }
                self.main_mut().plugin_registry = plugins;
                state
            }
            state => state,
        };

        // overall state is the earliest state of any sub-app
        self.sub_apps.iter_mut().skip(1).for_each(|s| {
            overall_plugins_state = overall_plugins_state.min(s.plugins_state());
        });

        overall_plugins_state
    }

    /// Runs [`Plugin::finish`] for each plugin. This is usually called by the event loop once all
    /// plugins are ready, but can be useful for situations where you want to use [`App::update`].
    pub fn finish(&mut self) {
        // plugins installed to main should see all sub-apps
        let plugins = core::mem::take(&mut self.main_mut().plugin_registry);
        for plugin in &plugins {
            plugin.finish(self);
        }
        let main = self.main_mut();
        main.plugin_registry = plugins;
        main.plugins_state = PluginsState::Finished;
        self.sub_apps.iter_mut().skip(1).for_each(SubApp::finish);
    }

    /// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after
    /// [`App::finish`], but can be useful for situations where you want to use [`App::update`].
    pub fn cleanup(&mut self) {
        // plugins installed to main should see all sub-apps
        let plugins = core::mem::take(&mut self.main_mut().plugin_registry);
        for plugin in &plugins {
            plugin.cleanup(self);
        }
        let main = self.main_mut();
        main.plugin_registry = plugins;
        main.plugins_state = PluginsState::Cleaned;
        self.sub_apps.iter_mut().skip(1).for_each(SubApp::cleanup);
    }

    /// Returns `true` if any of the sub-apps are building plugins.
    pub(crate) fn is_building_plugins(&self) -> bool {
        self.sub_apps.iter().any(SubApp::is_building_plugins)
    }

Review comment (suggestion):
note: if we want the plugins added during finish to have finish called on them, we should switch to a traditional for loop, because as-is the length gets computed once and baked into the range. Idk what the right behavior is here.

Code after:
                    if !plugin.ready(self) {
                        state = PluginsState::Adding;
                        break;
                    }
                }
                self.main_mut().plugin_registry = plugins;
                state
            }
            state => state,
        };

        // overall state is the earliest state of any sub-app
        self.sub_apps.iter_mut().skip(1).for_each(|s| {
            overall_plugins_state = overall_plugins_state.min(s.plugins_state());
        });

        overall_plugins_state
    }

    /// Runs [`Plugin::finish`] for each plugin. This is usually called by the event loop once all
    /// plugins are ready, but can be useful for situations where you want to use [`App::update`].
    pub fn finish(&mut self) {
        // plugins installed to main should see all sub-apps
        // do hokey pokey with a boxed zst plugin (doesn't allocate)
        let mut hokeypokey: Box<dyn Plugin> = Box::new(HokeyPokey);
        for i in 0..self.main().plugin_registry.len() {
            core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
            hokeypokey.finish(self);
            core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
        }
        self.main_mut().plugins_state = PluginsState::Finished;
        self.sub_apps.iter_mut().skip(1).for_each(SubApp::finish);
    }

    /// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after
    /// [`App::finish`], but can be useful for situations where you want to use [`App::update`].
    pub fn cleanup(&mut self) {
        // plugins installed to main should see all sub-apps
        // do hokey pokey with a boxed zst plugin (doesn't allocate)
        let mut hokeypokey: Box<dyn Plugin> = Box::new(HokeyPokey);
        for i in 0..self.main().plugin_registry.len() {
            core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
            hokeypokey.cleanup(self);
            core::mem::swap(&mut self.main_mut().plugin_registry[i], &mut hokeypokey);
        }
        self.main_mut().plugins_state = PluginsState::Cleaned;
        self.sub_apps.iter_mut().skip(1).for_each(SubApp::cleanup);
    }

    /// Returns `true` if any of the sub-apps are building plugins.
    pub(crate) fn is_building_plugins(&self) -> bool {