1use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
2use crate::{
3 self as bevy_reflect, ApplyError, NamedField, Reflect, ReflectKind, ReflectMut, ReflectOwned,
4 ReflectRef, TypeInfo, TypePath, TypePathTable,
5};
6use bevy_reflect_derive::impl_type_path;
7use bevy_utils::HashMap;
8use std::fmt::{Debug, Formatter};
9use std::sync::Arc;
10use std::{
11 any::{Any, TypeId},
12 borrow::Cow,
13 slice::Iter,
14};
15
16pub trait Struct: Reflect {
49 fn field(&self, name: &str) -> Option<&dyn Reflect>;
52
53 fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
56
57 fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
60
61 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
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
78#[derive(Clone, Debug)]
80pub struct StructInfo {
81 type_path: TypePathTable,
82 type_id: TypeId,
83 fields: Box<[NamedField]>,
84 field_names: Box<[&'static str]>,
85 field_indices: HashMap<&'static str, usize>,
86 custom_attributes: Arc<CustomAttributes>,
87 #[cfg(feature = "documentation")]
88 docs: Option<&'static str>,
89}
90
91impl StructInfo {
92 pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
99 let field_indices = fields
100 .iter()
101 .enumerate()
102 .map(|(index, field)| (field.name(), index))
103 .collect::<HashMap<_, _>>();
104
105 let field_names = fields.iter().map(|field| field.name()).collect();
106
107 Self {
108 type_path: TypePathTable::of::<T>(),
109 type_id: TypeId::of::<T>(),
110 fields: fields.to_vec().into_boxed_slice(),
111 field_names,
112 field_indices,
113 custom_attributes: Arc::new(CustomAttributes::default()),
114 #[cfg(feature = "documentation")]
115 docs: None,
116 }
117 }
118
119 #[cfg(feature = "documentation")]
121 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
122 Self { docs, ..self }
123 }
124
125 pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
127 Self {
128 custom_attributes: Arc::new(custom_attributes),
129 ..self
130 }
131 }
132
133 pub fn field_names(&self) -> &[&'static str] {
135 &self.field_names
136 }
137
138 pub fn field(&self, name: &str) -> Option<&NamedField> {
140 self.field_indices
141 .get(name)
142 .map(|index| &self.fields[*index])
143 }
144
145 pub fn field_at(&self, index: usize) -> Option<&NamedField> {
147 self.fields.get(index)
148 }
149
150 pub fn index_of(&self, name: &str) -> Option<usize> {
152 self.field_indices.get(name).copied()
153 }
154
155 pub fn iter(&self) -> Iter<'_, NamedField> {
157 self.fields.iter()
158 }
159
160 pub fn field_len(&self) -> usize {
162 self.fields.len()
163 }
164
165 pub fn type_path_table(&self) -> &TypePathTable {
169 &self.type_path
170 }
171
172 pub fn type_path(&self) -> &'static str {
179 self.type_path_table().path()
180 }
181
182 pub fn type_id(&self) -> TypeId {
184 self.type_id
185 }
186
187 pub fn is<T: Any>(&self) -> bool {
189 TypeId::of::<T>() == self.type_id
190 }
191
192 #[cfg(feature = "documentation")]
194 pub fn docs(&self) -> Option<&'static str> {
195 self.docs
196 }
197
198 impl_custom_attribute_methods!(self.custom_attributes, "struct");
199}
200
201pub struct FieldIter<'a> {
203 pub(crate) struct_val: &'a dyn Struct,
204 pub(crate) index: usize,
205}
206
207impl<'a> FieldIter<'a> {
208 pub fn new(value: &'a dyn Struct) -> Self {
209 FieldIter {
210 struct_val: value,
211 index: 0,
212 }
213 }
214}
215
216impl<'a> Iterator for FieldIter<'a> {
217 type Item = &'a dyn Reflect;
218
219 fn next(&mut self) -> Option<Self::Item> {
220 let value = self.struct_val.field_at(self.index);
221 self.index += value.is_some() as usize;
222 value
223 }
224
225 fn size_hint(&self) -> (usize, Option<usize>) {
226 let size = self.struct_val.field_len();
227 (size, Some(size))
228 }
229}
230
231impl<'a> ExactSizeIterator for FieldIter<'a> {}
232
233pub trait GetField {
254 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
257
258 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
261}
262
263impl<S: Struct> GetField for S {
264 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
265 self.field(name).and_then(|value| value.downcast_ref::<T>())
266 }
267
268 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
269 self.field_mut(name)
270 .and_then(|value| value.downcast_mut::<T>())
271 }
272}
273
274impl GetField for dyn Struct {
275 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
276 self.field(name).and_then(|value| value.downcast_ref::<T>())
277 }
278
279 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
280 self.field_mut(name)
281 .and_then(|value| value.downcast_mut::<T>())
282 }
283}
284
285#[derive(Default)]
287pub struct DynamicStruct {
288 represented_type: Option<&'static TypeInfo>,
289 fields: Vec<Box<dyn Reflect>>,
290 field_names: Vec<Cow<'static, str>>,
291 field_indices: HashMap<Cow<'static, str>, usize>,
292}
293
294impl DynamicStruct {
295 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
303 if let Some(represented_type) = represented_type {
304 assert!(
305 matches!(represented_type, TypeInfo::Struct(_)),
306 "expected TypeInfo::Struct but received: {:?}",
307 represented_type
308 );
309 }
310
311 self.represented_type = represented_type;
312 }
313
314 pub fn insert_boxed<'a>(&mut self, name: impl Into<Cow<'a, str>>, value: Box<dyn Reflect>) {
318 let name: Cow<str> = name.into();
319 if let Some(index) = self.field_indices.get(&name) {
320 self.fields[*index] = value;
321 } else {
322 self.fields.push(value);
323 self.field_indices
324 .insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
325 self.field_names.push(Cow::Owned(name.into_owned()));
326 }
327 }
328
329 pub fn insert<'a, T: Reflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
333 self.insert_boxed(name, Box::new(value));
334 }
335
336 pub fn index_of(&self, name: &str) -> Option<usize> {
338 self.field_indices.get(name).copied()
339 }
340}
341
342impl Struct for DynamicStruct {
343 #[inline]
344 fn field(&self, name: &str) -> Option<&dyn Reflect> {
345 self.field_indices
346 .get(name)
347 .map(|index| &*self.fields[*index])
348 }
349
350 #[inline]
351 fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
352 if let Some(index) = self.field_indices.get(name) {
353 Some(&mut *self.fields[*index])
354 } else {
355 None
356 }
357 }
358
359 #[inline]
360 fn field_at(&self, index: usize) -> Option<&dyn Reflect> {
361 self.fields.get(index).map(|value| &**value)
362 }
363
364 #[inline]
365 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
366 self.fields.get_mut(index).map(|value| &mut **value)
367 }
368
369 #[inline]
370 fn name_at(&self, index: usize) -> Option<&str> {
371 self.field_names.get(index).map(|name| name.as_ref())
372 }
373
374 #[inline]
375 fn field_len(&self) -> usize {
376 self.fields.len()
377 }
378
379 #[inline]
380 fn iter_fields(&self) -> FieldIter {
381 FieldIter {
382 struct_val: self,
383 index: 0,
384 }
385 }
386
387 fn clone_dynamic(&self) -> DynamicStruct {
388 DynamicStruct {
389 represented_type: self.get_represented_type_info(),
390 field_names: self.field_names.clone(),
391 field_indices: self.field_indices.clone(),
392 fields: self
393 .fields
394 .iter()
395 .map(|value| value.clone_value())
396 .collect(),
397 }
398 }
399}
400
401impl Reflect for DynamicStruct {
402 #[inline]
403 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
404 self.represented_type
405 }
406
407 #[inline]
408 fn into_any(self: Box<Self>) -> Box<dyn Any> {
409 self
410 }
411
412 #[inline]
413 fn as_any(&self) -> &dyn Any {
414 self
415 }
416
417 #[inline]
418 fn as_any_mut(&mut self) -> &mut dyn Any {
419 self
420 }
421
422 #[inline]
423 fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
424 self
425 }
426
427 #[inline]
428 fn as_reflect(&self) -> &dyn Reflect {
429 self
430 }
431
432 #[inline]
433 fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
434 self
435 }
436
437 fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
438 if let ReflectRef::Struct(struct_value) = value.reflect_ref() {
439 for (i, value) in struct_value.iter_fields().enumerate() {
440 let name = struct_value.name_at(i).unwrap();
441 if let Some(v) = self.field_mut(name) {
442 v.try_apply(value)?;
443 }
444 }
445 } else {
446 return Err(ApplyError::MismatchedKinds {
447 from_kind: value.reflect_kind(),
448 to_kind: ReflectKind::Struct,
449 });
450 }
451 Ok(())
452 }
453
454 #[inline]
455 fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
456 *self = value.take()?;
457 Ok(())
458 }
459
460 #[inline]
461 fn reflect_kind(&self) -> ReflectKind {
462 ReflectKind::Struct
463 }
464
465 #[inline]
466 fn reflect_ref(&self) -> ReflectRef {
467 ReflectRef::Struct(self)
468 }
469
470 #[inline]
471 fn reflect_mut(&mut self) -> ReflectMut {
472 ReflectMut::Struct(self)
473 }
474
475 #[inline]
476 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
477 ReflectOwned::Struct(self)
478 }
479
480 #[inline]
481 fn clone_value(&self) -> Box<dyn Reflect> {
482 Box::new(self.clone_dynamic())
483 }
484
485 fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
486 struct_partial_eq(self, value)
487 }
488
489 fn debug(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
490 write!(f, "DynamicStruct(")?;
491 struct_debug(self, f)?;
492 write!(f, ")")
493 }
494
495 #[inline]
496 fn is_dynamic(&self) -> bool {
497 true
498 }
499}
500
501impl_type_path!((in bevy_reflect) DynamicStruct);
502
503impl Debug for DynamicStruct {
504 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
505 self.debug(f)
506 }
507}
508
509#[inline]
519pub fn struct_partial_eq<S: Struct>(a: &S, b: &dyn Reflect) -> Option<bool> {
520 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
521 return Some(false);
522 };
523
524 if a.field_len() != struct_value.field_len() {
525 return Some(false);
526 }
527
528 for (i, value) in struct_value.iter_fields().enumerate() {
529 let name = struct_value.name_at(i).unwrap();
530 if let Some(field_value) = a.field(name) {
531 let eq_result = field_value.reflect_partial_eq(value);
532 if let failed @ (Some(false) | None) = eq_result {
533 return failed;
534 }
535 } else {
536 return Some(false);
537 }
538 }
539
540 Some(true)
541}
542
543#[inline]
563pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> std::fmt::Result {
564 let mut debug = f.debug_struct(
565 dyn_struct
566 .get_represented_type_info()
567 .map(|s| s.type_path())
568 .unwrap_or("_"),
569 );
570 for field_index in 0..dyn_struct.field_len() {
571 let field = dyn_struct.field_at(field_index).unwrap();
572 debug.field(
573 dyn_struct.name_at(field_index).unwrap(),
574 &field as &dyn Debug,
575 );
576 }
577 debug.finish()
578}
579
580#[cfg(test)]
581mod tests {
582 use crate as bevy_reflect;
583 use crate::*;
584 #[derive(Reflect, Default)]
585 struct MyStruct {
586 a: (),
587 b: (),
588 c: (),
589 }
590 #[test]
591 fn next_index_increment() {
592 let my_struct = MyStruct::default();
593 let mut iter = my_struct.iter_fields();
594 iter.index = iter.len() - 1;
595 let prev_index = iter.index;
596 assert!(iter.next().is_some());
597 assert_eq!(prev_index, iter.index - 1);
598
599 let prev_index = iter.index;
601 assert!(iter.next().is_none());
602 assert_eq!(prev_index, iter.index);
603 assert!(iter.next().is_none());
604 assert_eq!(prev_index, iter.index);
605 }
606}