1use crate::generics::impl_generic_info_methods;
5use crate::{
6 attributes::{impl_custom_attribute_methods, CustomAttributes},
7 ty::impl_type_methods,
8 ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectCloneError, ReflectKind,
9 ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
10};
11use alloc::{borrow::Cow, boxed::Box, vec::Vec};
12use bevy_platform::collections::HashMap;
13use bevy_reflect_derive::impl_type_path;
14use core::{
15 fmt::{Debug, Formatter},
16 slice::Iter,
17};
18
19pub trait Struct: PartialReflect {
51 fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
54
55 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
58
59 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
62
63 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
66
67 fn name_at(&self, index: usize) -> Option<&str>;
69
70 fn index_of_name(&self, name: &str) -> Option<usize>;
72
73 fn field_len(&self) -> usize;
75
76 fn iter_fields(&self) -> FieldIter<'_>;
78
79 fn to_dynamic_struct(&self) -> Result<DynamicStruct, ReflectCloneError> {
83 let mut dynamic_struct = DynamicStruct::default();
84 dynamic_struct.set_represented_type(self.get_represented_type_info());
85 for (name, value) in self.iter_fields() {
86 dynamic_struct.insert_boxed(name, value.to_dynamic()?);
87 }
88 Ok(dynamic_struct)
89 }
90
91 fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
93 self.get_represented_type_info()?.as_struct().ok()
94 }
95}
96
97impl<'a> IntoIterator for &'a dyn Struct {
98 type Item = (&'a str, &'a dyn PartialReflect);
99 type IntoIter = FieldIter<'a>;
100
101 fn into_iter(self) -> Self::IntoIter {
102 self.iter_fields()
103 }
104}
105
106#[derive(Clone, Debug)]
108pub struct StructInfo {
109 ty: Type,
110 generics: Generics,
111 fields: Box<[NamedField]>,
112 field_names: Box<[&'static str]>,
113 field_indices: HashMap<&'static str, usize>,
114 custom_attributes: CustomAttributes,
115 #[cfg(feature = "reflect_documentation")]
116 docs: Option<&'static str>,
117}
118
119impl StructInfo {
120 pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
126 Self::from_erased(fields, Type::of::<T>())
127 }
128
129 #[inline(never)]
132 fn from_erased(fields: &[NamedField], ty: Type) -> Self {
133 let field_indices = fields
134 .iter()
135 .enumerate()
136 .map(|(index, field)| (field.name(), index))
137 .collect::<HashMap<_, _>>();
138
139 let field_names = fields.iter().map(NamedField::name).collect();
140
141 Self {
142 ty,
143 generics: Generics::new(),
144 fields: fields.to_vec().into_boxed_slice(),
145 field_names,
146 field_indices,
147 custom_attributes: CustomAttributes::default(),
148 #[cfg(feature = "reflect_documentation")]
149 docs: None,
150 }
151 }
152
153 #[cfg(feature = "reflect_documentation")]
155 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
156 Self { docs, ..self }
157 }
158
159 pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
161 Self {
162 custom_attributes,
163 ..self
164 }
165 }
166
167 pub fn field_names(&self) -> &[&'static str] {
169 &self.field_names
170 }
171
172 pub fn field(&self, name: &str) -> Option<&NamedField> {
174 self.field_indices
175 .get(name)
176 .map(|index| &self.fields[*index])
177 }
178
179 pub fn field_at(&self, index: usize) -> Option<&NamedField> {
181 self.fields.get(index)
182 }
183
184 pub fn index_of(&self, name: &str) -> Option<usize> {
186 self.field_indices.get(name).copied()
187 }
188
189 pub fn iter(&self) -> Iter<'_, NamedField> {
191 self.fields.iter()
192 }
193
194 pub fn field_len(&self) -> usize {
196 self.fields.len()
197 }
198
199 impl_type_methods!(ty);
200
201 #[cfg(feature = "reflect_documentation")]
203 pub fn docs(&self) -> Option<&'static str> {
204 self.docs
205 }
206
207 impl_custom_attribute_methods!(self.custom_attributes, "struct");
208
209 impl_generic_info_methods!(generics);
210}
211
212pub struct FieldIter<'a> {
214 pub(crate) struct_val: &'a dyn Struct,
215 pub(crate) index: usize,
216}
217
218impl<'a> FieldIter<'a> {
219 pub fn new(value: &'a dyn Struct) -> Self {
221 FieldIter {
222 struct_val: value,
223 index: 0,
224 }
225 }
226}
227
228impl<'a> Iterator for FieldIter<'a> {
229 type Item = (&'a str, &'a dyn PartialReflect);
230
231 fn next(&mut self) -> Option<Self::Item> {
232 if let Some(name) = self.struct_val.name_at(self.index)
233 && let Some(field) = self.struct_val.field_at(self.index)
234 {
235 self.index += 1;
236 Some((name, field))
237 } else {
238 None
239 }
240 }
241
242 fn size_hint(&self) -> (usize, Option<usize>) {
243 let remaining = self.struct_val.field_len().saturating_sub(self.index);
244 (remaining, Some(remaining))
245 }
246}
247
248impl<'a> ExactSizeIterator for FieldIter<'a> {}
249
250pub trait GetField {
271 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
274
275 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
278}
279
280impl<S: Struct> GetField for S {
281 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
282 self.field(name)
283 .and_then(|value| value.try_downcast_ref::<T>())
284 }
285
286 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
287 self.field_mut(name)
288 .and_then(|value| value.try_downcast_mut::<T>())
289 }
290}
291
292impl GetField for dyn Struct {
293 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
294 self.field(name)
295 .and_then(|value| value.try_downcast_ref::<T>())
296 }
297
298 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
299 self.field_mut(name)
300 .and_then(|value| value.try_downcast_mut::<T>())
301 }
302}
303
304#[derive(Default)]
306pub struct DynamicStruct {
307 represented_type: Option<&'static TypeInfo>,
308 fields: Vec<Box<dyn PartialReflect>>,
309 field_names: Vec<Cow<'static, str>>,
310 field_indices: HashMap<Cow<'static, str>, usize>,
311}
312
313impl DynamicStruct {
314 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
322 if let Some(represented_type) = represented_type {
323 assert!(
324 matches!(represented_type, TypeInfo::Struct(_)),
325 "expected TypeInfo::Struct but received: {represented_type:?}"
326 );
327 }
328
329 self.represented_type = represented_type;
330 }
331
332 pub fn insert_boxed<'a>(
336 &mut self,
337 name: impl Into<Cow<'a, str>>,
338 field: Box<dyn PartialReflect>,
339 ) {
340 let name: Cow<str> = name.into();
341 if let Some(index) = self.field_indices.get(&name) {
342 self.fields[*index] = field;
343 } else {
344 self.fields.push(field);
345 self.field_indices
346 .insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
347 self.field_names.push(Cow::Owned(name.into_owned()));
348 }
349 }
350
351 pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, field: T) {
355 self.insert_boxed(name, Box::new(field));
356 }
357
358 pub fn remove_at(
360 &mut self,
361 index: usize,
362 ) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)> {
363 let mut i: usize = 0;
364 let mut extract = self.field_names.extract_if(0..self.field_names.len(), |n| {
365 let mut result = false;
366 if i == index {
367 self.field_indices
368 .remove(n)
369 .expect("Invalid name for `field_indices.remove(name)`");
370 result = true;
371 } else if i > index {
372 *self
373 .field_indices
374 .get_mut(n)
375 .expect("Invalid name for `field_indices.get_mut(name)`") -= 1;
376 }
377 i += 1;
378 result
379 });
380
381 let name = extract
382 .nth(0)
383 .expect("Invalid index for `extract.nth(index)`");
384 extract.for_each(drop); Some((name, self.fields.remove(index)))
387 }
388
389 pub fn remove_if<F>(&mut self, mut f: F) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)>
391 where
392 F: FnMut((&str, &dyn PartialReflect)) -> bool,
393 {
394 if let Some(index) = self
395 .field_names
396 .iter()
397 .zip(self.fields.iter())
398 .position(|(name, field)| f((name.as_ref(), field.as_ref())))
399 {
400 self.remove_at(index)
401 } else {
402 None
403 }
404 }
405
406 pub fn remove_by_name(
408 &mut self,
409 name: &str,
410 ) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)> {
411 if let Some(index) = self.index_of_name(name) {
412 self.remove_at(index)
413 } else {
414 None
415 }
416 }
417}
418
419impl Struct for DynamicStruct {
420 #[inline]
421 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
422 self.field_indices
423 .get(name)
424 .map(|index| &*self.fields[*index])
425 }
426
427 #[inline]
428 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
429 if let Some(index) = self.index_of_name(name) {
430 Some(self.fields[index].as_mut())
431 } else {
432 None
433 }
434 }
435
436 #[inline]
437 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
438 self.fields.get(index).map(AsRef::as_ref)
439 }
440
441 #[inline]
442 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
443 self.fields.get_mut(index).map(AsMut::as_mut)
444 }
445
446 #[inline]
447 fn name_at(&self, index: usize) -> Option<&str> {
448 self.field_names.get(index).map(AsRef::as_ref)
449 }
450
451 #[inline]
453 fn index_of_name(&self, name: &str) -> Option<usize> {
454 self.field_indices.get(name).copied()
455 }
456
457 #[inline]
458 fn field_len(&self) -> usize {
459 self.fields.len()
460 }
461
462 #[inline]
463 fn iter_fields(&self) -> FieldIter<'_> {
464 FieldIter::new(self)
465 }
466}
467
468impl PartialReflect for DynamicStruct {
469 #[inline]
470 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
471 self.represented_type
472 }
473
474 #[inline]
475 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
476 self
477 }
478
479 #[inline]
480 fn as_partial_reflect(&self) -> &dyn PartialReflect {
481 self
482 }
483
484 #[inline]
485 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
486 self
487 }
488
489 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
490 Err(self)
491 }
492 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
493 None
494 }
495 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
496 None
497 }
498
499 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
500 let struct_value = value.reflect_ref().as_struct()?;
501
502 for (name, value) in struct_value {
503 if let Some(v) = self.field_mut(name) {
504 v.try_apply(value)?;
505 }
506 }
507
508 Ok(())
509 }
510
511 #[inline]
512 fn reflect_kind(&self) -> ReflectKind {
513 ReflectKind::Struct
514 }
515
516 #[inline]
517 fn reflect_ref(&self) -> ReflectRef<'_> {
518 ReflectRef::Struct(self)
519 }
520
521 #[inline]
522 fn reflect_mut(&mut self) -> ReflectMut<'_> {
523 ReflectMut::Struct(self)
524 }
525
526 #[inline]
527 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
528 ReflectOwned::Struct(self)
529 }
530
531 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
532 struct_partial_eq(self, value)
533 }
534
535 fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
536 struct_partial_cmp(self, value)
537 }
538
539 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
540 write!(f, "DynamicStruct(")?;
541 struct_debug(self, f)?;
542 write!(f, ")")
543 }
544
545 #[inline]
546 fn is_dynamic(&self) -> bool {
547 true
548 }
549}
550
551impl_type_path!((in bevy_reflect) DynamicStruct);
552
553impl Debug for DynamicStruct {
554 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
555 self.debug(f)
556 }
557}
558
559impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
560where
561 N: Into<Cow<'a, str>>,
562{
563 fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
566 let mut dynamic_struct = Self::default();
567 for (name, value) in fields.into_iter() {
568 dynamic_struct.insert_boxed(name, value);
569 }
570 dynamic_struct
571 }
572}
573
574impl IntoIterator for DynamicStruct {
575 type Item = (Cow<'static, str>, Box<dyn PartialReflect>);
576 type IntoIter = core::iter::Zip<
577 alloc::vec::IntoIter<Cow<'static, str>>,
578 alloc::vec::IntoIter<Box<dyn PartialReflect>>,
579 >;
580
581 fn into_iter(self) -> Self::IntoIter {
582 self.field_names.into_iter().zip(self.fields)
583 }
584}
585
586impl<'a> IntoIterator for &'a DynamicStruct {
587 type Item = (&'a str, &'a dyn PartialReflect);
588 type IntoIter = FieldIter<'a>;
589
590 fn into_iter(self) -> Self::IntoIter {
591 self.iter_fields()
592 }
593}
594
595#[inline(never)]
605pub fn struct_partial_eq(a: &dyn Struct, b: &dyn PartialReflect) -> Option<bool> {
606 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
607 return Some(false);
608 };
609
610 if a.field_len() != struct_value.field_len() {
611 return Some(false);
612 }
613
614 for (name, value) in struct_value {
615 if let Some(field_value) = a.field(name) {
616 let eq_result = field_value.reflect_partial_eq(value);
617 if let failed @ (Some(false) | None) = eq_result {
618 return failed;
619 }
620 } else {
621 return Some(false);
622 }
623 }
624
625 Some(true)
626}
627
628#[inline(never)]
633pub fn struct_partial_cmp(a: &dyn Struct, b: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
634 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
635 return None;
636 };
637
638 if a.field_len() != struct_value.field_len() {
639 return None;
640 }
641
642 partial_cmp_by_field_names(
644 a.field_len(),
645 |i| a.name_at(i),
646 |i| a.field_at(i),
647 |i| struct_value.name_at(i),
648 |i| struct_value.field_at(i),
649 |name| struct_value.field(name),
650 )
651}
652
653pub(crate) fn partial_cmp_by_field_names<'a, NA, FA, NB, FB, FBY>(
663 field_len: usize,
664 name_at_a: NA,
665 field_at_a: FA,
666 name_at_b: NB,
667 field_at_b_index: FB,
668 field_b_by_name: FBY,
669) -> Option<::core::cmp::Ordering>
670where
671 NA: Fn(usize) -> Option<&'a str>,
672 FA: Fn(usize) -> Option<&'a dyn PartialReflect>,
673 NB: Fn(usize) -> Option<&'a str>,
674 FB: Fn(usize) -> Option<&'a dyn PartialReflect>,
675 FBY: Fn(&str) -> Option<&'a dyn PartialReflect>,
676{
677 use ::core::cmp::Ordering;
678
679 let mut same_field_order = true;
680 for i in 0..field_len {
681 if name_at_a(i) != name_at_b(i) {
682 same_field_order = false;
683 break;
684 }
685 }
686
687 if same_field_order {
688 for i in 0..field_len {
689 let a_val = field_at_a(i).unwrap();
690 let b_val = field_at_b_index(i).unwrap();
691 match a_val.reflect_partial_cmp(b_val) {
692 None => return None,
693 Some(Ordering::Equal) => continue,
694 Some(ord) => return Some(ord),
695 }
696 }
697 return Some(Ordering::Equal);
698 }
699
700 let mut all_less_equal = true;
701 let mut all_greater_equal = true;
702 let mut all_equal = true;
703
704 for i in 0..field_len {
705 let field_name = name_at_a(i).unwrap();
706 let a_val = field_at_a(i).unwrap();
707 let b_val = field_b_by_name(field_name)?;
708 match a_val.reflect_partial_cmp(b_val) {
709 None => return None,
710 Some(::core::cmp::Ordering::Less) => {
711 all_greater_equal = false;
712 all_equal = false;
713 }
714 Some(::core::cmp::Ordering::Greater) => {
715 all_less_equal = false;
716 all_equal = false;
717 }
718 Some(::core::cmp::Ordering::Equal) => {}
719 }
720 }
721
722 if all_equal {
723 Some(::core::cmp::Ordering::Equal)
724 } else if all_less_equal {
725 Some(::core::cmp::Ordering::Less)
726 } else if all_greater_equal {
727 Some(::core::cmp::Ordering::Greater)
728 } else {
729 None
730 }
731}
732
733#[inline]
753pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
754 let mut debug = f.debug_struct(
755 dyn_struct
756 .get_represented_type_info()
757 .map(TypeInfo::type_path)
758 .unwrap_or("_"),
759 );
760 for field_index in 0..dyn_struct.field_len() {
761 let field = dyn_struct.field_at(field_index).unwrap();
762 debug.field(
763 dyn_struct.name_at(field_index).unwrap(),
764 &field as &dyn Debug,
765 );
766 }
767 debug.finish()
768}
769
770#[cfg(test)]
771mod tests {
772 use crate::{structs::*, *};
773 use alloc::borrow::ToOwned;
774
775 #[derive(Reflect, Default)]
776 struct MyStruct {
777 a: (),
778 b: (),
779 c: (),
780 }
781
782 #[derive(Reflect, Default)]
783 struct OtherStruct {
784 a: u32,
785 b: u64,
786 c: MyStruct,
787 }
788
789 #[test]
790 fn dynamic_struct_remove_at() {
791 let mut s = OtherStruct::default().to_dynamic_struct().unwrap();
792
793 assert_eq!(s.field_len(), 3);
794
795 let field_2 = s
796 .remove_at(1)
797 .expect("Invalid index for `s.remove_at(index)`");
798
799 assert_eq!(s.field_len(), 2);
800 assert_eq!(field_2.0, "b");
801
802 let field_3 = s
803 .remove_at(0)
804 .expect("Invalid index for `s.remove_at(index)`");
805
806 assert_eq!(s.field_len(), 1);
807 assert_eq!(field_3.0, "a");
808
809 let field_1 = s
810 .remove_at(0)
811 .expect("Invalid index for `s.remove_at(index)`");
812
813 assert_eq!(s.field_len(), 0);
814 assert_eq!(field_1.0, "c");
815 }
816
817 #[test]
818 fn dynamic_struct_remove_by_name() {
819 let mut s = OtherStruct::default().to_dynamic_struct().unwrap();
820
821 assert_eq!(s.field_len(), 3);
822
823 let field_3 = s
824 .remove_by_name("b")
825 .expect("Invalid name for `s.remove_by_name(name)`");
826
827 assert_eq!(s.field_len(), 2);
828 assert_eq!(field_3.0, "b");
829
830 let field_2 = s
831 .remove_by_name("c")
832 .expect("Invalid name for `s.remove_by_name(name)`");
833
834 assert_eq!(s.field_len(), 1);
835 assert_eq!(field_2.0, "c");
836
837 let field_1 = s
838 .remove_by_name("a")
839 .expect("Invalid name for `s.remove_by_name(name)`");
840
841 assert_eq!(s.field_len(), 0);
842 assert_eq!(field_1.0, "a");
843 }
844
845 #[test]
846 fn dynamic_struct_remove_if() {
847 let mut s = OtherStruct::default().to_dynamic_struct().unwrap();
848
849 assert_eq!(s.field_len(), 3);
850
851 let field_3_name = s
852 .name_at(2)
853 .expect("Invalid index for `s.field_at(index)`")
854 .to_owned();
855 let field_3 = s
856 .remove_if(|(name, _field)| name == field_3_name)
857 .expect("No valid name/field found for `s.remove_with(|(name, field)|{})");
858
859 assert_eq!(s.field_len(), 2);
860 assert_eq!(field_3.0, "c");
861 }
862
863 #[test]
864 fn dynamic_struct_remove_combo() {
865 let mut s = OtherStruct::default().to_dynamic_struct().unwrap();
866
867 assert_eq!(s.field_len(), 3);
868
869 let field_2 = s
870 .remove_at(
871 s.index_of_name("b")
872 .expect("Invalid name for `s.index_of_name(name)`"),
873 )
874 .expect("Invalid index for `s.remove_at(index)`");
875
876 assert_eq!(s.field_len(), 2);
877 assert_eq!(field_2.0, "b");
878
879 let field_3_name = s
880 .name_at(1)
881 .expect("Invalid name for s.name_at(index)")
882 .to_owned();
883
884 let field_3 = s
885 .remove_by_name(field_3_name.as_ref())
886 .expect("Invalid name for `s.remove_by_name(name)`");
887
888 assert_eq!(s.field_len(), 1);
889 assert_eq!(field_3.0, "c");
890
891 let field_1_name = s
892 .name_at(0)
893 .expect("Invalid name for `s.name_at(name)`")
894 .to_owned();
895 let field_1 = s
896 .remove_if(|(name, _field)| name == field_1_name)
897 .expect("No valid name/field found for `s.remove_with(|(name, field)|{})`");
898
899 assert_eq!(s.field_len(), 0);
900 assert_eq!(field_1.0, "a");
901 }
902
903 #[test]
904 fn next_index_increment() {
905 let my_struct = MyStruct::default();
906 let mut iter = my_struct.iter_fields();
907 iter.index = iter.len() - 1;
908 let prev_index = iter.index;
909 assert!(iter.next().is_some());
910 assert_eq!(prev_index, iter.index - 1);
911
912 let prev_index = iter.index;
914 assert!(iter.next().is_none());
915 assert_eq!(prev_index, iter.index);
916 assert!(iter.next().is_none());
917 assert_eq!(prev_index, iter.index);
918 }
919}