bevy_reflect/
struct_trait.rs

1use crate::generics::impl_generic_info_methods;
2use crate::{
3    attributes::{impl_custom_attribute_methods, CustomAttributes},
4    type_info::impl_type_methods,
5    ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
6    ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
7};
8use alloc::{borrow::Cow, boxed::Box, vec::Vec};
9use bevy_platform::collections::HashMap;
10use bevy_platform::sync::Arc;
11use bevy_reflect_derive::impl_type_path;
12use core::{
13    fmt::{Debug, Formatter},
14    slice::Iter,
15};
16
17/// A trait used to power [struct-like] operations via [reflection].
18///
19/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
20/// be dynamically addressed by both name and index.
21///
22/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a standard struct,
23/// this trait will be automatically implemented.
24/// This goes for [unit structs] as well.
25///
26/// # Example
27///
28/// ```
29/// use bevy_reflect::{PartialReflect, Reflect, Struct};
30///
31/// #[derive(Reflect)]
32/// struct Foo {
33///     bar: u32,
34/// }
35///
36/// let foo = Foo { bar: 123 };
37///
38/// assert_eq!(foo.field_len(), 1);
39/// assert_eq!(foo.name_at(0), Some("bar"));
40///
41/// let field: &dyn PartialReflect = foo.field("bar").unwrap();
42/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
43/// ```
44///
45/// [struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html
46/// [reflection]: crate
47/// [unit structs]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
48pub trait Struct: PartialReflect {
49    /// Returns a reference to the value of the field named `name` as a `&dyn
50    /// PartialReflect`.
51    fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
52
53    /// Returns a mutable reference to the value of the field named `name` as a
54    /// `&mut dyn PartialReflect`.
55    fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
56
57    /// Returns a reference to the value of the field with index `index` as a
58    /// `&dyn PartialReflect`.
59    fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
60
61    /// Returns a mutable reference to the value of the field with index `index`
62    /// as a `&mut dyn PartialReflect`.
63    fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
64
65    /// Returns the name of the field with index `index`.
66    fn name_at(&self, index: usize) -> Option<&str>;
67
68    /// Returns the number of fields in the struct.
69    fn field_len(&self) -> usize;
70
71    /// Returns an iterator over the values of the reflectable fields for this struct.
72    fn iter_fields(&self) -> FieldIter<'_>;
73
74    /// Creates a new [`DynamicStruct`] from this struct.
75    fn to_dynamic_struct(&self) -> DynamicStruct {
76        let mut dynamic_struct = DynamicStruct::default();
77        dynamic_struct.set_represented_type(self.get_represented_type_info());
78        for (i, value) in self.iter_fields().enumerate() {
79            dynamic_struct.insert_boxed(self.name_at(i).unwrap(), value.to_dynamic());
80        }
81        dynamic_struct
82    }
83
84    /// Will return `None` if [`TypeInfo`] is not available.
85    fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
86        self.get_represented_type_info()?.as_struct().ok()
87    }
88}
89
90/// A container for compile-time named struct info.
91#[derive(Clone, Debug)]
92pub struct StructInfo {
93    ty: Type,
94    generics: Generics,
95    fields: Box<[NamedField]>,
96    field_names: Box<[&'static str]>,
97    field_indices: HashMap<&'static str, usize>,
98    custom_attributes: Arc<CustomAttributes>,
99    #[cfg(feature = "documentation")]
100    docs: Option<&'static str>,
101}
102
103impl StructInfo {
104    /// Create a new [`StructInfo`].
105    ///
106    /// # Arguments
107    ///
108    /// * `fields`: The fields of this struct in the order they are defined
109    pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
110        let field_indices = fields
111            .iter()
112            .enumerate()
113            .map(|(index, field)| (field.name(), index))
114            .collect::<HashMap<_, _>>();
115
116        let field_names = fields.iter().map(NamedField::name).collect();
117
118        Self {
119            ty: Type::of::<T>(),
120            generics: Generics::new(),
121            fields: fields.to_vec().into_boxed_slice(),
122            field_names,
123            field_indices,
124            custom_attributes: Arc::new(CustomAttributes::default()),
125            #[cfg(feature = "documentation")]
126            docs: None,
127        }
128    }
129
130    /// Sets the docstring for this struct.
131    #[cfg(feature = "documentation")]
132    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
133        Self { docs, ..self }
134    }
135
136    /// Sets the custom attributes for this struct.
137    pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
138        Self {
139            custom_attributes: Arc::new(custom_attributes),
140            ..self
141        }
142    }
143
144    /// A slice containing the names of all fields in order.
145    pub fn field_names(&self) -> &[&'static str] {
146        &self.field_names
147    }
148
149    /// Get the field with the given name.
150    pub fn field(&self, name: &str) -> Option<&NamedField> {
151        self.field_indices
152            .get(name)
153            .map(|index| &self.fields[*index])
154    }
155
156    /// Get the field at the given index.
157    pub fn field_at(&self, index: usize) -> Option<&NamedField> {
158        self.fields.get(index)
159    }
160
161    /// Get the index of the field with the given name.
162    pub fn index_of(&self, name: &str) -> Option<usize> {
163        self.field_indices.get(name).copied()
164    }
165
166    /// Iterate over the fields of this struct.
167    pub fn iter(&self) -> Iter<'_, NamedField> {
168        self.fields.iter()
169    }
170
171    /// The total number of fields in this struct.
172    pub fn field_len(&self) -> usize {
173        self.fields.len()
174    }
175
176    impl_type_methods!(ty);
177
178    /// The docstring of this struct, if any.
179    #[cfg(feature = "documentation")]
180    pub fn docs(&self) -> Option<&'static str> {
181        self.docs
182    }
183
184    impl_custom_attribute_methods!(self.custom_attributes, "struct");
185
186    impl_generic_info_methods!(generics);
187}
188
189/// An iterator over the field values of a struct.
190pub struct FieldIter<'a> {
191    pub(crate) struct_val: &'a dyn Struct,
192    pub(crate) index: usize,
193}
194
195impl<'a> FieldIter<'a> {
196    /// Creates a new [`FieldIter`].
197    pub fn new(value: &'a dyn Struct) -> Self {
198        FieldIter {
199            struct_val: value,
200            index: 0,
201        }
202    }
203}
204
205impl<'a> Iterator for FieldIter<'a> {
206    type Item = &'a dyn PartialReflect;
207
208    fn next(&mut self) -> Option<Self::Item> {
209        let value = self.struct_val.field_at(self.index);
210        self.index += value.is_some() as usize;
211        value
212    }
213
214    fn size_hint(&self) -> (usize, Option<usize>) {
215        let size = self.struct_val.field_len();
216        (size, Some(size))
217    }
218}
219
220impl<'a> ExactSizeIterator for FieldIter<'a> {}
221
222/// A convenience trait which combines fetching and downcasting of struct
223/// fields.
224///
225/// # Example
226///
227/// ```
228/// use bevy_reflect::{GetField, Reflect};
229///
230/// #[derive(Reflect)]
231/// struct Foo {
232///     bar: String,
233/// }
234///
235/// # fn main() {
236/// let mut foo = Foo { bar: "Hello, world!".to_string() };
237///
238/// foo.get_field_mut::<String>("bar").unwrap().truncate(5);
239/// assert_eq!(foo.get_field::<String>("bar"), Some(&"Hello".to_string()));
240/// # }
241/// ```
242pub trait GetField {
243    /// Returns a reference to the value of the field named `name`, downcast to
244    /// `T`.
245    fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
246
247    /// Returns a mutable reference to the value of the field named `name`,
248    /// downcast to `T`.
249    fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
250}
251
252impl<S: Struct> GetField for S {
253    fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
254        self.field(name)
255            .and_then(|value| value.try_downcast_ref::<T>())
256    }
257
258    fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
259        self.field_mut(name)
260            .and_then(|value| value.try_downcast_mut::<T>())
261    }
262}
263
264impl GetField for dyn Struct {
265    fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
266        self.field(name)
267            .and_then(|value| value.try_downcast_ref::<T>())
268    }
269
270    fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
271        self.field_mut(name)
272            .and_then(|value| value.try_downcast_mut::<T>())
273    }
274}
275
276/// A struct type which allows fields to be added at runtime.
277#[derive(Default)]
278pub struct DynamicStruct {
279    represented_type: Option<&'static TypeInfo>,
280    fields: Vec<Box<dyn PartialReflect>>,
281    field_names: Vec<Cow<'static, str>>,
282    field_indices: HashMap<Cow<'static, str>, usize>,
283}
284
285impl DynamicStruct {
286    /// Sets the [type] to be represented by this `DynamicStruct`.
287    ///
288    /// # Panics
289    ///
290    /// Panics if the given [type] is not a [`TypeInfo::Struct`].
291    ///
292    /// [type]: TypeInfo
293    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
294        if let Some(represented_type) = represented_type {
295            assert!(
296                matches!(represented_type, TypeInfo::Struct(_)),
297                "expected TypeInfo::Struct but received: {represented_type:?}"
298            );
299        }
300
301        self.represented_type = represented_type;
302    }
303
304    /// Inserts a field named `name` with value `value` into the struct.
305    ///
306    /// If the field already exists, it is overwritten.
307    pub fn insert_boxed<'a>(
308        &mut self,
309        name: impl Into<Cow<'a, str>>,
310        value: Box<dyn PartialReflect>,
311    ) {
312        let name: Cow<str> = name.into();
313        if let Some(index) = self.field_indices.get(&name) {
314            self.fields[*index] = value;
315        } else {
316            self.fields.push(value);
317            self.field_indices
318                .insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
319            self.field_names.push(Cow::Owned(name.into_owned()));
320        }
321    }
322
323    /// Inserts a field named `name` with the typed value `value` into the struct.
324    ///
325    /// If the field already exists, it is overwritten.
326    pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, value: T) {
327        self.insert_boxed(name, Box::new(value));
328    }
329
330    /// Gets the index of the field with the given name.
331    pub fn index_of(&self, name: &str) -> Option<usize> {
332        self.field_indices.get(name).copied()
333    }
334}
335
336impl Struct for DynamicStruct {
337    #[inline]
338    fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
339        self.field_indices
340            .get(name)
341            .map(|index| &*self.fields[*index])
342    }
343
344    #[inline]
345    fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
346        if let Some(index) = self.field_indices.get(name) {
347            Some(&mut *self.fields[*index])
348        } else {
349            None
350        }
351    }
352
353    #[inline]
354    fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
355        self.fields.get(index).map(|value| &**value)
356    }
357
358    #[inline]
359    fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
360        self.fields.get_mut(index).map(|value| &mut **value)
361    }
362
363    #[inline]
364    fn name_at(&self, index: usize) -> Option<&str> {
365        self.field_names.get(index).map(AsRef::as_ref)
366    }
367
368    #[inline]
369    fn field_len(&self) -> usize {
370        self.fields.len()
371    }
372
373    #[inline]
374    fn iter_fields(&self) -> FieldIter<'_> {
375        FieldIter {
376            struct_val: self,
377            index: 0,
378        }
379    }
380}
381
382impl PartialReflect for DynamicStruct {
383    #[inline]
384    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
385        self.represented_type
386    }
387
388    #[inline]
389    fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
390        self
391    }
392
393    #[inline]
394    fn as_partial_reflect(&self) -> &dyn PartialReflect {
395        self
396    }
397
398    #[inline]
399    fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
400        self
401    }
402
403    fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
404        Err(self)
405    }
406    fn try_as_reflect(&self) -> Option<&dyn Reflect> {
407        None
408    }
409    fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
410        None
411    }
412
413    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
414        let struct_value = value.reflect_ref().as_struct()?;
415
416        for (i, value) in struct_value.iter_fields().enumerate() {
417            let name = struct_value.name_at(i).unwrap();
418            if let Some(v) = self.field_mut(name) {
419                v.try_apply(value)?;
420            }
421        }
422
423        Ok(())
424    }
425
426    #[inline]
427    fn reflect_kind(&self) -> ReflectKind {
428        ReflectKind::Struct
429    }
430
431    #[inline]
432    fn reflect_ref(&self) -> ReflectRef<'_> {
433        ReflectRef::Struct(self)
434    }
435
436    #[inline]
437    fn reflect_mut(&mut self) -> ReflectMut<'_> {
438        ReflectMut::Struct(self)
439    }
440
441    #[inline]
442    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
443        ReflectOwned::Struct(self)
444    }
445
446    fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
447        struct_partial_eq(self, value)
448    }
449
450    fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
451        write!(f, "DynamicStruct(")?;
452        struct_debug(self, f)?;
453        write!(f, ")")
454    }
455
456    #[inline]
457    fn is_dynamic(&self) -> bool {
458        true
459    }
460}
461
462impl_type_path!((in bevy_reflect) DynamicStruct);
463
464impl Debug for DynamicStruct {
465    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
466        self.debug(f)
467    }
468}
469
470impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
471where
472    N: Into<Cow<'a, str>>,
473{
474    /// Create a dynamic struct that doesn't represent a type from the
475    /// field name, field value pairs.
476    fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
477        let mut dynamic_struct = Self::default();
478        for (name, value) in fields.into_iter() {
479            dynamic_struct.insert_boxed(name, value);
480        }
481        dynamic_struct
482    }
483}
484
485impl IntoIterator for DynamicStruct {
486    type Item = Box<dyn PartialReflect>;
487    type IntoIter = alloc::vec::IntoIter<Self::Item>;
488
489    fn into_iter(self) -> Self::IntoIter {
490        self.fields.into_iter()
491    }
492}
493
494impl<'a> IntoIterator for &'a DynamicStruct {
495    type Item = &'a dyn PartialReflect;
496    type IntoIter = FieldIter<'a>;
497
498    fn into_iter(self) -> Self::IntoIter {
499        self.iter_fields()
500    }
501}
502
503/// Compares a [`Struct`] with a [`PartialReflect`] value.
504///
505/// Returns true if and only if all of the following are true:
506/// - `b` is a struct;
507/// - For each field in `a`, `b` contains a field with the same name and
508///   [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
509///   values.
510///
511/// Returns [`None`] if the comparison couldn't even be performed.
512#[inline]
513pub fn struct_partial_eq<S: Struct + ?Sized>(a: &S, b: &dyn PartialReflect) -> Option<bool> {
514    let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
515        return Some(false);
516    };
517
518    if a.field_len() != struct_value.field_len() {
519        return Some(false);
520    }
521
522    for (i, value) in struct_value.iter_fields().enumerate() {
523        let name = struct_value.name_at(i).unwrap();
524        if let Some(field_value) = a.field(name) {
525            let eq_result = field_value.reflect_partial_eq(value);
526            if let failed @ (Some(false) | None) = eq_result {
527                return failed;
528            }
529        } else {
530            return Some(false);
531        }
532    }
533
534    Some(true)
535}
536
537/// The default debug formatter for [`Struct`] types.
538///
539/// # Example
540/// ```
541/// use bevy_reflect::Reflect;
542/// #[derive(Reflect)]
543/// struct MyStruct {
544///   foo: usize
545/// }
546///
547/// let my_struct: &dyn Reflect = &MyStruct { foo: 123 };
548/// println!("{:#?}", my_struct);
549///
550/// // Output:
551///
552/// // MyStruct {
553/// //   foo: 123,
554/// // }
555/// ```
556#[inline]
557pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
558    let mut debug = f.debug_struct(
559        dyn_struct
560            .get_represented_type_info()
561            .map(TypeInfo::type_path)
562            .unwrap_or("_"),
563    );
564    for field_index in 0..dyn_struct.field_len() {
565        let field = dyn_struct.field_at(field_index).unwrap();
566        debug.field(
567            dyn_struct.name_at(field_index).unwrap(),
568            &field as &dyn Debug,
569        );
570    }
571    debug.finish()
572}
573
574#[cfg(test)]
575mod tests {
576    use crate::*;
577    #[derive(Reflect, Default)]
578    struct MyStruct {
579        a: (),
580        b: (),
581        c: (),
582    }
583    #[test]
584    fn next_index_increment() {
585        let my_struct = MyStruct::default();
586        let mut iter = my_struct.iter_fields();
587        iter.index = iter.len() - 1;
588        let prev_index = iter.index;
589        assert!(iter.next().is_some());
590        assert_eq!(prev_index, iter.index - 1);
591
592        // When None we should no longer increase index
593        let prev_index = iter.index;
594        assert!(iter.next().is_none());
595        assert_eq!(prev_index, iter.index);
596        assert!(iter.next().is_none());
597        assert_eq!(prev_index, iter.index);
598    }
599}