diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs index 005e6f6b7e..07aa12efd0 100644 --- a/crates/bevy_reflect/src/array.rs +++ b/crates/bevy_reflect/src/array.rs @@ -21,19 +21,25 @@ use std::{ pub trait Array: Reflect { /// Returns a reference to the element at `index`, or `None` if out of bounds. fn get(&self, index: usize) -> Option<&dyn Reflect>; + /// Returns a mutable reference to the element at `index`, or `None` if out of bounds. fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; - /// Returns the number of elements in the collection. + + /// Returns the number of elements in the array. fn len(&self) -> usize; + /// Returns `true` if the collection contains no elements. fn is_empty(&self) -> bool { self.len() == 0 } - /// Returns an iterator over the collection. + + /// Returns an iterator over the array. fn iter(&self) -> ArrayIter; + /// Drain the elements of this array to get a vector of owned values. fn drain(self: Box) -> Vec>; + /// Clones the list, producing a [`DynamicArray`]. fn clone_dynamic(&self) -> DynamicArray { DynamicArray { name: self.type_name().to_string(), diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index c911653bd6..769c541d9d 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -3,11 +3,11 @@ use std::any::Any; use crate::utility::GenericTypeInfoCell; use crate::{ - Array, ArrayIter, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Reflect, - ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed, + FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Reflect, ReflectFromPtr, + ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed, }; -impl Array for SmallVec +impl List for SmallVec where T::Item: FromReflect, { @@ -27,25 +27,6 @@ where } } - fn len(&self) -> usize { - >::len(self) - } - - fn iter(&self) -> ArrayIter { - ArrayIter::new(self) - } - - fn drain(self: Box) -> Vec> { - self.into_iter() - .map(|value| Box::new(value) as Box) - .collect() - } -} - -impl List for SmallVec -where - T::Item: FromReflect, -{ fn insert(&mut self, index: usize, value: Box) { let value = value.take::().unwrap_or_else(|value| { ::Item::from_reflect(&*value).unwrap_or_else(|| { @@ -77,6 +58,20 @@ where fn pop(&mut self) -> Option> { self.pop().map(|value| Box::new(value) as Box) } + + fn len(&self) -> usize { + >::len(self) + } + + fn iter(&self) -> ListIter { + ListIter::new(self) + } + + fn drain(self: Box) -> Vec> { + self.into_iter() + .map(|value| Box::new(value) as Box) + .collect() + } } impl Reflect for SmallVec @@ -137,7 +132,7 @@ where } fn clone_value(&self) -> Box { - Box::new(List::clone_dynamic(self)) + Box::new(self.clone_dynamic()) } fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 4555447255..efae9fdc80 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -180,7 +180,7 @@ impl_from_reflect_value!(NonZeroI8); macro_rules! impl_reflect_for_veclike { ($ty:ty, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => { - impl Array for $ty { + impl List for $ty { #[inline] fn get(&self, index: usize) -> Option<&dyn Reflect> { <$sub>::get(self, index).map(|value| value as &dyn Reflect) @@ -191,25 +191,6 @@ macro_rules! impl_reflect_for_veclike { <$sub>::get_mut(self, index).map(|value| value as &mut dyn Reflect) } - #[inline] - fn len(&self) -> usize { - <$sub>::len(self) - } - - #[inline] - fn iter(&self) -> ArrayIter { - ArrayIter::new(self) - } - - #[inline] - fn drain(self: Box) -> Vec> { - self.into_iter() - .map(|value| Box::new(value) as Box) - .collect() - } - } - - impl List for $ty { fn insert(&mut self, index: usize, value: Box) { let value = value.take::().unwrap_or_else(|value| { T::from_reflect(&*value).unwrap_or_else(|| { @@ -239,6 +220,23 @@ macro_rules! impl_reflect_for_veclike { fn pop(&mut self) -> Option> { $pop(self).map(|value| Box::new(value) as Box) } + + #[inline] + fn len(&self) -> usize { + <$sub>::len(self) + } + + #[inline] + fn iter(&self) -> $crate::ListIter { + $crate::ListIter::new(self) + } + + #[inline] + fn drain(self: Box) -> Vec> { + self.into_iter() + .map(|value| Box::new(value) as Box) + .collect() + } } impl Reflect for $ty { @@ -296,11 +294,11 @@ macro_rules! impl_reflect_for_veclike { } fn clone_value(&self) -> Box { - Box::new(List::clone_dynamic(self)) + Box::new(self.clone_dynamic()) } fn reflect_hash(&self) -> Option { - crate::array_hash(self) + crate::list_hash(self) } fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index d0bf810584..2a80f501dd 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -394,7 +394,7 @@ mod tests { list.push(3isize); list.push(4isize); list.push(5isize); - foo_patch.insert("c", List::clone_dynamic(&list)); + foo_patch.insert("c", list.clone_dynamic()); let mut map = DynamicMap::default(); map.insert(2usize, 3i8); @@ -607,11 +607,11 @@ mod tests { #[test] fn dynamic_names() { let list = Vec::::new(); - let dyn_list = List::clone_dynamic(&list); + let dyn_list = list.clone_dynamic(); assert_eq!(dyn_list.type_name(), std::any::type_name::>()); let array = [b'0'; 4]; - let dyn_array = Array::clone_dynamic(&array); + let dyn_array = array.clone_dynamic(); assert_eq!(dyn_array.type_name(), std::any::type_name::<[u8; 4]>()); let map = HashMap::::default(); diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 4940cb4828..c331d76b43 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,16 +1,18 @@ use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; +use std::hash::{Hash, Hasher}; use crate::utility::NonGenericTypeInfoCell; use crate::{ - Array, ArrayIter, DynamicArray, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned, - ReflectRef, TypeInfo, Typed, + DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed, }; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. /// -/// This is a sub-trait of [`Array`], however as it implements [insertion](List::insert) and [removal](List::remove), -/// it's internal size may change. +/// Unlike the [`Array`](crate::Array) trait, implementors of this type are not expected to +/// maintain a constant length. +/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their +/// internal size to change. /// /// This trait expects index 0 to contain the _front_ element. /// The _back_ element must refer to the element with the largest index. @@ -18,7 +20,13 @@ use crate::{ /// /// [`push`](List::push) and [`pop`](List::pop) have default implementations, /// however it may be faster to implement them manually. -pub trait List: Reflect + Array { +pub trait List: Reflect { + /// Returns a reference to the element at `index`, or `None` if out of bounds. + fn get(&self, index: usize) -> Option<&dyn Reflect>; + + /// Returns a mutable reference to the element at `index`, or `None` if out of bounds. + fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; + /// Inserts an element at position `index` within the list, /// shifting all elements after it towards the back of the list. /// @@ -47,6 +55,20 @@ pub trait List: Reflect + Array { } } + /// Returns the number of elements in the list. + fn len(&self) -> usize; + + /// Returns `true` if the collection contains no elements. + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator over the list. + fn iter(&self) -> ListIter; + + /// Drain the elements of this list to get a vector of owned values. + fn drain(self: Box) -> Vec>; + /// Clones the list, producing a [`DynamicList`]. fn clone_dynamic(&self) -> DynamicList { DynamicList { @@ -162,7 +184,7 @@ impl DynamicList { } } -impl Array for DynamicList { +impl List for DynamicList { fn get(&self, index: usize) -> Option<&dyn Reflect> { self.values.get(index).map(|value| &**value) } @@ -171,31 +193,6 @@ impl Array for DynamicList { self.values.get_mut(index).map(|value| &mut **value) } - fn len(&self) -> usize { - self.values.len() - } - - fn iter(&self) -> ArrayIter { - ArrayIter::new(self) - } - - fn drain(self: Box) -> Vec> { - self.values - } - - fn clone_dynamic(&self) -> DynamicArray { - DynamicArray { - name: self.name.clone(), - values: self - .values - .iter() - .map(|value| value.clone_value()) - .collect(), - } - } -} - -impl List for DynamicList { fn insert(&mut self, index: usize, element: Box) { self.values.insert(index, element); } @@ -212,6 +209,18 @@ impl List for DynamicList { self.values.pop() } + fn len(&self) -> usize { + self.values.len() + } + + fn iter(&self) -> ListIter { + ListIter::new(self) + } + + fn drain(self: Box) -> Vec> { + self.values + } + fn clone_dynamic(&self) -> DynamicList { DynamicList { name: self.name.clone(), @@ -292,12 +301,12 @@ impl Reflect for DynamicList { #[inline] fn clone_value(&self) -> Box { - Box::new(List::clone_dynamic(self)) + Box::new(self.clone_dynamic()) } #[inline] fn reflect_hash(&self) -> Option { - crate::array_hash(self) + list_hash(self) } fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { @@ -333,6 +342,51 @@ impl IntoIterator for DynamicList { } } +/// An iterator over an [`List`]. +pub struct ListIter<'a> { + list: &'a dyn List, + index: usize, +} + +impl<'a> ListIter<'a> { + /// Creates a new [`ListIter`]. + #[inline] + pub const fn new(list: &'a dyn List) -> ListIter { + ListIter { list, index: 0 } + } +} + +impl<'a> Iterator for ListIter<'a> { + type Item = &'a dyn Reflect; + + #[inline] + fn next(&mut self) -> Option { + let value = self.list.get(self.index); + self.index += 1; + value + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.list.len(); + (size, Some(size)) + } +} + +impl<'a> ExactSizeIterator for ListIter<'a> {} + +/// Returns the `u64` hash of the given [list](List). +#[inline] +pub fn list_hash(list: &L) -> Option { + let mut hasher = crate::ReflectHasher::default(); + std::any::Any::type_id(list).hash(&mut hasher); + list.len().hash(&mut hasher); + for value in list.iter() { + hasher.write_u64(value.reflect_hash()?); + } + Some(hasher.finish()) +} + /// Applies the elements of `b` to the corresponding elements of `a`. /// /// If the length of `b` is greater than that of `a`, the excess elements of `b` @@ -350,7 +404,7 @@ pub fn list_apply(a: &mut L, b: &dyn Reflect) { v.apply(value); } } else { - List::push(a, value.clone_value()); + a.push(value.clone_value()); } } } else {