1use alloc::boxed::Box;
8use bevy_utils::prelude::DebugName;
9use core::any::{Any, TypeId};
10
11use crate::{
12 bundle::BundleFromComponents,
13 entity::EntityMapper,
14 prelude::Bundle,
15 relationship::RelationshipHookMode,
16 world::{EntityMut, EntityWorldMut},
17};
18use bevy_reflect::{
19 FromReflect, FromType, PartialReflect, Reflect, ReflectRef, TypePath, TypeRegistry,
20};
21
22use super::{from_reflect_with_fallback, ReflectComponent};
23
24#[derive(Clone)]
29pub struct ReflectBundle(ReflectBundleFns);
30
31#[derive(Clone)]
35pub struct ReflectBundleFns {
36 pub insert: fn(&mut EntityWorldMut, &dyn PartialReflect, &TypeRegistry),
38 pub apply: fn(EntityMut, &dyn PartialReflect, &TypeRegistry),
40 pub apply_or_insert_mapped: fn(
42 &mut EntityWorldMut,
43 &dyn PartialReflect,
44 &TypeRegistry,
45 &mut dyn EntityMapper,
46 RelationshipHookMode,
47 ),
48 pub remove: fn(&mut EntityWorldMut),
50 pub take: fn(&mut EntityWorldMut) -> Option<Box<dyn Reflect>>,
52}
53
54impl ReflectBundleFns {
55 pub fn new<T: Bundle + FromReflect + TypePath + BundleFromComponents>() -> Self {
61 <ReflectBundle as FromType<T>>::from_type().0
62 }
63}
64
65impl ReflectBundle {
66 pub fn insert(
68 &self,
69 entity: &mut EntityWorldMut,
70 bundle: &dyn PartialReflect,
71 registry: &TypeRegistry,
72 ) {
73 (self.0.insert)(entity, bundle, registry);
74 }
75
76 pub fn apply<'a>(
82 &self,
83 entity: impl Into<EntityMut<'a>>,
84 bundle: &dyn PartialReflect,
85 registry: &TypeRegistry,
86 ) {
87 (self.0.apply)(entity.into(), bundle, registry);
88 }
89
90 pub fn apply_or_insert_mapped(
92 &self,
93 entity: &mut EntityWorldMut,
94 bundle: &dyn PartialReflect,
95 registry: &TypeRegistry,
96 mapper: &mut dyn EntityMapper,
97 relationship_hook_mode: RelationshipHookMode,
98 ) {
99 (self.0.apply_or_insert_mapped)(entity, bundle, registry, mapper, relationship_hook_mode);
100 }
101
102 pub fn remove(&self, entity: &mut EntityWorldMut) -> &ReflectBundle {
104 (self.0.remove)(entity);
105 self
106 }
107
108 #[must_use]
112 pub fn take(&self, entity: &mut EntityWorldMut) -> Option<Box<dyn Reflect>> {
113 (self.0.take)(entity)
114 }
115
116 pub fn new(fns: ReflectBundleFns) -> Self {
128 Self(fns)
129 }
130
131 pub fn fn_pointers(&self) -> &ReflectBundleFns {
147 &self.0
148 }
149}
150
151impl<B: Bundle + Reflect + TypePath + BundleFromComponents> FromType<B> for ReflectBundle {
152 fn from_type() -> Self {
153 ReflectBundle(ReflectBundleFns {
154 insert: |entity, reflected_bundle, registry| {
155 let bundle = entity.world_scope(|world| {
156 from_reflect_with_fallback::<B>(reflected_bundle, world, registry)
157 });
158 entity.insert(bundle);
159 },
160 apply: |mut entity, reflected_bundle, registry| {
161 if let Some(reflect_component) =
162 registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
163 {
164 reflect_component.apply(entity, reflected_bundle);
165 } else {
166 match reflected_bundle.reflect_ref() {
167 ReflectRef::Struct(bundle) => bundle
168 .iter_fields()
169 .for_each(|field| apply_field(&mut entity, field, registry)),
170 ReflectRef::Tuple(bundle) => bundle
171 .iter_fields()
172 .for_each(|field| apply_field(&mut entity, field, registry)),
173 _ => panic!(
174 "expected bundle `{}` to be named struct or tuple",
175 DebugName::type_name::<B>(),
177 ),
178 }
179 }
180 },
181 apply_or_insert_mapped: |entity,
182 reflected_bundle,
183 registry,
184 mapper,
185 relationship_hook_mode| {
186 if let Some(reflect_component) =
187 registry.get_type_data::<ReflectComponent>(TypeId::of::<B>())
188 {
189 reflect_component.apply_or_insert_mapped(
190 entity,
191 reflected_bundle,
192 registry,
193 mapper,
194 relationship_hook_mode,
195 );
196 } else {
197 match reflected_bundle.reflect_ref() {
198 ReflectRef::Struct(bundle) => bundle.iter_fields().for_each(|field| {
199 apply_or_insert_field_mapped(
200 entity,
201 field,
202 registry,
203 mapper,
204 relationship_hook_mode,
205 );
206 }),
207 ReflectRef::Tuple(bundle) => bundle.iter_fields().for_each(|field| {
208 apply_or_insert_field_mapped(
209 entity,
210 field,
211 registry,
212 mapper,
213 relationship_hook_mode,
214 );
215 }),
216 _ => panic!(
217 "expected bundle `{}` to be a named struct or tuple",
218 DebugName::type_name::<B>(),
220 ),
221 }
222 }
223 },
224 remove: |entity| {
225 entity.remove::<B>();
226 },
227 take: |entity| {
228 entity
229 .take::<B>()
230 .map(|bundle| Box::new(bundle).into_reflect())
231 },
232 })
233 }
234}
235
236fn apply_field(entity: &mut EntityMut, field: &dyn PartialReflect, registry: &TypeRegistry) {
237 let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
238 panic!(
239 "`{}` did not implement `Reflect`",
240 field.reflect_type_path()
241 );
242 };
243 if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
244 reflect_component.apply(entity.reborrow(), field);
245 } else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
246 reflect_bundle.apply(entity.reborrow(), field, registry);
247 } else {
248 panic!(
249 "no `ReflectComponent` nor `ReflectBundle` registration found for `{}`",
250 field.reflect_type_path()
251 );
252 }
253}
254
255fn apply_or_insert_field_mapped(
256 entity: &mut EntityWorldMut,
257 field: &dyn PartialReflect,
258 registry: &TypeRegistry,
259 mapper: &mut dyn EntityMapper,
260 relationship_hook_mode: RelationshipHookMode,
261) {
262 let Some(type_id) = field.try_as_reflect().map(Any::type_id) else {
263 panic!(
264 "`{}` did not implement `Reflect`",
265 field.reflect_type_path()
266 );
267 };
268
269 if let Some(reflect_component) = registry.get_type_data::<ReflectComponent>(type_id) {
270 reflect_component.apply_or_insert_mapped(
271 entity,
272 field,
273 registry,
274 mapper,
275 relationship_hook_mode,
276 );
277 } else if let Some(reflect_bundle) = registry.get_type_data::<ReflectBundle>(type_id) {
278 reflect_bundle.apply_or_insert_mapped(
279 entity,
280 field,
281 registry,
282 mapper,
283 relationship_hook_mode,
284 );
285 } else {
286 let is_component = entity.world().components().get_id(type_id).is_some();
287
288 if is_component {
289 panic!(
290 "no `ReflectComponent` registration found for `{}`",
291 field.reflect_type_path(),
292 );
293 } else {
294 panic!(
295 "no `ReflectBundle` registration found for `{}`",
296 field.reflect_type_path(),
297 )
298 }
299 }
300}