Skip to main content

bevy_reflect/
array.rs

1//! Traits and types used to power [array-like] operations via reflection.
2//!
3//! [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
4use crate::generics::impl_generic_info_methods;
5use crate::{
6    ty::impl_type_methods, utility::reflect_hasher, ApplyError, Generics, MaybeTyped,
7    PartialReflect, Reflect, ReflectCloneError, ReflectKind, ReflectMut, ReflectOwned, ReflectRef,
8    Type, TypeInfo, TypePath,
9};
10use alloc::{boxed::Box, vec::Vec};
11use bevy_reflect_derive::impl_type_path;
12use core::{
13    any::Any,
14    fmt::{Debug, Formatter},
15    hash::{Hash, Hasher},
16};
17
18/// A trait used to power [array-like] operations via [reflection].
19///
20/// This corresponds to true Rust arrays like `[T; N]`,
21/// but also to any fixed-size linear sequence types.
22/// It is expected that implementors of this trait uphold this contract
23/// and maintain a fixed size as returned by the [`Array::len`] method.
24///
25/// Due to the [type-erasing] nature of the reflection API as a whole,
26/// this trait does not make any guarantees that the implementor's elements
27/// are homogeneous (i.e. all the same type).
28///
29/// This trait has a blanket implementation over Rust arrays of up to 32 items.
30/// This implementation can technically contain more than 32,
31/// but the blanket [`GetTypeRegistration`] is only implemented up to the 32
32/// item limit due to a [limitation] on [`Deserialize`].
33///
34/// # Example
35///
36/// ```
37/// use bevy_reflect::{PartialReflect, array::Array};
38///
39/// let foo: &dyn Array = &[123_u32, 456_u32, 789_u32];
40/// assert_eq!(foo.len(), 3);
41///
42/// let field: &dyn PartialReflect = foo.get(0).unwrap();
43/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123));
44/// ```
45///
46/// [array-like]: https://doc.rust-lang.org/book/ch03-02-data-types.html#the-array-type
47/// [reflection]: crate
48/// [`List`]: crate::list::List
49/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
50/// [`GetTypeRegistration`]: crate::GetTypeRegistration
51/// [limitation]: https://github.com/serde-rs/serde/issues/1937
52/// [`Deserialize`]: ::serde::Deserialize
53// Prevents unexpectedly importing this trait when trying to call, for example, `array::map`
54#[rust_analyzer::completions(ignore_flyimport_methods)]
55pub trait Array: PartialReflect {
56    /// Returns a reference to the element at `index`, or `None` if out of bounds.
57    fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
58
59    /// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
60    fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
61
62    /// Returns the number of elements in the array.
63    fn len(&self) -> usize;
64
65    /// Returns `true` if the collection contains no elements.
66    fn is_empty(&self) -> bool {
67        self.len() == 0
68    }
69
70    /// Returns an iterator over the array.
71    fn iter(&self) -> ArrayIter<'_>;
72
73    /// Drain the elements of this array to get a vector of owned values.
74    fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>>;
75
76    /// Creates a new [`DynamicArray`] from this array.
77    ///
78    /// Returns an error if any element cannot be converted via [`PartialReflect::to_dynamic`].
79    fn to_dynamic_array(&self) -> Result<DynamicArray, ReflectCloneError> {
80        Ok(DynamicArray {
81            represented_type: self.get_represented_type_info(),
82            values: self
83                .iter()
84                .map(PartialReflect::to_dynamic)
85                .collect::<Result<_, _>>()?,
86        })
87    }
88
89    /// Will return `None` if [`TypeInfo`] is not available.
90    fn get_represented_array_info(&self) -> Option<&'static ArrayInfo> {
91        self.get_represented_type_info()?.as_array().ok()
92    }
93}
94
95/// A container for compile-time array info.
96#[derive(Clone, Debug)]
97pub struct ArrayInfo {
98    ty: Type,
99    generics: Generics,
100    item_info: fn() -> Option<&'static TypeInfo>,
101    item_ty: Type,
102    capacity: usize,
103    #[cfg(feature = "reflect_documentation")]
104    docs: Option<&'static str>,
105}
106
107impl ArrayInfo {
108    /// Create a new [`ArrayInfo`].
109    ///
110    /// # Arguments
111    ///
112    /// * `capacity`: The maximum capacity of the underlying array.
113    pub fn new<TArray: Array + TypePath, TItem: Reflect + MaybeTyped + TypePath>(
114        capacity: usize,
115    ) -> Self {
116        Self {
117            ty: Type::of::<TArray>(),
118            generics: Generics::new(),
119            item_info: TItem::maybe_type_info,
120            item_ty: Type::of::<TItem>(),
121            capacity,
122            #[cfg(feature = "reflect_documentation")]
123            docs: None,
124        }
125    }
126
127    /// Sets the docstring for this array.
128    #[cfg(feature = "reflect_documentation")]
129    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
130        Self { docs, ..self }
131    }
132
133    /// The compile-time capacity of the array.
134    pub fn capacity(&self) -> usize {
135        self.capacity
136    }
137
138    impl_type_methods!(ty);
139
140    /// The [`TypeInfo`] of the array item.
141    ///
142    /// Returns `None` if the array item does not contain static type information,
143    /// such as for dynamic types.
144    pub fn item_info(&self) -> Option<&'static TypeInfo> {
145        (self.item_info)()
146    }
147
148    /// The [type] of the array item.
149    ///
150    /// [type]: Type
151    pub fn item_ty(&self) -> Type {
152        self.item_ty
153    }
154
155    /// The docstring of this array, if any.
156    #[cfg(feature = "reflect_documentation")]
157    pub fn docs(&self) -> Option<&'static str> {
158        self.docs
159    }
160
161    impl_generic_info_methods!(generics);
162}
163
164/// A fixed-size list of reflected values.
165///
166/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`]
167/// is constant, whereas a [`DynamicList`] can have items added and removed.
168///
169/// This isn't to say that a [`DynamicArray`] is immutable— its items
170/// can be mutated— just that the _number_ of items cannot change.
171///
172/// [`DynamicList`]: crate::list::DynamicList
173#[derive(Debug)]
174pub struct DynamicArray {
175    pub(crate) represented_type: Option<&'static TypeInfo>,
176    pub(crate) values: Box<[Box<dyn PartialReflect>]>,
177}
178
179impl DynamicArray {
180    /// Creates a new [`DynamicArray`].
181    #[inline]
182    pub fn new(values: Box<[Box<dyn PartialReflect>]>) -> Self {
183        Self {
184            represented_type: None,
185            values,
186        }
187    }
188
189    /// Sets the [type] to be represented by this `DynamicArray`.
190    ///
191    /// # Panics
192    ///
193    /// Panics if the given [type] is not a [`TypeInfo::Array`].
194    ///
195    /// [type]: TypeInfo
196    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
197        if let Some(represented_type) = represented_type {
198            assert!(
199                matches!(represented_type, TypeInfo::Array(_)),
200                "expected TypeInfo::Array but received: {represented_type:?}"
201            );
202        }
203
204        self.represented_type = represented_type;
205    }
206}
207
208impl PartialReflect for DynamicArray {
209    #[inline]
210    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
211        self.represented_type
212    }
213
214    #[inline]
215    fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
216        self
217    }
218
219    #[inline]
220    fn as_partial_reflect(&self) -> &dyn PartialReflect {
221        self
222    }
223
224    #[inline]
225    fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
226        self
227    }
228
229    fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
230        Err(self)
231    }
232
233    fn try_as_reflect(&self) -> Option<&dyn Reflect> {
234        None
235    }
236
237    fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
238        None
239    }
240
241    fn apply(&mut self, value: &dyn PartialReflect) {
242        array_apply(self, value);
243    }
244
245    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
246        array_try_apply(self, value)
247    }
248
249    #[inline]
250    fn reflect_kind(&self) -> ReflectKind {
251        ReflectKind::Array
252    }
253
254    #[inline]
255    fn reflect_ref(&self) -> ReflectRef<'_> {
256        ReflectRef::Array(self)
257    }
258
259    #[inline]
260    fn reflect_mut(&mut self) -> ReflectMut<'_> {
261        ReflectMut::Array(self)
262    }
263
264    #[inline]
265    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
266        ReflectOwned::Array(self)
267    }
268
269    #[inline]
270    fn reflect_hash(&self) -> Option<u64> {
271        array_hash(self)
272    }
273
274    fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
275        array_partial_eq(self, value)
276    }
277
278    fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
279        array_partial_cmp(self, value)
280    }
281
282    fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
283        write!(f, "DynamicArray(")?;
284        array_debug(self, f)?;
285        write!(f, ")")
286    }
287
288    #[inline]
289    fn is_dynamic(&self) -> bool {
290        true
291    }
292}
293
294impl Array for DynamicArray {
295    #[inline]
296    fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
297        self.values.get(index).map(|value| &**value)
298    }
299
300    #[inline]
301    fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
302        self.values.get_mut(index).map(|value| &mut **value)
303    }
304
305    #[inline]
306    fn len(&self) -> usize {
307        self.values.len()
308    }
309
310    #[inline]
311    fn iter(&self) -> ArrayIter<'_> {
312        ArrayIter::new(self)
313    }
314
315    #[inline]
316    fn drain(self: Box<Self>) -> Vec<Box<dyn PartialReflect>> {
317        self.values.into_vec()
318    }
319}
320
321impl FromIterator<Box<dyn PartialReflect>> for DynamicArray {
322    fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
323        Self {
324            represented_type: None,
325            values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
326        }
327    }
328}
329
330impl<T: PartialReflect> FromIterator<T> for DynamicArray {
331    fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
332        values
333            .into_iter()
334            .map(|value| Box::new(value).into_partial_reflect())
335            .collect()
336    }
337}
338
339impl IntoIterator for DynamicArray {
340    type Item = Box<dyn PartialReflect>;
341    type IntoIter = alloc::vec::IntoIter<Self::Item>;
342
343    fn into_iter(self) -> Self::IntoIter {
344        self.values.into_vec().into_iter()
345    }
346}
347
348impl<'a> IntoIterator for &'a DynamicArray {
349    type Item = &'a dyn PartialReflect;
350    type IntoIter = ArrayIter<'a>;
351
352    fn into_iter(self) -> Self::IntoIter {
353        self.iter()
354    }
355}
356
357impl_type_path!((in bevy_reflect) DynamicArray);
358
359/// An iterator over an [`Array`].
360pub struct ArrayIter<'a> {
361    array: &'a dyn Array,
362    index: usize,
363}
364
365impl ArrayIter<'_> {
366    /// Creates a new [`ArrayIter`].
367    #[inline]
368    pub const fn new(array: &dyn Array) -> ArrayIter<'_> {
369        ArrayIter { array, index: 0 }
370    }
371}
372
373impl<'a> Iterator for ArrayIter<'a> {
374    type Item = &'a dyn PartialReflect;
375
376    #[inline]
377    fn next(&mut self) -> Option<Self::Item> {
378        let value = self.array.get(self.index);
379        self.index += value.is_some() as usize;
380        value
381    }
382
383    #[inline]
384    fn size_hint(&self) -> (usize, Option<usize>) {
385        let remaining = self.array.len().saturating_sub(self.index);
386        (remaining, Some(remaining))
387    }
388}
389
390impl<'a> ExactSizeIterator for ArrayIter<'a> {}
391
392/// Returns the `u64` hash of the given [array](Array).
393#[inline]
394pub fn array_hash<A: Array + ?Sized>(array: &A) -> Option<u64> {
395    let mut hasher = reflect_hasher();
396    Any::type_id(array).hash(&mut hasher);
397    array.len().hash(&mut hasher);
398    for value in array.iter() {
399        hasher.write_u64(value.reflect_hash()?);
400    }
401    Some(hasher.finish())
402}
403
404/// Applies the reflected [array](Array) data to the given [array](Array).
405///
406/// # Panics
407///
408/// * Panics if the two arrays have differing lengths.
409/// * Panics if the reflected value is not a [valid array](ReflectRef::Array).
410#[inline]
411pub fn array_apply<A: Array + ?Sized>(array: &mut A, reflect: &dyn PartialReflect) {
412    if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
413        if array.len() != reflect_array.len() {
414            panic!("Attempted to apply different sized `Array` types.");
415        }
416        for (i, value) in reflect_array.iter().enumerate() {
417            let v = array.get_mut(i).unwrap();
418            v.apply(value);
419        }
420    } else {
421        panic!("Attempted to apply a non-`Array` type to an `Array` type.");
422    }
423}
424
425/// Tries to apply the reflected [array](Array) data to the given [array](Array) and
426/// returns a Result.
427///
428/// # Errors
429///
430/// * Returns an [`ApplyError::DifferentSize`] if the two arrays have differing lengths.
431/// * Returns an [`ApplyError::MismatchedKinds`] if the reflected value is not a
432///   [valid array](ReflectRef::Array).
433/// * Returns any error that is generated while applying elements to each other.
434#[inline]
435pub fn array_try_apply<A: Array>(
436    array: &mut A,
437    reflect: &dyn PartialReflect,
438) -> Result<(), ApplyError> {
439    let reflect_array = reflect.reflect_ref().as_array()?;
440
441    if array.len() != reflect_array.len() {
442        return Err(ApplyError::DifferentSize {
443            from_size: reflect_array.len(),
444            to_size: array.len(),
445        });
446    }
447
448    for (i, value) in reflect_array.iter().enumerate() {
449        let v = array.get_mut(i).unwrap();
450        v.try_apply(value)?;
451    }
452
453    Ok(())
454}
455
456/// Compares two [arrays](Array) (one concrete and one reflected) to see if they
457/// are equal.
458///
459/// Returns [`None`] if the comparison couldn't even be performed.
460#[inline]
461pub fn array_partial_eq<A: Array + ?Sized>(
462    array: &A,
463    reflect: &dyn PartialReflect,
464) -> Option<bool> {
465    match reflect.reflect_ref() {
466        ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => {
467            for (a, b) in array.iter().zip(reflect_array.iter()) {
468                let eq_result = a.reflect_partial_eq(b);
469                if let failed @ (Some(false) | None) = eq_result {
470                    return failed;
471                }
472            }
473        }
474        _ => return Some(false),
475    }
476
477    Some(true)
478}
479
480/// Lexicographically compares two [arrays](Array) and returns their ordering.
481///
482/// Returns [`None`] if the comparison couldn't be performed (e.g., kinds mismatch
483/// or an element comparison returns `None`).
484#[inline]
485pub fn array_partial_cmp<A: Array + ?Sized>(
486    array: &A,
487    reflect: &dyn PartialReflect,
488) -> Option<::core::cmp::Ordering> {
489    let ReflectRef::Array(reflect_array) = reflect.reflect_ref() else {
490        return None;
491    };
492
493    let min_len = core::cmp::min(array.len(), reflect_array.len());
494
495    for (a, b) in array.iter().zip(reflect_array.iter()).take(min_len) {
496        match a.reflect_partial_cmp(b) {
497            None => return None,
498            Some(core::cmp::Ordering::Equal) => continue,
499            Some(ord) => return Some(ord),
500        }
501    }
502
503    // If all compared elements were equal, order by length
504    Some(array.len().cmp(&reflect_array.len()))
505}
506
507/// The default debug formatter for [`Array`] types.
508///
509/// # Example
510/// ```
511/// use bevy_reflect::Reflect;
512///
513/// let my_array: &dyn Reflect = &[1, 2, 3];
514/// println!("{:#?}", my_array);
515///
516/// // Output:
517///
518/// // [
519/// //   1,
520/// //   2,
521/// //   3,
522/// // ]
523/// ```
524#[inline]
525pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> core::fmt::Result {
526    let mut debug = f.debug_list();
527    for item in dyn_array.iter() {
528        debug.entry(&item as &dyn Debug);
529    }
530    debug.finish()
531}
532#[cfg(test)]
533mod tests {
534    use crate::Reflect;
535    use alloc::boxed::Box;
536
537    #[test]
538    fn next_index_increment() {
539        const SIZE: usize = if cfg!(debug_assertions) {
540            4
541        } else {
542            // If compiled in release mode, verify we dont overflow
543            usize::MAX
544        };
545
546        let b = Box::new([(); SIZE]).into_reflect();
547
548        let array = b.reflect_ref().as_array().unwrap();
549
550        let mut iter = array.iter();
551        iter.index = SIZE - 1;
552        assert!(iter.next().is_some());
553
554        // When None we should no longer increase index
555        assert!(iter.next().is_none());
556        assert!(iter.index == SIZE);
557        assert!(iter.next().is_none());
558        assert!(iter.index == SIZE);
559    }
560}