Skip to content

Commit c110e48

Browse files
committed
fix bug, add test, add doc
1 parent 85ab55a commit c110e48

File tree

2 files changed

+210
-23
lines changed

2 files changed

+210
-23
lines changed

crates/bevy_app/src/app_builder.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,13 +294,17 @@ impl AppBuilder {
294294
self
295295
}
296296

297+
/// Adds a [`PluginGroup`] to the application. To customize the plugins in the group
298+
/// (reorder, disable a plugin, add a new plugin before / after another plugin),
299+
/// see [`add_plugins_with`](Self::add_plugins_with).
297300
pub fn add_plugins<T: PluginGroup>(&mut self, mut group: T) -> &mut Self {
298301
let mut plugin_group_builder = PluginGroupBuilder::default();
299302
group.build(&mut plugin_group_builder);
300303
plugin_group_builder.finish(self);
301304
self
302305
}
303306

307+
/// Adds a [`PluginGroup`] to the application, customizing it with a [`PluginGroupBuilder`].
304308
pub fn add_plugins_with<T, F>(&mut self, mut group: T, func: F) -> &mut Self
305309
where
306310
T: PluginGroup,

crates/bevy_app/src/plugin_group.rs

Lines changed: 206 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,53 @@ struct PluginEntry {
1111
enabled: bool,
1212
}
1313

14+
/// Builds and customizes a plugin group. A plugin group is an ordered list of plugins that
15+
/// that can be enabled, disabled or reordered.
1416
#[derive(Default)]
1517
pub struct PluginGroupBuilder {
1618
plugins: HashMap<TypeId, PluginEntry>,
1719
order: Vec<TypeId>,
1820
}
1921

2022
impl PluginGroupBuilder {
23+
// Removes a previous ordering of a plugin that has just been added at `added_at` index
24+
fn remove_when_adding<T: Plugin>(&mut self, added_at: usize) {
25+
if let Some(to_remove) = self
26+
.order
27+
.iter()
28+
.enumerate()
29+
.find(|(i, ty)| *i != added_at && **ty == TypeId::of::<T>())
30+
.map(|(i, _)| i)
31+
{
32+
self.order.remove(to_remove);
33+
}
34+
}
35+
36+
/// Adds the plugin `plugin` at the end of this `PluginGroupBuilder`. If the plugin was
37+
/// already in the group, it is removed from its previous place.
2138
pub fn add<T: Plugin>(&mut self, plugin: T) -> &mut Self {
39+
let target_index = self.order.len();
2240
self.order.push(TypeId::of::<T>());
23-
self.plugins.insert(
24-
TypeId::of::<T>(),
25-
PluginEntry {
26-
plugin: Box::new(plugin),
27-
enabled: true,
28-
},
29-
);
41+
if self
42+
.plugins
43+
.insert(
44+
TypeId::of::<T>(),
45+
PluginEntry {
46+
plugin: Box::new(plugin),
47+
enabled: true,
48+
},
49+
)
50+
.is_some()
51+
{
52+
self.remove_when_adding::<T>(target_index);
53+
}
54+
3055
self
3156
}
3257

58+
/// Adds the plugin `plugin` in this `PluginGroupBuilder` before the plugin of type `Target`.
59+
/// If the plugin was already the group, it is removed from its previous place. There must
60+
/// be a plugin of type `Target` in the group or it will fail.
3361
pub fn add_before<Target: Plugin, T: Plugin>(&mut self, plugin: T) -> &mut Self {
3462
let target_index = self
3563
.order
@@ -44,16 +72,25 @@ impl PluginGroupBuilder {
4472
)
4573
});
4674
self.order.insert(target_index, TypeId::of::<T>());
47-
self.plugins.insert(
48-
TypeId::of::<T>(),
49-
PluginEntry {
50-
plugin: Box::new(plugin),
51-
enabled: true,
52-
},
53-
);
75+
if self
76+
.plugins
77+
.insert(
78+
TypeId::of::<T>(),
79+
PluginEntry {
80+
plugin: Box::new(plugin),
81+
enabled: true,
82+
},
83+
)
84+
.is_some()
85+
{
86+
self.remove_when_adding::<T>(target_index);
87+
}
5488
self
5589
}
5690

91+
/// Adds the plugin `plugin` in this `PluginGroupBuilder` after the plugin of type `Target`.
92+
/// If the plugin was already the group, it is removed from its previous place. There must
93+
/// be a plugin of type `Target` in the group or it will fail.
5794
pub fn add_after<Target: Plugin, T: Plugin>(&mut self, plugin: T) -> &mut Self {
5895
let target_index = self
5996
.order
@@ -66,18 +103,27 @@ impl PluginGroupBuilder {
66103
"Plugin does not exist: {}.",
67104
std::any::type_name::<Target>()
68105
)
69-
});
70-
self.order.insert(target_index + 1, TypeId::of::<T>());
71-
self.plugins.insert(
72-
TypeId::of::<T>(),
73-
PluginEntry {
74-
plugin: Box::new(plugin),
75-
enabled: true,
76-
},
77-
);
106+
})
107+
+ 1;
108+
self.order.insert(target_index, TypeId::of::<T>());
109+
if self
110+
.plugins
111+
.insert(
112+
TypeId::of::<T>(),
113+
PluginEntry {
114+
plugin: Box::new(plugin),
115+
enabled: true,
116+
},
117+
)
118+
.is_some()
119+
{
120+
self.remove_when_adding::<T>(target_index);
121+
}
78122
self
79123
}
80124

125+
/// Enables the plugin of type `T` in this `PluginGroupBuilder`. There must
126+
/// be a plugin of type `Target` in the group or it will fail.
81127
pub fn enable<T: Plugin>(&mut self) -> &mut Self {
82128
let mut plugin_entry = self
83129
.plugins
@@ -87,6 +133,10 @@ impl PluginGroupBuilder {
87133
self
88134
}
89135

136+
/// Disables the plugin of type `T` in this `PluginGroupBuilder`, but leave it in its
137+
/// place so that you can still use [`add_before`](Self::add_before) or
138+
/// [`add_after`](Self::add_after), or re-enable it with [`enable`](Self::enable).
139+
/// There must be a plugin of type `Target` in the group or it will fail.
90140
pub fn disable<T: Plugin>(&mut self) -> &mut Self {
91141
let mut plugin_entry = self
92142
.plugins
@@ -96,6 +146,7 @@ impl PluginGroupBuilder {
96146
self
97147
}
98148

149+
/// Adds the enabled [`Plugin`] from this group in order to the application.
99150
pub fn finish(self, app: &mut AppBuilder) {
100151
for ty in self.order.iter() {
101152
if let Some(entry) = self.plugins.get(ty) {
@@ -107,3 +158,135 @@ impl PluginGroupBuilder {
107158
}
108159
}
109160
}
161+
162+
#[cfg(test)]
163+
mod tests {
164+
use super::PluginGroupBuilder;
165+
use crate::{AppBuilder, Plugin};
166+
167+
struct PluginA;
168+
impl Plugin for PluginA {
169+
fn build(&self, _: &mut AppBuilder) {
170+
()
171+
}
172+
}
173+
174+
struct PluginB;
175+
impl Plugin for PluginB {
176+
fn build(&self, _: &mut AppBuilder) {
177+
()
178+
}
179+
}
180+
181+
struct PluginC;
182+
impl Plugin for PluginC {
183+
fn build(&self, _: &mut AppBuilder) {
184+
()
185+
}
186+
}
187+
188+
#[test]
189+
fn basic_ordering() {
190+
let mut group = PluginGroupBuilder::default();
191+
group.add(PluginA);
192+
group.add(PluginB);
193+
group.add(PluginC);
194+
195+
assert_eq!(
196+
group.order,
197+
vec![
198+
std::any::TypeId::of::<PluginA>(),
199+
std::any::TypeId::of::<PluginB>(),
200+
std::any::TypeId::of::<PluginC>(),
201+
]
202+
)
203+
}
204+
205+
#[test]
206+
fn add_after() {
207+
let mut group = PluginGroupBuilder::default();
208+
group.add(PluginA);
209+
group.add(PluginB);
210+
group.add_after::<PluginA, PluginC>(PluginC);
211+
212+
assert_eq!(
213+
group.order,
214+
vec![
215+
std::any::TypeId::of::<PluginA>(),
216+
std::any::TypeId::of::<PluginC>(),
217+
std::any::TypeId::of::<PluginB>(),
218+
]
219+
)
220+
}
221+
222+
#[test]
223+
fn add_before() {
224+
let mut group = PluginGroupBuilder::default();
225+
group.add(PluginA);
226+
group.add(PluginB);
227+
group.add_before::<PluginB, PluginC>(PluginC);
228+
229+
assert_eq!(
230+
group.order,
231+
vec![
232+
std::any::TypeId::of::<PluginA>(),
233+
std::any::TypeId::of::<PluginC>(),
234+
std::any::TypeId::of::<PluginB>(),
235+
]
236+
)
237+
}
238+
239+
#[test]
240+
fn readd() {
241+
let mut group = PluginGroupBuilder::default();
242+
group.add(PluginA);
243+
group.add(PluginB);
244+
group.add(PluginC);
245+
group.add(PluginB);
246+
247+
assert_eq!(
248+
group.order,
249+
vec![
250+
std::any::TypeId::of::<PluginA>(),
251+
std::any::TypeId::of::<PluginC>(),
252+
std::any::TypeId::of::<PluginB>(),
253+
]
254+
)
255+
}
256+
257+
#[test]
258+
fn readd_after() {
259+
let mut group = PluginGroupBuilder::default();
260+
group.add(PluginA);
261+
group.add(PluginB);
262+
group.add(PluginC);
263+
group.add_after::<PluginA, PluginC>(PluginC);
264+
265+
assert_eq!(
266+
group.order,
267+
vec![
268+
std::any::TypeId::of::<PluginA>(),
269+
std::any::TypeId::of::<PluginC>(),
270+
std::any::TypeId::of::<PluginB>(),
271+
]
272+
)
273+
}
274+
275+
#[test]
276+
fn readd_before() {
277+
let mut group = PluginGroupBuilder::default();
278+
group.add(PluginA);
279+
group.add(PluginB);
280+
group.add(PluginC);
281+
group.add_before::<PluginB, PluginC>(PluginC);
282+
283+
assert_eq!(
284+
group.order,
285+
vec![
286+
std::any::TypeId::of::<PluginA>(),
287+
std::any::TypeId::of::<PluginC>(),
288+
std::any::TypeId::of::<PluginB>(),
289+
]
290+
)
291+
}
292+
}

0 commit comments

Comments
 (0)