bevy_ecs/reflect/
bundle.rs

1//! Definitions for [`Bundle`] reflection.
2//! This allows inserting, updating and/or removing bundles whose type is only known at runtime.
3//!
4//! This module exports two types: [`ReflectBundleFns`] and [`ReflectBundle`].
5//!
6//! Same as [`super::component`], but for bundles.
7use std::any::TypeId;
8
9use crate::{
10    prelude::Bundle,
11    world::{EntityMut, EntityWorldMut},
12};
13use bevy_reflect::{FromReflect, FromType, Reflect, ReflectRef, TypeRegistry};
14
15use super::{from_reflect_with_fallback, ReflectComponent};
16
17/// A struct used to operate on reflected [`Bundle`] trait of a type.
18///
19/// A [`ReflectBundle`] for type `T` can be obtained via
20/// [`bevy_reflect::TypeRegistration::data`].
21#[derive(Clone)]
22pub struct ReflectBundle(ReflectBundleFns);
23
24/// The raw function pointers needed to make up a [`ReflectBundle`].
25///
26/// The also [`super::component::ReflectComponentFns`].
27#[derive(Clone)]
28pub struct ReflectBundleFns {
29    /// Function pointer implementing [`ReflectBundle::insert()`].
30    pub insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
31    /// Function pointer implementing [`ReflectBundle::apply()`].
32    pub apply: fn(EntityMut, &dyn Reflect, &TypeRegistry),
33    /// Function pointer implementing [`ReflectBundle::apply_or_insert()`].
34    pub apply_or_insert: fn(&mut EntityWorldMut, &dyn Reflect, &TypeRegistry),
35    /// Function pointer implementing [`ReflectBundle::remove()`].
36    pub remove: fn(&mut EntityWorldMut),
37}
38
39impl ReflectBundleFns {
40    /// Get the default set of [`ReflectBundleFns`] for a specific bundle type using its
41    /// [`FromType`] implementation.
42    ///
43    /// This is useful if you want to start with the default implementation before overriding some
44    /// of the functions to create a custom implementation.
45    pub fn new<T: Bundle + Reflect + FromReflect>() -> Self {
46        <ReflectBundle as FromType<T>>::from_type().0
47    }
48}
49
50impl ReflectBundle {
51    /// Insert a reflected [`Bundle`] into the entity like [`insert()`](EntityWorldMut::insert).
52    pub fn insert(
53        &self,
54        entity: &mut EntityWorldMut,
55        bundle: &dyn Reflect,
56        registry: &TypeRegistry,
57    ) {
58        (self.0.insert)(entity, bundle, registry);
59    }
60
61    /// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value.
62    ///
63    /// # Panics
64    ///
65    /// Panics if there is no [`Bundle`] of the given type.
66    pub fn apply<'a>(
67        &self,
68        entity: impl Into<EntityMut<'a>>,
69        bundle: &dyn Reflect,
70        registry: &TypeRegistry,
71    ) {
72        (self.0.apply)(entity.into(), bundle, registry);
73    }
74
75    /// Uses reflection to set the value of this [`Bundle`] type in the entity to the given value or insert a new one if it does not exist.
76    pub fn apply_or_insert(
77        &self,
78        entity: &mut EntityWorldMut,
79        bundle: &dyn Reflect,
80        registry: &TypeRegistry,
81    ) {
82        (self.0.apply_or_insert)(entity, bundle, registry);
83    }
84
85    /// Removes this [`Bundle`] type from the entity. Does nothing if it doesn't exist.
86    pub fn remove(&self, entity: &mut EntityWorldMut) {
87        (self.0.remove)(entity);
88    }
89
90    /// Create a custom implementation of [`ReflectBundle`].
91    ///
92    /// This is an advanced feature,
93    /// useful for scripting implementations,
94    /// that should not be used by most users
95    /// unless you know what you are doing.
96    ///
97    /// Usually you should derive [`Reflect`] and add the `#[reflect(Bundle)]` bundle
98    /// to generate a [`ReflectBundle`] implementation automatically.
99    ///
100    /// See [`ReflectBundleFns`] for more information.
101    pub fn new(fns: ReflectBundleFns) -> Self {
102        Self(fns)
103    }
104
105    /// The underlying function pointers implementing methods on `ReflectBundle`.
106    ///
107    /// This is useful when you want to keep track locally of an individual
108    /// function pointer.
109    ///
110    /// Calling [`TypeRegistry::get`] followed by
111    /// [`TypeRegistration::data::<ReflectBundle>`] can be costly if done several
112    /// times per frame. Consider cloning [`ReflectBundle`] and keeping it
113    /// between frames, cloning a `ReflectBundle` is very cheap.
114    ///
115    /// If you only need a subset of the methods on `ReflectBundle`,
116    /// use `fn_pointers` to get the underlying [`ReflectBundleFns`]
117    /// and copy the subset of function pointers you care about.
118    ///
119    /// [`TypeRegistration::data::<ReflectBundle>`]: bevy_reflect::TypeRegistration::data
120    pub fn fn_pointers(&self) -> &ReflectBundleFns {
121        &self.0
122    }
123}
124
125impl<B: Bundle + Reflect> FromType<B> for ReflectBundle {
126    fn from_type() -> Self {
127        ReflectBundle(ReflectBundleFns {
128            insert: |entity, reflected_bundle, registry| {
129                let bundle = entity.world_scope(|world| {
130                    from_reflect_with_fallback::<B>(reflected_bundle, world, registry)
131                });
132                entity.insert(bundle);
133            },
134            apply: |mut entity, reflected_bundle, registry| {
135                if let Some(reflect_component) =
136                    registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
137                {
138                    reflect_component.apply(entity, reflected_bundle);
139                } else {
140                    match reflected_bundle.reflect_ref() {
141                        ReflectRef::Struct(bundle) => bundle
142                            .iter_fields()
143                            .for_each(|field| apply_field(&mut entity, field, registry)),
144                        ReflectRef::Tuple(bundle) => bundle
145                            .iter_fields()
146                            .for_each(|field| apply_field(&mut entity, field, registry)),
147                        _ => panic!(
148                            "expected bundle `{}` to be named struct or tuple",
149                            // FIXME: once we have unique reflect, use `TypePath`.
150                            std::any::type_name::<B>(),
151                        ),
152                    }
153                }
154            },
155            apply_or_insert: |entity, reflected_bundle, registry| {
156                if let Some(reflect_component) =
157                    registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
158                {
159                    reflect_component.apply_or_insert(entity, reflected_bundle, registry);
160                } else {
161                    match reflected_bundle.reflect_ref() {
162                        ReflectRef::Struct(bundle) => bundle
163                            .iter_fields()
164                            .for_each(|field| apply_or_insert_field(entity, field, registry)),
165                        ReflectRef::Tuple(bundle) => bundle
166                            .iter_fields()
167                            .for_each(|field| apply_or_insert_field(entity, field, registry)),
168                        _ => panic!(
169                            "expected bundle `{}` to be named struct or tuple",
170                            // FIXME: once we have unique reflect, use `TypePath`.
171                            std::any::type_name::<B>(),
172                        ),
173                    }
174                }
175            },
176            remove: |entity| {
177                entity.remove::<B>();
178            },
179        })
180    }
181}
182
183fn apply_field(entity: &mut EntityMut, field: &dyn Reflect, registry: &TypeRegistry) {
184    if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
185        reflect_component.apply(entity.reborrow(), field);
186    } else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
187        reflect_bundle.apply(entity.reborrow(), field, registry);
188    } else {
189        panic!(
190            "no `ReflectComponent` nor `ReflectBundle` registration found for `{}`",
191            field.reflect_type_path()
192        );
193    }
194}
195
196fn apply_or_insert_field(
197    entity: &mut EntityWorldMut,
198    field: &dyn Reflect,
199    registry: &TypeRegistry,
200) {
201    if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(field.type_id()) {
202        reflect_component.apply_or_insert(entity, field, registry);
203    } else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(field.type_id()) {
204        reflect_bundle.apply_or_insert(entity, field, registry);
205    } else {
206        let is_component = entity
207            .world()
208            .components()
209            .get_id(field.type_id())
210            .is_some();
211
212        if is_component {
213            panic!(
214                "no `ReflectComponent` registration found for `{}`",
215                field.reflect_type_path(),
216            );
217        } else {
218            panic!(
219                "no `ReflectBundle` registration found for `{}`",
220                field.reflect_type_path(),
221            )
222        }
223    }
224}