bevy_ecs/reflect/
entity_commands.rs

1use crate::{
2    entity::Entity,
3    prelude::Mut,
4    reflect::{AppTypeRegistry, ReflectBundle, ReflectComponent},
5    resource::Resource,
6    system::EntityCommands,
7    world::{EntityWorldMut, World},
8};
9use alloc::{borrow::Cow, boxed::Box};
10use bevy_reflect::{PartialReflect, TypeRegistry};
11
12/// An extension trait for [`EntityCommands`] for reflection related functions
13pub trait ReflectCommandExt {
14    /// Adds the given boxed reflect component or bundle to the entity using the reflection data in
15    /// [`AppTypeRegistry`].
16    ///
17    /// This will overwrite any previous component(s) of the same type.
18    ///
19    /// # Panics
20    ///
21    /// - If the entity doesn't exist.
22    /// - If [`AppTypeRegistry`] does not have the reflection data for the given
23    ///   [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
24    /// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
25    /// - If [`AppTypeRegistry`] is not present in the [`World`].
26    ///
27    /// # Note
28    ///
29    /// Prefer to use the typed [`EntityCommands::insert`] if possible. Adding a reflected component
30    /// is much slower.
31    ///
32    /// # Example
33    ///
34    /// ```
35    /// // Note that you need to register the component type in the AppTypeRegistry prior to using
36    /// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
37    /// // or write to the TypeRegistry directly to register all your components
38    ///
39    /// # use bevy_ecs::prelude::*;
40    /// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
41    /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
42    /// // A resource that can hold any component that implements reflect as a boxed reflect component
43    /// #[derive(Resource)]
44    /// struct Prefab {
45    ///     data: Box<dyn Reflect>,
46    /// }
47    /// #[derive(Component, Reflect, Default)]
48    /// #[reflect(Component)]
49    /// struct ComponentA(u32);
50    ///
51    /// #[derive(Component, Reflect, Default)]
52    /// #[reflect(Component)]
53    /// struct ComponentB(String);
54    ///
55    /// #[derive(Bundle, Reflect, Default)]
56    /// #[reflect(Bundle)]
57    /// struct BundleA {
58    ///     a: ComponentA,
59    ///     b: ComponentB,
60    /// }
61    ///
62    /// fn insert_reflect_component(
63    ///     mut commands: Commands,
64    ///     mut prefab: ResMut<Prefab>
65    ///     ) {
66    ///     // Create a set of new boxed reflect components to use
67    ///     let boxed_reflect_component_a: Box<dyn Reflect> = Box::new(ComponentA(916));
68    ///     let boxed_reflect_component_b: Box<dyn Reflect>  = Box::new(ComponentB("NineSixteen".to_string()));
69    ///     let boxed_reflect_bundle_a: Box<dyn Reflect> = Box::new(BundleA {
70    ///         a: ComponentA(24),
71    ///         b: ComponentB("Twenty-Four".to_string()),
72    ///     });
73    ///
74    ///     // You can overwrite the component in the resource with either ComponentA or ComponentB
75    ///     prefab.data = boxed_reflect_component_a;
76    ///     prefab.data = boxed_reflect_component_b;
77    ///
78    ///     // Or even with BundleA
79    ///     prefab.data = boxed_reflect_bundle_a;
80    ///
81    ///     // No matter which component or bundle is in the resource and without knowing the exact type, you can
82    ///     // use the insert_reflect entity command to insert that component/bundle into an entity.
83    ///     commands
84    ///         .spawn_empty()
85    ///         .insert_reflect(prefab.data.reflect_clone().unwrap().into_partial_reflect());
86    /// }
87    /// ```
88    fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self;
89
90    /// Same as [`insert_reflect`](ReflectCommandExt::insert_reflect), but using the `T` resource as type registry instead of
91    /// `AppTypeRegistry`.
92    ///
93    /// # Panics
94    ///
95    /// - If the given [`Resource`] is not present in the [`World`].
96    ///
97    /// # Note
98    ///
99    /// - The given [`Resource`] is removed from the [`World`] before the command is applied.
100    fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
101        &mut self,
102        component: Box<dyn PartialReflect>,
103    ) -> &mut Self;
104
105    /// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
106    ///
107    /// If the type is a bundle, it will remove any components in that bundle regardless if the entity
108    /// contains all the components.
109    ///
110    /// Does nothing if the type is a component and the entity does not have a component of the same type,
111    /// if the type is a bundle and the entity does not contain any of the components in the bundle,
112    /// if [`AppTypeRegistry`] does not contain the reflection data for the given component,
113    /// or if the entity does not exist.
114    ///
115    /// # Note
116    ///
117    /// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
118    /// is much slower.
119    ///
120    /// # Example
121    ///
122    /// ```
123    /// // Note that you need to register the component/bundle type in the AppTypeRegistry prior to using
124    /// // reflection. You can use the helpers on the App with `app.register_type::<ComponentA>()`
125    /// // or write to the TypeRegistry directly to register all your components and bundles
126    ///
127    /// # use bevy_ecs::prelude::*;
128    /// # use bevy_ecs::reflect::{ReflectCommandExt, ReflectBundle};
129    /// # use bevy_reflect::{FromReflect, FromType, Reflect, TypeRegistry};
130    ///
131    /// // A resource that can hold any component or bundle that implements reflect as a boxed reflect
132    /// #[derive(Resource)]
133    /// struct Prefab{
134    ///     entity: Entity,
135    ///     data: Box<dyn Reflect>,
136    /// }
137    /// #[derive(Component, Reflect, Default)]
138    /// #[reflect(Component)]
139    /// struct ComponentA(u32);
140    /// #[derive(Component, Reflect, Default)]
141    /// #[reflect(Component)]
142    /// struct ComponentB(String);
143    /// #[derive(Bundle, Reflect, Default)]
144    /// #[reflect(Bundle)]
145    /// struct BundleA {
146    ///     a: ComponentA,
147    ///     b: ComponentB,
148    /// }
149    ///
150    /// fn remove_reflect_component(
151    ///     mut commands: Commands,
152    ///     prefab: Res<Prefab>
153    ///     ) {
154    ///     // Prefab can hold any boxed reflect component or bundle. In this case either
155    ///     // ComponentA, ComponentB, or BundleA. No matter which component or bundle is in the resource though,
156    ///     // we can attempt to remove any component (or set of components in the case of a bundle)
157    ///     // of that same type from an entity.
158    ///     commands.entity(prefab.entity)
159    ///         .remove_reflect(prefab.data.reflect_type_path().to_owned());
160    /// }
161    /// ```
162    fn remove_reflect(&mut self, component_type_name: impl Into<Cow<'static, str>>) -> &mut Self;
163    /// Same as [`remove_reflect`](ReflectCommandExt::remove_reflect), but using the `T` resource as type registry instead of
164    /// `AppTypeRegistry`.
165    fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
166        &mut self,
167        component_type_name: impl Into<Cow<'static, str>>,
168    ) -> &mut Self;
169}
170
171impl ReflectCommandExt for EntityCommands<'_> {
172    fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
173        self.queue(move |mut entity: EntityWorldMut| {
174            entity.insert_reflect(component);
175        })
176    }
177
178    fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
179        &mut self,
180        component: Box<dyn PartialReflect>,
181    ) -> &mut Self {
182        self.queue(move |mut entity: EntityWorldMut| {
183            entity.insert_reflect_with_registry::<T>(component);
184        })
185    }
186
187    fn remove_reflect(&mut self, component_type_path: impl Into<Cow<'static, str>>) -> &mut Self {
188        let component_type_path: Cow<'static, str> = component_type_path.into();
189        self.queue(move |mut entity: EntityWorldMut| {
190            entity.remove_reflect(component_type_path);
191        })
192    }
193
194    fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
195        &mut self,
196        component_type_path: impl Into<Cow<'static, str>>,
197    ) -> &mut Self {
198        let component_type_path: Cow<'static, str> = component_type_path.into();
199        self.queue(move |mut entity: EntityWorldMut| {
200            entity.remove_reflect_with_registry::<T>(component_type_path);
201        })
202    }
203}
204
205impl<'w> EntityWorldMut<'w> {
206    /// Adds the given boxed reflect component or bundle to the entity using the reflection data in
207    /// [`AppTypeRegistry`].
208    ///
209    /// This will overwrite any previous component(s) of the same type.
210    ///
211    /// # Panics
212    ///
213    /// - If the entity has been despawned while this `EntityWorldMut` is still alive.
214    /// - If [`AppTypeRegistry`] does not have the reflection data for the given
215    ///   [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
216    /// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
217    /// - If [`AppTypeRegistry`] is not present in the [`World`].
218    ///
219    /// # Note
220    ///
221    /// Prefer to use the typed [`EntityWorldMut::insert`] if possible. Adding a reflected component
222    /// is much slower.
223    pub fn insert_reflect(&mut self, component: Box<dyn PartialReflect>) -> &mut Self {
224        self.assert_not_despawned();
225        let entity_id = self.id();
226        self.world_scope(|world| {
227            world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
228                let type_registry = &registry.as_ref().read();
229                insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
230            });
231            world.flush();
232        });
233        self.update_location();
234        self
235    }
236
237    /// Same as [`insert_reflect`](EntityWorldMut::insert_reflect), but using
238    /// the `T` resource as type registry instead of [`AppTypeRegistry`].
239    ///
240    /// This will overwrite any previous component(s) of the same type.
241    ///
242    /// # Panics
243    ///
244    /// - If the entity has been despawned while this `EntityWorldMut` is still alive.
245    /// - If the given [`Resource`] does not have the reflection data for the given
246    ///   [`Component`](crate::component::Component) or [`Bundle`](crate::bundle::Bundle).
247    /// - If the component or bundle data is invalid. See [`PartialReflect::apply`] for further details.
248    /// - If the given [`Resource`] is not present in the [`World`].
249    pub fn insert_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
250        &mut self,
251        component: Box<dyn PartialReflect>,
252    ) -> &mut Self {
253        self.assert_not_despawned();
254        let entity_id = self.id();
255        self.world_scope(|world| {
256            world.resource_scope(|world, registry: Mut<T>| {
257                let type_registry = registry.as_ref().as_ref();
258                insert_reflect_with_registry_ref(world, entity_id, type_registry, component);
259            });
260            world.flush();
261        });
262        self.update_location();
263        self
264    }
265
266    /// Removes from the entity the component or bundle with the given type name registered in [`AppTypeRegistry`].
267    ///
268    /// If the type is a bundle, it will remove any components in that bundle regardless if the entity
269    /// contains all the components.
270    ///
271    /// Does nothing if the type is a component and the entity does not have a component of the same type,
272    /// if the type is a bundle and the entity does not contain any of the components in the bundle,
273    /// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
274    ///
275    /// # Panics
276    ///
277    /// - If the entity has been despawned while this `EntityWorldMut` is still alive.
278    /// - If [`AppTypeRegistry`] is not present in the [`World`].
279    ///
280    /// # Note
281    ///
282    /// Prefer to use the typed [`EntityCommands::remove`] if possible. Removing a reflected component
283    /// is much slower.
284    pub fn remove_reflect(&mut self, component_type_path: Cow<'static, str>) -> &mut Self {
285        self.assert_not_despawned();
286        let entity_id = self.id();
287        self.world_scope(|world| {
288            world.resource_scope(|world, registry: Mut<AppTypeRegistry>| {
289                let type_registry = &registry.as_ref().read();
290                remove_reflect_with_registry_ref(
291                    world,
292                    entity_id,
293                    type_registry,
294                    component_type_path,
295                );
296            });
297            world.flush();
298        });
299        self.update_location();
300        self
301    }
302
303    /// Same as [`remove_reflect`](EntityWorldMut::remove_reflect), but using
304    /// the `T` resource as type registry instead of `AppTypeRegistry`.
305    ///
306    /// If the given type is a bundle, it will remove any components in that bundle regardless if the entity
307    /// contains all the components.
308    ///
309    /// Does nothing if the type is a component and the entity does not have a component of the same type,
310    /// if the type is a bundle and the entity does not contain any of the components in the bundle,
311    /// or if [`AppTypeRegistry`] does not contain the reflection data for the given component.
312    ///
313    /// # Panics
314    ///
315    /// - If the entity has been despawned while this `EntityWorldMut` is still alive.
316    /// - If [`AppTypeRegistry`] is not present in the [`World`].
317    pub fn remove_reflect_with_registry<T: Resource + AsRef<TypeRegistry>>(
318        &mut self,
319        component_type_path: Cow<'static, str>,
320    ) -> &mut Self {
321        self.assert_not_despawned();
322        let entity_id = self.id();
323        self.world_scope(|world| {
324            world.resource_scope(|world, registry: Mut<T>| {
325                let type_registry = registry.as_ref().as_ref();
326                remove_reflect_with_registry_ref(
327                    world,
328                    entity_id,
329                    type_registry,
330                    component_type_path,
331                );
332            });
333            world.flush();
334        });
335        self.update_location();
336        self
337    }
338}
339
340/// Helper function to add a reflect component or bundle to a given entity
341fn insert_reflect_with_registry_ref(
342    world: &mut World,
343    entity: Entity,
344    type_registry: &TypeRegistry,
345    component: Box<dyn PartialReflect>,
346) {
347    let type_info = component
348        .get_represented_type_info()
349        .expect("component should represent a type.");
350    let type_path = type_info.type_path();
351    let Ok(mut entity) = world.get_entity_mut(entity) else {
352        panic!("error[B0003]: Could not insert a reflected component (of type {type_path}) for entity {entity}, which {}. See: https://bevyengine.org/learn/errors/b0003",
353        world.entities().entity_does_not_exist_error_details(entity));
354    };
355    let Some(type_registration) = type_registry.get(type_info.type_id()) else {
356        panic!("`{type_path}` should be registered in type registry via `App::register_type<{type_path}>`");
357    };
358
359    if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
360        reflect_component.insert(&mut entity, component.as_partial_reflect(), type_registry);
361    } else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
362        reflect_bundle.insert(&mut entity, component.as_partial_reflect(), type_registry);
363    } else {
364        panic!("`{type_path}` should have #[reflect(Component)] or #[reflect(Bundle)]");
365    }
366}
367
368/// Helper function to remove a reflect component or bundle from a given entity
369fn remove_reflect_with_registry_ref(
370    world: &mut World,
371    entity: Entity,
372    type_registry: &TypeRegistry,
373    component_type_path: Cow<'static, str>,
374) {
375    let Ok(mut entity) = world.get_entity_mut(entity) else {
376        return;
377    };
378    let Some(type_registration) = type_registry.get_with_type_path(&component_type_path) else {
379        return;
380    };
381    if let Some(reflect_component) = type_registration.data::<ReflectComponent>() {
382        reflect_component.remove(&mut entity);
383    } else if let Some(reflect_bundle) = type_registration.data::<ReflectBundle>() {
384        reflect_bundle.remove(&mut entity);
385    }
386}
387
388#[cfg(test)]
389mod tests {
390    use crate::{
391        bundle::Bundle,
392        component::Component,
393        prelude::{AppTypeRegistry, ReflectComponent},
394        reflect::{ReflectBundle, ReflectCommandExt},
395        system::{Commands, SystemState},
396        world::World,
397    };
398    use alloc::{borrow::ToOwned, boxed::Box};
399    use bevy_ecs_macros::Resource;
400    use bevy_reflect::{PartialReflect, Reflect, TypeRegistry};
401
402    #[derive(Resource)]
403    struct TypeRegistryResource {
404        type_registry: TypeRegistry,
405    }
406
407    impl AsRef<TypeRegistry> for TypeRegistryResource {
408        fn as_ref(&self) -> &TypeRegistry {
409            &self.type_registry
410        }
411    }
412
413    #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
414    #[reflect(Component)]
415    struct ComponentA(u32);
416
417    #[derive(Component, Reflect, Default, PartialEq, Eq, Debug)]
418    #[reflect(Component)]
419    struct ComponentB(u32);
420
421    #[derive(Bundle, Reflect, Default, Debug, PartialEq)]
422    #[reflect(Bundle)]
423    struct BundleA {
424        a: ComponentA,
425        b: ComponentB,
426    }
427
428    #[test]
429    fn insert_reflected() {
430        let mut world = World::new();
431
432        let type_registry = AppTypeRegistry::default();
433        {
434            let mut registry = type_registry.write();
435            registry.register::<ComponentA>();
436            registry.register_type_data::<ComponentA, ReflectComponent>();
437        }
438        world.insert_resource(type_registry);
439
440        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
441        let mut commands = system_state.get_mut(&mut world);
442
443        let entity = commands.spawn_empty().id();
444        let entity2 = commands.spawn_empty().id();
445        let entity3 = commands.spawn_empty().id();
446
447        let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
448        let boxed_reflect_component_a_clone = boxed_reflect_component_a.reflect_clone().unwrap();
449        let boxed_reflect_component_a_dynamic = boxed_reflect_component_a.to_dynamic();
450
451        commands
452            .entity(entity)
453            .insert_reflect(boxed_reflect_component_a);
454        commands
455            .entity(entity2)
456            .insert_reflect(boxed_reflect_component_a_clone.into_partial_reflect());
457        commands
458            .entity(entity3)
459            .insert_reflect(boxed_reflect_component_a_dynamic);
460        system_state.apply(&mut world);
461
462        assert_eq!(
463            world.entity(entity).get::<ComponentA>(),
464            world.entity(entity2).get::<ComponentA>(),
465        );
466        assert_eq!(
467            world.entity(entity).get::<ComponentA>(),
468            world.entity(entity3).get::<ComponentA>(),
469        );
470    }
471
472    #[test]
473    fn insert_reflected_with_registry() {
474        let mut world = World::new();
475
476        let mut type_registry = TypeRegistryResource {
477            type_registry: TypeRegistry::new(),
478        };
479
480        type_registry.type_registry.register::<ComponentA>();
481        type_registry
482            .type_registry
483            .register_type_data::<ComponentA, ReflectComponent>();
484        world.insert_resource(type_registry);
485
486        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
487        let mut commands = system_state.get_mut(&mut world);
488
489        let entity = commands.spawn_empty().id();
490
491        let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn PartialReflect>;
492
493        commands
494            .entity(entity)
495            .insert_reflect_with_registry::<TypeRegistryResource>(boxed_reflect_component_a);
496        system_state.apply(&mut world);
497
498        assert_eq!(
499            world.entity(entity).get::<ComponentA>(),
500            Some(&ComponentA(916))
501        );
502    }
503
504    #[test]
505    fn remove_reflected() {
506        let mut world = World::new();
507
508        let type_registry = AppTypeRegistry::default();
509        {
510            let mut registry = type_registry.write();
511            registry.register::<ComponentA>();
512            registry.register_type_data::<ComponentA, ReflectComponent>();
513        }
514        world.insert_resource(type_registry);
515
516        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
517        let mut commands = system_state.get_mut(&mut world);
518
519        let entity = commands.spawn(ComponentA(0)).id();
520
521        let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
522
523        commands
524            .entity(entity)
525            .remove_reflect(boxed_reflect_component_a.reflect_type_path().to_owned());
526        system_state.apply(&mut world);
527
528        assert_eq!(world.entity(entity).get::<ComponentA>(), None);
529    }
530
531    #[test]
532    fn remove_reflected_with_registry() {
533        let mut world = World::new();
534
535        let mut type_registry = TypeRegistryResource {
536            type_registry: TypeRegistry::new(),
537        };
538
539        type_registry.type_registry.register::<ComponentA>();
540        type_registry
541            .type_registry
542            .register_type_data::<ComponentA, ReflectComponent>();
543        world.insert_resource(type_registry);
544
545        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
546        let mut commands = system_state.get_mut(&mut world);
547
548        let entity = commands.spawn(ComponentA(0)).id();
549
550        let boxed_reflect_component_a = Box::new(ComponentA(916)) as Box<dyn Reflect>;
551
552        commands
553            .entity(entity)
554            .remove_reflect_with_registry::<TypeRegistryResource>(
555                boxed_reflect_component_a.reflect_type_path().to_owned(),
556            );
557        system_state.apply(&mut world);
558
559        assert_eq!(world.entity(entity).get::<ComponentA>(), None);
560    }
561
562    #[test]
563    fn insert_reflect_bundle() {
564        let mut world = World::new();
565
566        let type_registry = AppTypeRegistry::default();
567        {
568            let mut registry = type_registry.write();
569            registry.register::<BundleA>();
570            registry.register_type_data::<BundleA, ReflectBundle>();
571        }
572        world.insert_resource(type_registry);
573
574        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
575        let mut commands = system_state.get_mut(&mut world);
576
577        let entity = commands.spawn_empty().id();
578        let bundle = Box::new(BundleA {
579            a: ComponentA(31),
580            b: ComponentB(20),
581        }) as Box<dyn PartialReflect>;
582        commands.entity(entity).insert_reflect(bundle);
583
584        system_state.apply(&mut world);
585
586        assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
587        assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
588    }
589
590    #[test]
591    fn insert_reflect_bundle_with_registry() {
592        let mut world = World::new();
593
594        let mut type_registry = TypeRegistryResource {
595            type_registry: TypeRegistry::new(),
596        };
597
598        type_registry.type_registry.register::<BundleA>();
599        type_registry
600            .type_registry
601            .register_type_data::<BundleA, ReflectBundle>();
602        world.insert_resource(type_registry);
603
604        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
605        let mut commands = system_state.get_mut(&mut world);
606
607        let entity = commands.spawn_empty().id();
608        let bundle = Box::new(BundleA {
609            a: ComponentA(31),
610            b: ComponentB(20),
611        }) as Box<dyn PartialReflect>;
612
613        commands
614            .entity(entity)
615            .insert_reflect_with_registry::<TypeRegistryResource>(bundle);
616        system_state.apply(&mut world);
617
618        assert_eq!(world.get::<ComponentA>(entity), Some(&ComponentA(31)));
619        assert_eq!(world.get::<ComponentB>(entity), Some(&ComponentB(20)));
620    }
621
622    #[test]
623    fn remove_reflected_bundle() {
624        let mut world = World::new();
625
626        let type_registry = AppTypeRegistry::default();
627        {
628            let mut registry = type_registry.write();
629            registry.register::<BundleA>();
630            registry.register_type_data::<BundleA, ReflectBundle>();
631        }
632        world.insert_resource(type_registry);
633
634        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
635        let mut commands = system_state.get_mut(&mut world);
636
637        let entity = commands
638            .spawn(BundleA {
639                a: ComponentA(31),
640                b: ComponentB(20),
641            })
642            .id();
643
644        let boxed_reflect_bundle_a = Box::new(BundleA {
645            a: ComponentA(1),
646            b: ComponentB(23),
647        }) as Box<dyn Reflect>;
648
649        commands
650            .entity(entity)
651            .remove_reflect(boxed_reflect_bundle_a.reflect_type_path().to_owned());
652        system_state.apply(&mut world);
653
654        assert_eq!(world.entity(entity).get::<ComponentA>(), None);
655        assert_eq!(world.entity(entity).get::<ComponentB>(), None);
656    }
657
658    #[test]
659    fn remove_reflected_bundle_with_registry() {
660        let mut world = World::new();
661
662        let mut type_registry = TypeRegistryResource {
663            type_registry: TypeRegistry::new(),
664        };
665
666        type_registry.type_registry.register::<BundleA>();
667        type_registry
668            .type_registry
669            .register_type_data::<BundleA, ReflectBundle>();
670        world.insert_resource(type_registry);
671
672        let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
673        let mut commands = system_state.get_mut(&mut world);
674
675        let entity = commands
676            .spawn(BundleA {
677                a: ComponentA(31),
678                b: ComponentB(20),
679            })
680            .id();
681
682        let boxed_reflect_bundle_a = Box::new(BundleA {
683            a: ComponentA(1),
684            b: ComponentB(23),
685        }) as Box<dyn Reflect>;
686
687        commands
688            .entity(entity)
689            .remove_reflect_with_registry::<TypeRegistryResource>(
690                boxed_reflect_bundle_a.reflect_type_path().to_owned(),
691            );
692        system_state.apply(&mut world);
693
694        assert_eq!(world.entity(entity).get::<ComponentA>(), None);
695        assert_eq!(world.entity(entity).get::<ComponentB>(), None);
696    }
697}