Skip to main content

bevy_ecs/reflect/
entity_commands.rs

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