@@ -256,27 +256,29 @@ impl App {
256
256
/// plugins are ready, but can be useful for situations where you want to use [`App::update`].
257
257
pub fn finish ( & mut self ) {
258
258
// plugins installed to main should see all sub-apps
259
- let plugins = core:: mem:: take ( & mut self . main_mut ( ) . plugin_registry ) ;
260
- for plugin in & plugins {
261
- plugin. finish ( self ) ;
259
+ // do hokey pokey with a boxed zst plugin (doesn't allocate)
260
+ let mut hokeypokey: Box < dyn Plugin > = Box :: new ( HokeyPokey ) ;
261
+ for i in 0 ..self . main ( ) . plugin_registry . len ( ) {
262
+ core:: mem:: swap ( & mut self . main_mut ( ) . plugin_registry [ i] , & mut hokeypokey) ;
263
+ hokeypokey. finish ( self ) ;
264
+ core:: mem:: swap ( & mut self . main_mut ( ) . plugin_registry [ i] , & mut hokeypokey) ;
262
265
}
263
- let main = self . main_mut ( ) ;
264
- main. plugin_registry = plugins;
265
- main. plugins_state = PluginsState :: Finished ;
266
+ self . main_mut ( ) . plugins_state = PluginsState :: Finished ;
266
267
self . sub_apps . iter_mut ( ) . skip ( 1 ) . for_each ( SubApp :: finish) ;
267
268
}
268
269
269
270
/// Runs [`Plugin::cleanup`] for each plugin. This is usually called by the event loop after
270
271
/// [`App::finish`], but can be useful for situations where you want to use [`App::update`].
271
272
pub fn cleanup ( & mut self ) {
272
273
// plugins installed to main should see all sub-apps
273
- let plugins = core:: mem:: take ( & mut self . main_mut ( ) . plugin_registry ) ;
274
- for plugin in & plugins {
275
- plugin. cleanup ( self ) ;
274
+ // do hokey pokey with a boxed zst plugin (doesn't allocate)
275
+ let mut hokeypokey: Box < dyn Plugin > = Box :: new ( HokeyPokey ) ;
276
+ for i in 0 ..self . main ( ) . plugin_registry . len ( ) {
277
+ core:: mem:: swap ( & mut self . main_mut ( ) . plugin_registry [ i] , & mut hokeypokey) ;
278
+ hokeypokey. cleanup ( self ) ;
279
+ core:: mem:: swap ( & mut self . main_mut ( ) . plugin_registry [ i] , & mut hokeypokey) ;
276
280
}
277
- let main = self . main_mut ( ) ;
278
- main. plugin_registry = plugins;
279
- main. plugins_state = PluginsState :: Cleaned ;
281
+ self . main_mut ( ) . plugins_state = PluginsState :: Cleaned ;
280
282
self . sub_apps . iter_mut ( ) . skip ( 1 ) . for_each ( SubApp :: cleanup) ;
281
283
}
282
284
@@ -1390,6 +1392,12 @@ impl App {
1390
1392
}
1391
1393
}
1392
1394
1395
+ // Used for doing hokey pokey in finish and cleanup
1396
+ pub ( crate ) struct HokeyPokey ;
1397
+ impl Plugin for HokeyPokey {
1398
+ fn build ( & self , _: & mut App ) { }
1399
+ }
1400
+
1393
1401
type RunnerFn = Box < dyn FnOnce ( App ) -> AppExit > ;
1394
1402
1395
1403
fn run_once ( mut app : App ) -> AppExit {
@@ -1526,6 +1534,38 @@ mod tests {
1526
1534
}
1527
1535
}
1528
1536
1537
+ struct PluginF ;
1538
+
1539
+ impl Plugin for PluginF {
1540
+ fn build ( & self , _app : & mut App ) { }
1541
+
1542
+ fn finish ( & self , app : & mut App ) {
1543
+ // Ensure other plugins are available during finish
1544
+ assert_eq ! (
1545
+ app. is_plugin_added:: <PluginA >( ) ,
1546
+ !app. get_added_plugins:: <PluginA >( ) . is_empty( ) ,
1547
+ ) ;
1548
+ }
1549
+
1550
+ fn cleanup ( & self , app : & mut App ) {
1551
+ // Ensure other plugins are available during finish
1552
+ assert_eq ! (
1553
+ app. is_plugin_added:: <PluginA >( ) ,
1554
+ !app. get_added_plugins:: <PluginA >( ) . is_empty( ) ,
1555
+ ) ;
1556
+ }
1557
+ }
1558
+
1559
+ struct PluginG ;
1560
+
1561
+ impl Plugin for PluginG {
1562
+ fn build ( & self , _app : & mut App ) { }
1563
+
1564
+ fn finish ( & self , app : & mut App ) {
1565
+ app. add_plugins ( PluginB ) ;
1566
+ }
1567
+ }
1568
+
1529
1569
#[ test]
1530
1570
fn can_add_two_plugins ( ) {
1531
1571
App :: new ( ) . add_plugins ( ( PluginA , PluginB ) ) ;
@@ -1595,6 +1635,39 @@ mod tests {
1595
1635
app. finish ( ) ;
1596
1636
}
1597
1637
1638
+ #[ test]
1639
+ fn test_get_added_plugins_works_during_finish_and_cleanup ( ) {
1640
+ let mut app = App :: new ( ) ;
1641
+ app. add_plugins ( PluginA ) ;
1642
+ app. add_plugins ( PluginF ) ;
1643
+ app. finish ( ) ;
1644
+ }
1645
+
1646
+ #[ test]
1647
+ fn test_adding_plugin_works_during_finish ( ) {
1648
+ let mut app = App :: new ( ) ;
1649
+ app. add_plugins ( PluginA ) ;
1650
+ app. add_plugins ( PluginG ) ;
1651
+ app. finish ( ) ;
1652
+ assert_eq ! (
1653
+ app. main( ) . plugin_registry[ 0 ] . name( ) ,
1654
+ "bevy_app::main_schedule::MainSchedulePlugin"
1655
+ ) ;
1656
+ assert_eq ! (
1657
+ app. main( ) . plugin_registry[ 1 ] . name( ) ,
1658
+ "bevy_app::app::tests::PluginA"
1659
+ ) ;
1660
+ assert_eq ! (
1661
+ app. main( ) . plugin_registry[ 2 ] . name( ) ,
1662
+ "bevy_app::app::tests::PluginG"
1663
+ ) ;
1664
+ // PluginG adds PluginB during finish
1665
+ assert_eq ! (
1666
+ app. main( ) . plugin_registry[ 3 ] . name( ) ,
1667
+ "bevy_app::app::tests::PluginB"
1668
+ ) ;
1669
+ }
1670
+
1598
1671
#[ test]
1599
1672
fn test_derive_app_label ( ) {
1600
1673
use super :: AppLabel ;
0 commit comments