bevy_reflect/
struct_trait.rs

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
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    /// Clones the struct into a [`DynamicStruct`].
75    fn clone_dynamic(&self) -> DynamicStruct;
76
77    /// Will return `None` if [`TypeInfo`] is not available.
78    fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
79        self.get_represented_type_info()?.as_struct().ok()
80    }
81}
82
83/// A container for compile-time named struct info.
84#[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    /// Create a new [`StructInfo`].
98    ///
99    /// # Arguments
100    ///
101    /// * `fields`: The fields of this struct in the order they are defined
102    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    /// Sets the docstring for this struct.
124    #[cfg(feature = "documentation")]
125    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
126        Self { docs, ..self }
127    }
128
129    /// Sets the custom attributes for this struct.
130    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    /// A slice containing the names of all fields in order.
138    pub fn field_names(&self) -> &[&'static str] {
139        &self.field_names
140    }
141
142    /// Get the field with the given name.
143    pub fn field(&self, name: &str) -> Option<&NamedField> {
144        self.field_indices
145            .get(name)
146            .map(|index| &self.fields[*index])
147    }
148
149    /// Get the field at the given index.
150    pub fn field_at(&self, index: usize) -> Option<&NamedField> {
151        self.fields.get(index)
152    }
153
154    /// Get the index of the field with the given name.
155    pub fn index_of(&self, name: &str) -> Option<usize> {
156        self.field_indices.get(name).copied()
157    }
158
159    /// Iterate over the fields of this struct.
160    pub fn iter(&self) -> Iter<'_, NamedField> {
161        self.fields.iter()
162    }
163
164    /// The total number of fields in this struct.
165    pub fn field_len(&self) -> usize {
166        self.fields.len()
167    }
168
169    impl_type_methods!(ty);
170
171    /// The docstring of this struct, if any.
172    #[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
182/// An iterator over the field values of a struct.
183pub 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
214/// A convenience trait which combines fetching and downcasting of struct
215/// fields.
216///
217/// # Example
218///
219/// ```
220/// use bevy_reflect::{GetField, Reflect};
221///
222/// #[derive(Reflect)]
223/// struct Foo {
224///     bar: String,
225/// }
226///
227/// # fn main() {
228/// let mut foo = Foo { bar: "Hello, world!".to_string() };
229///
230/// foo.get_field_mut::<String>("bar").unwrap().truncate(5);
231/// assert_eq!(foo.get_field::<String>("bar"), Some(&"Hello".to_string()));
232/// # }
233/// ```
234pub trait GetField {
235    /// Returns a reference to the value of the field named `name`, downcast to
236    /// `T`.
237    fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
238
239    /// Returns a mutable reference to the value of the field named `name`,
240    /// downcast to `T`.
241    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/// A struct type which allows fields to be added at runtime.
269#[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    /// Sets the [type] to be represented by this `DynamicStruct`.
279    ///
280    /// # Panics
281    ///
282    /// Panics if the given [type] is not a [`TypeInfo::Struct`].
283    ///
284    /// [type]: TypeInfo
285    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    /// Inserts a field named `name` with value `value` into the struct.
298    ///
299    /// If the field already exists, it is overwritten.
300    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    /// Inserts a field named `name` with the typed value `value` into the struct.
317    ///
318    /// If the field already exists, it is overwritten.
319    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    /// Gets the index of the field with the given name.
324    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    /// Create a dynamic struct that doesn't represent a type from the
486    /// field name, field value pairs.
487    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/// Compares a [`Struct`] with a [`PartialReflect`] value.
515///
516/// Returns true if and only if all of the following are true:
517/// - `b` is a struct;
518/// - For each field in `a`, `b` contains a field with the same name and
519///   [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two field
520///   values.
521///
522/// Returns [`None`] if the comparison couldn't even be performed.
523#[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/// The default debug formatter for [`Struct`] types.
549///
550/// # Example
551/// ```
552/// use bevy_reflect::Reflect;
553/// #[derive(Reflect)]
554/// struct MyStruct {
555///   foo: usize
556/// }
557///
558/// let my_struct: &dyn Reflect = &MyStruct { foo: 123 };
559/// println!("{:#?}", my_struct);
560///
561/// // Output:
562///
563/// // MyStruct {
564/// //   foo: 123,
565/// // }
566/// ```
567#[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        // When None we should no longer increase index
605        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}