bevy_reflect/
tuple_struct.rs

1use bevy_reflect_derive::impl_type_path;
2
3use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
4use crate::{
5    self as bevy_reflect, ApplyError, DynamicTuple, Reflect, ReflectKind, ReflectMut, ReflectOwned,
6    ReflectRef, Tuple, TypeInfo, TypePath, TypePathTable, UnnamedField,
7};
8use std::any::{Any, TypeId};
9use std::fmt::{Debug, Formatter};
10use std::slice::Iter;
11use std::sync::Arc;
12
13/// A trait used to power [tuple struct-like] operations via [reflection].
14///
15/// This trait uses the [`Reflect`] trait to allow implementors to have their fields
16/// be dynamically addressed by index.
17///
18/// When using [`#[derive(Reflect)]`](derive@crate::Reflect) on a tuple struct,
19/// this trait will be automatically implemented.
20///
21/// # Example
22///
23/// ```
24/// use bevy_reflect::{Reflect, TupleStruct};
25///
26/// #[derive(Reflect)]
27/// struct Foo(u32);
28///
29/// let foo = Foo(123);
30///
31/// assert_eq!(foo.field_len(), 1);
32///
33/// let field: &dyn Reflect = foo.field(0).unwrap();
34/// assert_eq!(field.downcast_ref::<u32>(), Some(&123));
35/// ```
36///
37/// [tuple struct-like]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types
38/// [reflection]: crate
39pub trait TupleStruct: Reflect {
40    /// Returns a reference to the value of the field with index `index` as a
41    /// `&dyn Reflect`.
42    fn field(&self, index: usize) -> Option<&dyn Reflect>;
43
44    /// Returns a mutable reference to the value of the field with index `index`
45    /// as a `&mut dyn Reflect`.
46    fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
47
48    /// Returns the number of fields in the tuple struct.
49    fn field_len(&self) -> usize;
50
51    /// Returns an iterator over the values of the tuple struct's fields.
52    fn iter_fields(&self) -> TupleStructFieldIter;
53
54    /// Clones the struct into a [`DynamicTupleStruct`].
55    fn clone_dynamic(&self) -> DynamicTupleStruct;
56}
57
58/// A container for compile-time tuple struct info.
59#[derive(Clone, Debug)]
60pub struct TupleStructInfo {
61    type_path: TypePathTable,
62    type_id: TypeId,
63    fields: Box<[UnnamedField]>,
64    custom_attributes: Arc<CustomAttributes>,
65    #[cfg(feature = "documentation")]
66    docs: Option<&'static str>,
67}
68
69impl TupleStructInfo {
70    /// Create a new [`TupleStructInfo`].
71    ///
72    /// # Arguments
73    ///
74    /// * `fields`: The fields of this struct in the order they are defined
75    ///
76    pub fn new<T: Reflect + TypePath>(fields: &[UnnamedField]) -> Self {
77        Self {
78            type_path: TypePathTable::of::<T>(),
79            type_id: TypeId::of::<T>(),
80            fields: fields.to_vec().into_boxed_slice(),
81            custom_attributes: Arc::new(CustomAttributes::default()),
82            #[cfg(feature = "documentation")]
83            docs: None,
84        }
85    }
86
87    /// Sets the docstring for this struct.
88    #[cfg(feature = "documentation")]
89    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
90        Self { docs, ..self }
91    }
92
93    /// Sets the custom attributes for this struct.
94    pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
95        Self {
96            custom_attributes: Arc::new(custom_attributes),
97            ..self
98        }
99    }
100
101    /// Get the field at the given index.
102    pub fn field_at(&self, index: usize) -> Option<&UnnamedField> {
103        self.fields.get(index)
104    }
105
106    /// Iterate over the fields of this struct.
107    pub fn iter(&self) -> Iter<'_, UnnamedField> {
108        self.fields.iter()
109    }
110
111    /// The total number of fields in this struct.
112    pub fn field_len(&self) -> usize {
113        self.fields.len()
114    }
115
116    /// A representation of the type path of the struct.
117    ///
118    /// Provides dynamic access to all methods on [`TypePath`].
119    pub fn type_path_table(&self) -> &TypePathTable {
120        &self.type_path
121    }
122
123    /// The [stable, full type path] of the struct.
124    ///
125    /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
126    ///
127    /// [stable, full type path]: TypePath
128    /// [`type_path_table`]: Self::type_path_table
129    pub fn type_path(&self) -> &'static str {
130        self.type_path_table().path()
131    }
132
133    /// The [`TypeId`] of the tuple struct.
134    pub fn type_id(&self) -> TypeId {
135        self.type_id
136    }
137
138    /// Check if the given type matches the tuple struct type.
139    pub fn is<T: Any>(&self) -> bool {
140        TypeId::of::<T>() == self.type_id
141    }
142
143    /// The docstring of this struct, if any.
144    #[cfg(feature = "documentation")]
145    pub fn docs(&self) -> Option<&'static str> {
146        self.docs
147    }
148
149    impl_custom_attribute_methods!(self.custom_attributes, "struct");
150}
151
152/// An iterator over the field values of a tuple struct.
153pub struct TupleStructFieldIter<'a> {
154    pub(crate) tuple_struct: &'a dyn TupleStruct,
155    pub(crate) index: usize,
156}
157
158impl<'a> TupleStructFieldIter<'a> {
159    pub fn new(value: &'a dyn TupleStruct) -> Self {
160        TupleStructFieldIter {
161            tuple_struct: value,
162            index: 0,
163        }
164    }
165}
166
167impl<'a> Iterator for TupleStructFieldIter<'a> {
168    type Item = &'a dyn Reflect;
169
170    fn next(&mut self) -> Option<Self::Item> {
171        let value = self.tuple_struct.field(self.index);
172        self.index += value.is_some() as usize;
173        value
174    }
175
176    fn size_hint(&self) -> (usize, Option<usize>) {
177        let size = self.tuple_struct.field_len();
178        (size, Some(size))
179    }
180}
181
182impl<'a> ExactSizeIterator for TupleStructFieldIter<'a> {}
183
184/// A convenience trait which combines fetching and downcasting of tuple
185/// struct fields.
186///
187/// # Example
188///
189/// ```
190/// use bevy_reflect::{GetTupleStructField, Reflect};
191///
192/// #[derive(Reflect)]
193/// struct Foo(String);
194///
195/// # fn main() {
196/// let mut foo = Foo("Hello, world!".to_string());
197///
198/// foo.get_field_mut::<String>(0).unwrap().truncate(5);
199/// assert_eq!(foo.get_field::<String>(0), Some(&"Hello".to_string()));
200/// # }
201/// ```
202pub trait GetTupleStructField {
203    /// Returns a reference to the value of the field with index `index`,
204    /// downcast to `T`.
205    fn get_field<T: Reflect>(&self, index: usize) -> Option<&T>;
206
207    /// Returns a mutable reference to the value of the field with index
208    /// `index`, downcast to `T`.
209    fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T>;
210}
211
212impl<S: TupleStruct> GetTupleStructField for S {
213    fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
214        self.field(index)
215            .and_then(|value| value.downcast_ref::<T>())
216    }
217
218    fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
219        self.field_mut(index)
220            .and_then(|value| value.downcast_mut::<T>())
221    }
222}
223
224impl GetTupleStructField for dyn TupleStruct {
225    fn get_field<T: Reflect>(&self, index: usize) -> Option<&T> {
226        self.field(index)
227            .and_then(|value| value.downcast_ref::<T>())
228    }
229
230    fn get_field_mut<T: Reflect>(&mut self, index: usize) -> Option<&mut T> {
231        self.field_mut(index)
232            .and_then(|value| value.downcast_mut::<T>())
233    }
234}
235
236/// A tuple struct which allows fields to be added at runtime.
237#[derive(Default)]
238pub struct DynamicTupleStruct {
239    represented_type: Option<&'static TypeInfo>,
240    fields: Vec<Box<dyn Reflect>>,
241}
242
243impl DynamicTupleStruct {
244    /// Sets the [type] to be represented by this `DynamicTupleStruct`.
245    ///
246    /// # Panics
247    ///
248    /// Panics if the given [type] is not a [`TypeInfo::TupleStruct`].
249    ///
250    /// [type]: TypeInfo
251    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
252        if let Some(represented_type) = represented_type {
253            assert!(
254                matches!(represented_type, TypeInfo::TupleStruct(_)),
255                "expected TypeInfo::TupleStruct but received: {:?}",
256                represented_type
257            );
258        }
259
260        self.represented_type = represented_type;
261    }
262
263    /// Appends an element with value `value` to the tuple struct.
264    pub fn insert_boxed(&mut self, value: Box<dyn Reflect>) {
265        self.fields.push(value);
266    }
267
268    /// Appends a typed element with value `value` to the tuple struct.
269    pub fn insert<T: Reflect>(&mut self, value: T) {
270        self.insert_boxed(Box::new(value));
271    }
272}
273
274impl TupleStruct for DynamicTupleStruct {
275    #[inline]
276    fn field(&self, index: usize) -> Option<&dyn Reflect> {
277        self.fields.get(index).map(|field| &**field)
278    }
279
280    #[inline]
281    fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
282        self.fields.get_mut(index).map(|field| &mut **field)
283    }
284
285    #[inline]
286    fn field_len(&self) -> usize {
287        self.fields.len()
288    }
289
290    #[inline]
291    fn iter_fields(&self) -> TupleStructFieldIter {
292        TupleStructFieldIter {
293            tuple_struct: self,
294            index: 0,
295        }
296    }
297
298    fn clone_dynamic(&self) -> DynamicTupleStruct {
299        DynamicTupleStruct {
300            represented_type: self.represented_type,
301            fields: self
302                .fields
303                .iter()
304                .map(|value| value.clone_value())
305                .collect(),
306        }
307    }
308}
309
310impl Reflect for DynamicTupleStruct {
311    #[inline]
312    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
313        self.represented_type
314    }
315
316    #[inline]
317    fn into_any(self: Box<Self>) -> Box<dyn Any> {
318        self
319    }
320
321    #[inline]
322    fn as_any(&self) -> &dyn Any {
323        self
324    }
325
326    #[inline]
327    fn as_any_mut(&mut self) -> &mut dyn Any {
328        self
329    }
330
331    #[inline]
332    fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
333        self
334    }
335
336    #[inline]
337    fn as_reflect(&self) -> &dyn Reflect {
338        self
339    }
340
341    #[inline]
342    fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
343        self
344    }
345
346    fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
347        if let ReflectRef::TupleStruct(tuple_struct) = value.reflect_ref() {
348            for (i, value) in tuple_struct.iter_fields().enumerate() {
349                if let Some(v) = self.field_mut(i) {
350                    v.try_apply(value)?;
351                }
352            }
353        } else {
354            return Err(ApplyError::MismatchedKinds {
355                from_kind: value.reflect_kind(),
356                to_kind: ReflectKind::TupleStruct,
357            });
358        }
359        Ok(())
360    }
361
362    #[inline]
363    fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
364        *self = value.take()?;
365        Ok(())
366    }
367
368    #[inline]
369    fn reflect_kind(&self) -> ReflectKind {
370        ReflectKind::TupleStruct
371    }
372
373    #[inline]
374    fn reflect_ref(&self) -> ReflectRef {
375        ReflectRef::TupleStruct(self)
376    }
377
378    #[inline]
379    fn reflect_mut(&mut self) -> ReflectMut {
380        ReflectMut::TupleStruct(self)
381    }
382
383    #[inline]
384    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
385        ReflectOwned::TupleStruct(self)
386    }
387
388    #[inline]
389    fn clone_value(&self) -> Box<dyn Reflect> {
390        Box::new(self.clone_dynamic())
391    }
392
393    #[inline]
394    fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
395        tuple_struct_partial_eq(self, value)
396    }
397
398    fn debug(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
399        write!(f, "DynamicTupleStruct(")?;
400        tuple_struct_debug(self, f)?;
401        write!(f, ")")
402    }
403
404    #[inline]
405    fn is_dynamic(&self) -> bool {
406        true
407    }
408}
409
410impl_type_path!((in bevy_reflect) DynamicTupleStruct);
411
412impl Debug for DynamicTupleStruct {
413    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
414        self.debug(f)
415    }
416}
417
418impl From<DynamicTuple> for DynamicTupleStruct {
419    fn from(value: DynamicTuple) -> Self {
420        Self {
421            represented_type: None,
422            fields: Box::new(value).drain(),
423        }
424    }
425}
426
427/// Compares a [`TupleStruct`] with a [`Reflect`] value.
428///
429/// Returns true if and only if all of the following are true:
430/// - `b` is a tuple struct;
431/// - `b` has the same number of fields as `a`;
432/// - [`Reflect::reflect_partial_eq`] returns `Some(true)` for pairwise fields of `a` and `b`.
433///
434/// Returns [`None`] if the comparison couldn't even be performed.
435#[inline]
436pub fn tuple_struct_partial_eq<S: TupleStruct>(a: &S, b: &dyn Reflect) -> Option<bool> {
437    let ReflectRef::TupleStruct(tuple_struct) = b.reflect_ref() else {
438        return Some(false);
439    };
440
441    if a.field_len() != tuple_struct.field_len() {
442        return Some(false);
443    }
444
445    for (i, value) in tuple_struct.iter_fields().enumerate() {
446        if let Some(field_value) = a.field(i) {
447            let eq_result = field_value.reflect_partial_eq(value);
448            if let failed @ (Some(false) | None) = eq_result {
449                return failed;
450            }
451        } else {
452            return Some(false);
453        }
454    }
455
456    Some(true)
457}
458
459/// The default debug formatter for [`TupleStruct`] types.
460///
461/// # Example
462/// ```
463/// use bevy_reflect::Reflect;
464/// #[derive(Reflect)]
465/// struct MyTupleStruct(usize);
466///
467/// let my_tuple_struct: &dyn Reflect = &MyTupleStruct(123);
468/// println!("{:#?}", my_tuple_struct);
469///
470/// // Output:
471///
472/// // MyTupleStruct (
473/// //   123,
474/// // )
475/// ```
476#[inline]
477pub fn tuple_struct_debug(
478    dyn_tuple_struct: &dyn TupleStruct,
479    f: &mut Formatter<'_>,
480) -> std::fmt::Result {
481    let mut debug = f.debug_tuple(
482        dyn_tuple_struct
483            .get_represented_type_info()
484            .map(|s| s.type_path())
485            .unwrap_or("_"),
486    );
487    for field in dyn_tuple_struct.iter_fields() {
488        debug.field(&field as &dyn Debug);
489    }
490    debug.finish()
491}
492
493#[cfg(test)]
494mod tests {
495    use crate as bevy_reflect;
496    use crate::*;
497    #[derive(Reflect)]
498    struct Ts(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
499    #[test]
500    fn next_index_increment() {
501        let mut iter = Ts(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).iter_fields();
502        let size = iter.len();
503        iter.index = size - 1;
504        let prev_index = iter.index;
505        assert!(iter.next().is_some());
506        assert_eq!(prev_index, iter.index - 1);
507
508        // When None we should no longer increase index
509        assert!(iter.next().is_none());
510        assert_eq!(size, iter.index);
511        assert!(iter.next().is_none());
512        assert_eq!(size, iter.index);
513    }
514}