1use crate::generics::impl_generic_info_methods;
2use crate::{
3 self as bevy_reflect,
4 attributes::{impl_custom_attribute_methods, CustomAttributes},
5 type_info::impl_type_methods,
6 ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
7 ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
8};
9use alloc::{borrow::Cow, sync::Arc};
10use bevy_reflect_derive::impl_type_path;
11use bevy_utils::HashMap;
12use core::{
13 fmt::{Debug, Formatter},
14 slice::Iter,
15};
16
17pub trait Struct: PartialReflect {
49 fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
52
53 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
56
57 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
60
61 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
64
65 fn name_at(&self, index: usize) -> Option<&str>;
67
68 fn field_len(&self) -> usize;
70
71 fn iter_fields(&self) -> FieldIter;
73
74 fn clone_dynamic(&self) -> DynamicStruct;
76
77 fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
79 self.get_represented_type_info()?.as_struct().ok()
80 }
81}
82
83#[derive(Clone, Debug)]
85pub struct StructInfo {
86 ty: Type,
87 generics: Generics,
88 fields: Box<[NamedField]>,
89 field_names: Box<[&'static str]>,
90 field_indices: HashMap<&'static str, usize>,
91 custom_attributes: Arc<CustomAttributes>,
92 #[cfg(feature = "documentation")]
93 docs: Option<&'static str>,
94}
95
96impl StructInfo {
97 pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
103 let field_indices = fields
104 .iter()
105 .enumerate()
106 .map(|(index, field)| (field.name(), index))
107 .collect::<HashMap<_, _>>();
108
109 let field_names = fields.iter().map(NamedField::name).collect();
110
111 Self {
112 ty: Type::of::<T>(),
113 generics: Generics::new(),
114 fields: fields.to_vec().into_boxed_slice(),
115 field_names,
116 field_indices,
117 custom_attributes: Arc::new(CustomAttributes::default()),
118 #[cfg(feature = "documentation")]
119 docs: None,
120 }
121 }
122
123 #[cfg(feature = "documentation")]
125 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
126 Self { docs, ..self }
127 }
128
129 pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
131 Self {
132 custom_attributes: Arc::new(custom_attributes),
133 ..self
134 }
135 }
136
137 pub fn field_names(&self) -> &[&'static str] {
139 &self.field_names
140 }
141
142 pub fn field(&self, name: &str) -> Option<&NamedField> {
144 self.field_indices
145 .get(name)
146 .map(|index| &self.fields[*index])
147 }
148
149 pub fn field_at(&self, index: usize) -> Option<&NamedField> {
151 self.fields.get(index)
152 }
153
154 pub fn index_of(&self, name: &str) -> Option<usize> {
156 self.field_indices.get(name).copied()
157 }
158
159 pub fn iter(&self) -> Iter<'_, NamedField> {
161 self.fields.iter()
162 }
163
164 pub fn field_len(&self) -> usize {
166 self.fields.len()
167 }
168
169 impl_type_methods!(ty);
170
171 #[cfg(feature = "documentation")]
173 pub fn docs(&self) -> Option<&'static str> {
174 self.docs
175 }
176
177 impl_custom_attribute_methods!(self.custom_attributes, "struct");
178
179 impl_generic_info_methods!(generics);
180}
181
182pub struct FieldIter<'a> {
184 pub(crate) struct_val: &'a dyn Struct,
185 pub(crate) index: usize,
186}
187
188impl<'a> FieldIter<'a> {
189 pub fn new(value: &'a dyn Struct) -> Self {
190 FieldIter {
191 struct_val: value,
192 index: 0,
193 }
194 }
195}
196
197impl<'a> Iterator for FieldIter<'a> {
198 type Item = &'a dyn PartialReflect;
199
200 fn next(&mut self) -> Option<Self::Item> {
201 let value = self.struct_val.field_at(self.index);
202 self.index += value.is_some() as usize;
203 value
204 }
205
206 fn size_hint(&self) -> (usize, Option<usize>) {
207 let size = self.struct_val.field_len();
208 (size, Some(size))
209 }
210}
211
212impl<'a> ExactSizeIterator for FieldIter<'a> {}
213
214pub trait GetField {
235 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
238
239 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
242}
243
244impl<S: Struct> GetField for S {
245 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
246 self.field(name)
247 .and_then(|value| value.try_downcast_ref::<T>())
248 }
249
250 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
251 self.field_mut(name)
252 .and_then(|value| value.try_downcast_mut::<T>())
253 }
254}
255
256impl GetField for dyn Struct {
257 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
258 self.field(name)
259 .and_then(|value| value.try_downcast_ref::<T>())
260 }
261
262 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
263 self.field_mut(name)
264 .and_then(|value| value.try_downcast_mut::<T>())
265 }
266}
267
268#[derive(Default)]
270pub struct DynamicStruct {
271 represented_type: Option<&'static TypeInfo>,
272 fields: Vec<Box<dyn PartialReflect>>,
273 field_names: Vec<Cow<'static, str>>,
274 field_indices: HashMap<Cow<'static, str>, usize>,
275}
276
277impl DynamicStruct {
278 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
286 if let Some(represented_type) = represented_type {
287 assert!(
288 matches!(represented_type, TypeInfo::Struct(_)),
289 "expected TypeInfo::Struct but received: {:?}",
290 represented_type
291 );
292 }
293
294 self.represented_type = represented_type;
295 }
296
297 pub fn insert_boxed<'a>(
301 &mut self,
302 name: impl Into<Cow<'a, str>>,
303 value: Box<dyn PartialReflect>,
304 ) {
305 let name: Cow<str> = name.into();
306 if let Some(index) = self.field_indices.get(&name) {
307 self.fields[*index] = value;
308 } else {
309 self.fields.push(value);
310 self.field_indices
311 .insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
312 self.field_names.push(Cow::Owned(name.into_owned()));
313 }
314 }
315
316 pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
320 self.insert_boxed(name, Box::new(value));
321 }
322
323 pub fn index_of(&self, name: &str) -> Option<usize> {
325 self.field_indices.get(name).copied()
326 }
327}
328
329impl Struct for DynamicStruct {
330 #[inline]
331 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
332 self.field_indices
333 .get(name)
334 .map(|index| &*self.fields[*index])
335 }
336
337 #[inline]
338 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
339 if let Some(index) = self.field_indices.get(name) {
340 Some(&mut *self.fields[*index])
341 } else {
342 None
343 }
344 }
345
346 #[inline]
347 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
348 self.fields.get(index).map(|value| &**value)
349 }
350
351 #[inline]
352 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
353 self.fields.get_mut(index).map(|value| &mut **value)
354 }
355
356 #[inline]
357 fn name_at(&self, index: usize) -> Option<&str> {
358 self.field_names.get(index).map(AsRef::as_ref)
359 }
360
361 #[inline]
362 fn field_len(&self) -> usize {
363 self.fields.len()
364 }
365
366 #[inline]
367 fn iter_fields(&self) -> FieldIter {
368 FieldIter {
369 struct_val: self,
370 index: 0,
371 }
372 }
373
374 fn clone_dynamic(&self) -> DynamicStruct {
375 DynamicStruct {
376 represented_type: self.get_represented_type_info(),
377 field_names: self.field_names.clone(),
378 field_indices: self.field_indices.clone(),
379 fields: self
380 .fields
381 .iter()
382 .map(|value| value.clone_value())
383 .collect(),
384 }
385 }
386}
387
388impl PartialReflect for DynamicStruct {
389 #[inline]
390 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
391 self.represented_type
392 }
393
394 #[inline]
395 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
396 self
397 }
398
399 #[inline]
400 fn as_partial_reflect(&self) -> &dyn PartialReflect {
401 self
402 }
403
404 #[inline]
405 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
406 self
407 }
408
409 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
410 Err(self)
411 }
412 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
413 None
414 }
415 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
416 None
417 }
418
419 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
420 let struct_value = value.reflect_ref().as_struct()?;
421
422 for (i, value) in struct_value.iter_fields().enumerate() {
423 let name = struct_value.name_at(i).unwrap();
424 if let Some(v) = self.field_mut(name) {
425 v.try_apply(value)?;
426 }
427 }
428
429 Ok(())
430 }
431
432 #[inline]
433 fn reflect_kind(&self) -> ReflectKind {
434 ReflectKind::Struct
435 }
436
437 #[inline]
438 fn reflect_ref(&self) -> ReflectRef {
439 ReflectRef::Struct(self)
440 }
441
442 #[inline]
443 fn reflect_mut(&mut self) -> ReflectMut {
444 ReflectMut::Struct(self)
445 }
446
447 #[inline]
448 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
449 ReflectOwned::Struct(self)
450 }
451
452 #[inline]
453 fn clone_value(&self) -> Box<dyn PartialReflect> {
454 Box::new(self.clone_dynamic())
455 }
456
457 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
458 struct_partial_eq(self, value)
459 }
460
461 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
462 write!(f, "DynamicStruct(")?;
463 struct_debug(self, f)?;
464 write!(f, ")")
465 }
466
467 #[inline]
468 fn is_dynamic(&self) -> bool {
469 true
470 }
471}
472
473impl_type_path!((in bevy_reflect) DynamicStruct);
474
475impl Debug for DynamicStruct {
476 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
477 self.debug(f)
478 }
479}
480
481impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
482where
483 N: Into<Cow<'a, str>>,
484{
485 fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
488 let mut dynamic_struct = Self::default();
489 for (name, value) in fields.into_iter() {
490 dynamic_struct.insert_boxed(name, value);
491 }
492 dynamic_struct
493 }
494}
495
496impl IntoIterator for DynamicStruct {
497 type Item = Box<dyn PartialReflect>;
498 type IntoIter = alloc::vec::IntoIter<Self::Item>;
499
500 fn into_iter(self) -> Self::IntoIter {
501 self.fields.into_iter()
502 }
503}
504
505impl<'a> IntoIterator for &'a DynamicStruct {
506 type Item = &'a dyn PartialReflect;
507 type IntoIter = FieldIter<'a>;
508
509 fn into_iter(self) -> Self::IntoIter {
510 self.iter_fields()
511 }
512}
513
514#[inline]
524pub fn struct_partial_eq<S: Struct + ?Sized>(a: &S, b: &dyn PartialReflect) -> Option<bool> {
525 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
526 return Some(false);
527 };
528
529 if a.field_len() != struct_value.field_len() {
530 return Some(false);
531 }
532
533 for (i, value) in struct_value.iter_fields().enumerate() {
534 let name = struct_value.name_at(i).unwrap();
535 if let Some(field_value) = a.field(name) {
536 let eq_result = field_value.reflect_partial_eq(value);
537 if let failed @ (Some(false) | None) = eq_result {
538 return failed;
539 }
540 } else {
541 return Some(false);
542 }
543 }
544
545 Some(true)
546}
547
548#[inline]
568pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
569 let mut debug = f.debug_struct(
570 dyn_struct
571 .get_represented_type_info()
572 .map(TypeInfo::type_path)
573 .unwrap_or("_"),
574 );
575 for field_index in 0..dyn_struct.field_len() {
576 let field = dyn_struct.field_at(field_index).unwrap();
577 debug.field(
578 dyn_struct.name_at(field_index).unwrap(),
579 &field as &dyn Debug,
580 );
581 }
582 debug.finish()
583}
584
585#[cfg(test)]
586mod tests {
587 use crate as bevy_reflect;
588 use crate::*;
589 #[derive(Reflect, Default)]
590 struct MyStruct {
591 a: (),
592 b: (),
593 c: (),
594 }
595 #[test]
596 fn next_index_increment() {
597 let my_struct = MyStruct::default();
598 let mut iter = my_struct.iter_fields();
599 iter.index = iter.len() - 1;
600 let prev_index = iter.index;
601 assert!(iter.next().is_some());
602 assert_eq!(prev_index, iter.index - 1);
603
604 let prev_index = iter.index;
606 assert!(iter.next().is_none());
607 assert_eq!(prev_index, iter.index);
608 assert!(iter.next().is_none());
609 assert_eq!(prev_index, iter.index);
610 }
611}