bevy_reflect/
list.rs

1use core::{
2    any::Any,
3    fmt::{Debug, Formatter},
4    hash::{Hash, Hasher},
5};
6
7use bevy_reflect_derive::impl_type_path;
8
9use crate::generics::impl_generic_info_methods;
10use crate::{
11    self as bevy_reflect, type_info::impl_type_methods, utility::reflect_hasher, ApplyError,
12    FromReflect, Generics, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut,
13    ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
14};
15
16/// A trait used to power [list-like] operations via [reflection].
17///
18/// This corresponds to types, like [`Vec`], which contain an ordered sequence
19/// of elements that implement [`Reflect`].
20///
21/// Unlike the [`Array`](crate::Array) trait, implementors of this trait are not expected to
22/// maintain a constant length.
23/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their
24/// internal size to change.
25///
26/// [`push`](List::push) and [`pop`](List::pop) have default implementations,
27/// however it will generally be more performant to implement them manually
28/// as the default implementation uses a very naive approach to find the correct position.
29///
30/// This trait expects its elements to be ordered linearly from front to back.
31/// The _front_ element starts at index 0 with the _back_ element ending at the largest index.
32/// This contract above should be upheld by any manual implementors.
33///
34/// Due to the [type-erasing] nature of the reflection API as a whole,
35/// this trait does not make any guarantees that the implementor's elements
36/// are homogeneous (i.e. all the same type).
37///
38/// # Example
39///
40/// ```
41/// use bevy_reflect::{PartialReflect, Reflect, List};
42///
43/// let foo: &mut dyn List = &mut vec![123_u32, 456_u32, 789_u32];
44/// assert_eq!(foo.len(), 3);
45///
46/// let last_field: Box<dyn PartialReflect> = foo.pop().unwrap();
47/// assert_eq!(last_field.try_downcast_ref::<u32>(), Some(&789));
48/// ```
49///
50/// [list-like]: https://doc.rust-lang.org/book/ch08-01-vectors.html
51/// [reflection]: crate
52/// [type-erasing]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
53pub trait List: PartialReflect {
54    /// Returns a reference to the element at `index`, or `None` if out of bounds.
55    fn get(&self, index: usize) -> Option<&dyn PartialReflect>;
56
57    /// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
58    fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
59
60    /// Inserts an element at position `index` within the list,
61    /// shifting all elements after it towards the back of the list.
62    ///
63    /// # Panics
64    /// Panics if `index > len`.
65    fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>);
66
67    /// Removes and returns the element at position `index` within the list,
68    /// shifting all elements before it towards the front of the list.
69    ///
70    /// # Panics
71    /// Panics if `index` is out of bounds.
72    fn remove(&mut self, index: usize) -> Box<dyn PartialReflect>;
73
74    /// Appends an element to the _back_ of the list.
75    fn push(&mut self, value: Box<dyn PartialReflect>) {
76        self.insert(self.len(), value);
77    }
78
79    /// Removes the _back_ element from the list and returns it, or [`None`] if it is empty.
80    fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
81        if self.is_empty() {
82            None
83        } else {
84            Some(self.remove(self.len() - 1))
85        }
86    }
87
88    /// Returns the number of elements in the list.
89    fn len(&self) -> usize;
90
91    /// Returns `true` if the collection contains no elements.
92    fn is_empty(&self) -> bool {
93        self.len() == 0
94    }
95
96    /// Returns an iterator over the list.
97    fn iter(&self) -> ListIter;
98
99    /// Drain the elements of this list to get a vector of owned values.
100    ///
101    /// After calling this function, `self` will be empty. The order of items in the returned
102    /// [`Vec`] will match the order of items in `self`.
103    fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
104
105    /// Clones the list, producing a [`DynamicList`].
106    fn clone_dynamic(&self) -> DynamicList {
107        DynamicList {
108            represented_type: self.get_represented_type_info(),
109            values: self.iter().map(PartialReflect::clone_value).collect(),
110        }
111    }
112
113    /// Will return `None` if [`TypeInfo`] is not available.
114    fn get_represented_list_info(&self) -> Option<&'static ListInfo> {
115        self.get_represented_type_info()?.as_list().ok()
116    }
117}
118
119/// A container for compile-time list info.
120#[derive(Clone, Debug)]
121pub struct ListInfo {
122    ty: Type,
123    generics: Generics,
124    item_info: fn() -> Option<&'static TypeInfo>,
125    item_ty: Type,
126    #[cfg(feature = "documentation")]
127    docs: Option<&'static str>,
128}
129
130impl ListInfo {
131    /// Create a new [`ListInfo`].
132    pub fn new<TList: List + TypePath, TItem: FromReflect + MaybeTyped + TypePath>() -> Self {
133        Self {
134            ty: Type::of::<TList>(),
135            generics: Generics::new(),
136            item_info: TItem::maybe_type_info,
137            item_ty: Type::of::<TItem>(),
138            #[cfg(feature = "documentation")]
139            docs: None,
140        }
141    }
142
143    /// Sets the docstring for this list.
144    #[cfg(feature = "documentation")]
145    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
146        Self { docs, ..self }
147    }
148
149    impl_type_methods!(ty);
150
151    /// The [`TypeInfo`] of the list item.
152    ///
153    /// Returns `None` if the list item does not contain static type information,
154    /// such as for dynamic types.
155    pub fn item_info(&self) -> Option<&'static TypeInfo> {
156        (self.item_info)()
157    }
158
159    /// The [type] of the list item.
160    ///
161    /// [type]: Type
162    pub fn item_ty(&self) -> Type {
163        self.item_ty
164    }
165
166    /// The docstring of this list, if any.
167    #[cfg(feature = "documentation")]
168    pub fn docs(&self) -> Option<&'static str> {
169        self.docs
170    }
171
172    impl_generic_info_methods!(generics);
173}
174
175/// A list of reflected values.
176#[derive(Default)]
177pub struct DynamicList {
178    represented_type: Option<&'static TypeInfo>,
179    values: Vec<Box<dyn PartialReflect>>,
180}
181
182impl DynamicList {
183    /// Sets the [type] to be represented by this `DynamicList`.
184    /// # Panics
185    ///
186    /// Panics if the given [type] is not a [`TypeInfo::List`].
187    ///
188    /// [type]: TypeInfo
189    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
190        if let Some(represented_type) = represented_type {
191            assert!(
192                matches!(represented_type, TypeInfo::List(_)),
193                "expected TypeInfo::List but received: {:?}",
194                represented_type
195            );
196        }
197
198        self.represented_type = represented_type;
199    }
200
201    /// Appends a typed value to the list.
202    pub fn push<T: PartialReflect>(&mut self, value: T) {
203        self.values.push(Box::new(value));
204    }
205
206    /// Appends a [`Reflect`] trait object to the list.
207    pub fn push_box(&mut self, value: Box<dyn PartialReflect>) {
208        self.values.push(value);
209    }
210}
211
212impl List for DynamicList {
213    fn get(&self, index: usize) -> Option<&dyn PartialReflect> {
214        self.values.get(index).map(|value| &**value)
215    }
216
217    fn get_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
218        self.values.get_mut(index).map(|value| &mut **value)
219    }
220
221    fn insert(&mut self, index: usize, element: Box<dyn PartialReflect>) {
222        self.values.insert(index, element);
223    }
224
225    fn remove(&mut self, index: usize) -> Box<dyn PartialReflect> {
226        self.values.remove(index)
227    }
228
229    fn push(&mut self, value: Box<dyn PartialReflect>) {
230        DynamicList::push_box(self, value);
231    }
232
233    fn pop(&mut self) -> Option<Box<dyn PartialReflect>> {
234        self.values.pop()
235    }
236
237    fn len(&self) -> usize {
238        self.values.len()
239    }
240
241    fn iter(&self) -> ListIter {
242        ListIter::new(self)
243    }
244
245    fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
246        self.values.drain(..).collect()
247    }
248
249    fn clone_dynamic(&self) -> DynamicList {
250        DynamicList {
251            represented_type: self.represented_type,
252            values: self
253                .values
254                .iter()
255                .map(|value| value.clone_value())
256                .collect(),
257        }
258    }
259}
260
261impl PartialReflect for DynamicList {
262    #[inline]
263    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
264        self.represented_type
265    }
266
267    #[inline]
268    fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
269        self
270    }
271
272    #[inline]
273    fn as_partial_reflect(&self) -> &dyn PartialReflect {
274        self
275    }
276
277    #[inline]
278    fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
279        self
280    }
281
282    fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
283        Err(self)
284    }
285
286    fn try_as_reflect(&self) -> Option<&dyn Reflect> {
287        None
288    }
289
290    fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
291        None
292    }
293
294    fn apply(&mut self, value: &dyn PartialReflect) {
295        list_apply(self, value);
296    }
297
298    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
299        list_try_apply(self, value)
300    }
301
302    #[inline]
303    fn reflect_kind(&self) -> ReflectKind {
304        ReflectKind::List
305    }
306
307    #[inline]
308    fn reflect_ref(&self) -> ReflectRef {
309        ReflectRef::List(self)
310    }
311
312    #[inline]
313    fn reflect_mut(&mut self) -> ReflectMut {
314        ReflectMut::List(self)
315    }
316
317    #[inline]
318    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
319        ReflectOwned::List(self)
320    }
321
322    #[inline]
323    fn clone_value(&self) -> Box<dyn PartialReflect> {
324        Box::new(self.clone_dynamic())
325    }
326
327    #[inline]
328    fn reflect_hash(&self) -> Option<u64> {
329        list_hash(self)
330    }
331
332    fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
333        list_partial_eq(self, value)
334    }
335
336    fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
337        write!(f, "DynamicList(")?;
338        list_debug(self, f)?;
339        write!(f, ")")
340    }
341
342    #[inline]
343    fn is_dynamic(&self) -> bool {
344        true
345    }
346}
347
348impl_type_path!((in bevy_reflect) DynamicList);
349
350impl Debug for DynamicList {
351    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
352        self.debug(f)
353    }
354}
355
356impl FromIterator<Box<dyn PartialReflect>> for DynamicList {
357    fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
358        Self {
359            represented_type: None,
360            values: values.into_iter().collect(),
361        }
362    }
363}
364
365impl<T: PartialReflect> FromIterator<T> for DynamicList {
366    fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
367        values
368            .into_iter()
369            .map(|field| Box::new(field).into_partial_reflect())
370            .collect()
371    }
372}
373
374impl IntoIterator for DynamicList {
375    type Item = Box<dyn PartialReflect>;
376    type IntoIter = alloc::vec::IntoIter<Self::Item>;
377
378    fn into_iter(self) -> Self::IntoIter {
379        self.values.into_iter()
380    }
381}
382
383impl<'a> IntoIterator for &'a DynamicList {
384    type Item = &'a dyn PartialReflect;
385    type IntoIter = ListIter<'a>;
386
387    fn into_iter(self) -> Self::IntoIter {
388        self.iter()
389    }
390}
391
392/// An iterator over an [`List`].
393pub struct ListIter<'a> {
394    list: &'a dyn List,
395    index: usize,
396}
397
398impl ListIter<'_> {
399    /// Creates a new [`ListIter`].
400    #[inline]
401    pub const fn new(list: &dyn List) -> ListIter {
402        ListIter { list, index: 0 }
403    }
404}
405
406impl<'a> Iterator for ListIter<'a> {
407    type Item = &'a dyn PartialReflect;
408
409    #[inline]
410    fn next(&mut self) -> Option<Self::Item> {
411        let value = self.list.get(self.index);
412        self.index += value.is_some() as usize;
413        value
414    }
415
416    #[inline]
417    fn size_hint(&self) -> (usize, Option<usize>) {
418        let size = self.list.len();
419        (size, Some(size))
420    }
421}
422
423impl ExactSizeIterator for ListIter<'_> {}
424
425/// Returns the `u64` hash of the given [list](List).
426#[inline]
427pub fn list_hash<L: List>(list: &L) -> Option<u64> {
428    let mut hasher = reflect_hasher();
429    Any::type_id(list).hash(&mut hasher);
430    list.len().hash(&mut hasher);
431    for value in list.iter() {
432        hasher.write_u64(value.reflect_hash()?);
433    }
434    Some(hasher.finish())
435}
436
437/// Applies the elements of `b` to the corresponding elements of `a`.
438///
439/// If the length of `b` is greater than that of `a`, the excess elements of `b`
440/// are cloned and appended to `a`.
441///
442/// # Panics
443///
444/// This function panics if `b` is not a list.
445#[inline]
446pub fn list_apply<L: List>(a: &mut L, b: &dyn PartialReflect) {
447    if let Err(err) = list_try_apply(a, b) {
448        panic!("{err}");
449    }
450}
451
452/// Tries to apply the elements of `b` to the corresponding elements of `a` and
453/// returns a Result.
454///
455/// If the length of `b` is greater than that of `a`, the excess elements of `b`
456/// are cloned and appended to `a`.
457///
458/// # Errors
459///
460/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a list or if
461/// applying elements to each other fails.
462#[inline]
463pub fn list_try_apply<L: List>(a: &mut L, b: &dyn PartialReflect) -> Result<(), ApplyError> {
464    let list_value = b.reflect_ref().as_list()?;
465
466    for (i, value) in list_value.iter().enumerate() {
467        if i < a.len() {
468            if let Some(v) = a.get_mut(i) {
469                v.try_apply(value)?;
470            }
471        } else {
472            List::push(a, value.clone_value());
473        }
474    }
475
476    Ok(())
477}
478
479/// Compares a [`List`] with a [`Reflect`] value.
480///
481/// Returns true if and only if all of the following are true:
482/// - `b` is a list;
483/// - `b` is the same length as `a`;
484/// - [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for pairwise elements of `a` and `b`.
485///
486/// Returns [`None`] if the comparison couldn't even be performed.
487#[inline]
488pub fn list_partial_eq<L: List + ?Sized>(a: &L, b: &dyn PartialReflect) -> Option<bool> {
489    let ReflectRef::List(list) = b.reflect_ref() else {
490        return Some(false);
491    };
492
493    if a.len() != list.len() {
494        return Some(false);
495    }
496
497    for (a_value, b_value) in a.iter().zip(list.iter()) {
498        let eq_result = a_value.reflect_partial_eq(b_value);
499        if let failed @ (Some(false) | None) = eq_result {
500            return failed;
501        }
502    }
503
504    Some(true)
505}
506
507/// The default debug formatter for [`List`] types.
508///
509/// # Example
510/// ```
511/// use bevy_reflect::Reflect;
512///
513/// let my_list: &dyn Reflect = &vec![1, 2, 3];
514/// println!("{:#?}", my_list);
515///
516/// // Output:
517///
518/// // [
519/// //   1,
520/// //   2,
521/// //   3,
522/// // ]
523/// ```
524#[inline]
525pub fn list_debug(dyn_list: &dyn List, f: &mut Formatter<'_>) -> core::fmt::Result {
526    let mut debug = f.debug_list();
527    for item in dyn_list.iter() {
528        debug.entry(&item as &dyn Debug);
529    }
530    debug.finish()
531}
532
533#[cfg(test)]
534mod tests {
535    use super::DynamicList;
536    use crate::Reflect;
537    use core::assert_eq;
538
539    #[test]
540    fn test_into_iter() {
541        let mut list = DynamicList::default();
542        list.push(0usize);
543        list.push(1usize);
544        list.push(2usize);
545        let items = list.into_iter();
546        for (index, item) in items.into_iter().enumerate() {
547            let value = item
548                .try_take::<usize>()
549                .expect("couldn't downcast to usize");
550            assert_eq!(index, value);
551        }
552    }
553
554    #[test]
555    fn next_index_increment() {
556        const SIZE: usize = if cfg!(debug_assertions) {
557            4
558        } else {
559            // If compiled in release mode, verify we dont overflow
560            usize::MAX
561        };
562        let b = Box::new(vec![(); SIZE]).into_reflect();
563
564        let list = b.reflect_ref().as_list().unwrap();
565
566        let mut iter = list.iter();
567        iter.index = SIZE - 1;
568        assert!(iter.next().is_some());
569
570        // When None we should no longer increase index
571        assert!(iter.next().is_none());
572        assert!(iter.index == SIZE);
573        assert!(iter.next().is_none());
574        assert!(iter.index == SIZE);
575    }
576}