Skip to content

Commit 724b362

Browse files
committed
bevy_reflect: Decouple List and Array traits (#7467)
# Objective Resolves #7121 ## Solution Decouples `List` and `Array` by removing `Array` as a supertrait of `List`. Additionally, similar methods from `Array` have been added to `List` so that their usages can remain largely unchanged. #### Possible Alternatives ##### `Sequence` My guess for why we originally made `List` a subtrait of `Array` is that they share a lot of common operations. We could potentially move these overlapping methods to a `Sequence` (name taken from #7059) trait and make that a supertrait of both. This would allow functions to contain logic that simply operates on a sequence rather than "list vs array". However, this means that we'd need to add methods for converting to a `dyn Sequence`. It also might be confusing since we wouldn't add a `ReflectRef::Sequence` or anything like that. Is such a trait worth adding (either in this PR or a followup one)? --- ## Changelog - Removed `Array` as supertrait of `List` - Added methods to `List` that were previously provided by `Array` ## Migration Guide The `List` trait is no longer dependent on `Array`. Implementors of `List` can remove the `Array` impl and move its methods into the `List` impl (with only a couple tweaks). ```rust // BEFORE impl Array for Foo { fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */} fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */} fn len(&self) -> usize {/* ... */} fn is_empty(&self) -> bool {/* ... */} fn iter(&self) -> ArrayIter {/* ... */} fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */} fn clone_dynamic(&self) -> DynamicArray {/* ... */} } impl List for Foo { fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */} fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */} fn push(&mut self, value: Box<dyn Reflect>) {/* ... */} fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */} fn clone_dynamic(&self) -> DynamicList {/* ... */} } // AFTER impl List for Foo { fn get(&self, index: usize) -> Option<&dyn Reflect> {/* ... */} fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {/* ... */} fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {/* ... */} fn remove(&mut self, index: usize) -> Box<dyn Reflect> {/* ... */} fn push(&mut self, value: Box<dyn Reflect>) {/* ... */} fn pop(&mut self) -> Option<Box<dyn Reflect>> {/* ... */} fn len(&self) -> usize {/* ... */} fn is_empty(&self) -> bool {/* ... */} fn iter(&self) -> ListIter {/* ... */} fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {/* ... */} fn clone_dynamic(&self) -> DynamicList {/* ... */} } ``` Some other small tweaks that will need to be made include: - Use `ListIter` for `List::iter` instead of `ArrayIter` (the return type from `Array::iter`) - Replace `array_hash` with `list_hash` in `Reflect::reflect_hash` for implementors of `List`
1 parent d7d983b commit 724b362

File tree

5 files changed

+137
-84
lines changed

5 files changed

+137
-84
lines changed

crates/bevy_reflect/src/array.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,25 @@ use std::{
2121
pub trait Array: Reflect {
2222
/// Returns a reference to the element at `index`, or `None` if out of bounds.
2323
fn get(&self, index: usize) -> Option<&dyn Reflect>;
24+
2425
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
2526
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
26-
/// Returns the number of elements in the collection.
27+
28+
/// Returns the number of elements in the array.
2729
fn len(&self) -> usize;
30+
2831
/// Returns `true` if the collection contains no elements.
2932
fn is_empty(&self) -> bool {
3033
self.len() == 0
3134
}
32-
/// Returns an iterator over the collection.
35+
36+
/// Returns an iterator over the array.
3337
fn iter(&self) -> ArrayIter;
38+
3439
/// Drain the elements of this array to get a vector of owned values.
3540
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
3641

42+
/// Clones the list, producing a [`DynamicArray`].
3743
fn clone_dynamic(&self) -> DynamicArray {
3844
DynamicArray {
3945
name: self.type_name().to_string(),

crates/bevy_reflect/src/impls/smallvec.rs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ use std::any::Any;
33

44
use crate::utility::GenericTypeInfoCell;
55
use crate::{
6-
Array, ArrayIter, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Reflect,
7-
ReflectFromPtr, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed,
6+
FromReflect, FromType, GetTypeRegistration, List, ListInfo, ListIter, Reflect, ReflectFromPtr,
7+
ReflectMut, ReflectOwned, ReflectRef, TypeInfo, TypeRegistration, Typed,
88
};
99

10-
impl<T: smallvec::Array + Send + Sync + 'static> Array for SmallVec<T>
10+
impl<T: smallvec::Array + Send + Sync + 'static> List for SmallVec<T>
1111
where
1212
T::Item: FromReflect,
1313
{
@@ -27,25 +27,6 @@ where
2727
}
2828
}
2929

30-
fn len(&self) -> usize {
31-
<SmallVec<T>>::len(self)
32-
}
33-
34-
fn iter(&self) -> ArrayIter {
35-
ArrayIter::new(self)
36-
}
37-
38-
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
39-
self.into_iter()
40-
.map(|value| Box::new(value) as Box<dyn Reflect>)
41-
.collect()
42-
}
43-
}
44-
45-
impl<T: smallvec::Array + Send + Sync + 'static> List for SmallVec<T>
46-
where
47-
T::Item: FromReflect,
48-
{
4930
fn insert(&mut self, index: usize, value: Box<dyn Reflect>) {
5031
let value = value.take::<T::Item>().unwrap_or_else(|value| {
5132
<T as smallvec::Array>::Item::from_reflect(&*value).unwrap_or_else(|| {
@@ -77,6 +58,20 @@ where
7758
fn pop(&mut self) -> Option<Box<dyn Reflect>> {
7859
self.pop().map(|value| Box::new(value) as Box<dyn Reflect>)
7960
}
61+
62+
fn len(&self) -> usize {
63+
<SmallVec<T>>::len(self)
64+
}
65+
66+
fn iter(&self) -> ListIter {
67+
ListIter::new(self)
68+
}
69+
70+
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
71+
self.into_iter()
72+
.map(|value| Box::new(value) as Box<dyn Reflect>)
73+
.collect()
74+
}
8075
}
8176

8277
impl<T: smallvec::Array + Send + Sync + 'static> Reflect for SmallVec<T>
@@ -137,7 +132,7 @@ where
137132
}
138133

139134
fn clone_value(&self) -> Box<dyn Reflect> {
140-
Box::new(List::clone_dynamic(self))
135+
Box::new(self.clone_dynamic())
141136
}
142137

143138
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {

crates/bevy_reflect/src/impls/std.rs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ impl_from_reflect_value!(NonZeroI8);
180180

181181
macro_rules! impl_reflect_for_veclike {
182182
($ty:ty, $insert:expr, $remove:expr, $push:expr, $pop:expr, $sub:ty) => {
183-
impl<T: FromReflect> Array for $ty {
183+
impl<T: FromReflect> List for $ty {
184184
#[inline]
185185
fn get(&self, index: usize) -> Option<&dyn Reflect> {
186186
<$sub>::get(self, index).map(|value| value as &dyn Reflect)
@@ -191,25 +191,6 @@ macro_rules! impl_reflect_for_veclike {
191191
<$sub>::get_mut(self, index).map(|value| value as &mut dyn Reflect)
192192
}
193193

194-
#[inline]
195-
fn len(&self) -> usize {
196-
<$sub>::len(self)
197-
}
198-
199-
#[inline]
200-
fn iter(&self) -> ArrayIter {
201-
ArrayIter::new(self)
202-
}
203-
204-
#[inline]
205-
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
206-
self.into_iter()
207-
.map(|value| Box::new(value) as Box<dyn Reflect>)
208-
.collect()
209-
}
210-
}
211-
212-
impl<T: FromReflect> List for $ty {
213194
fn insert(&mut self, index: usize, value: Box<dyn Reflect>) {
214195
let value = value.take::<T>().unwrap_or_else(|value| {
215196
T::from_reflect(&*value).unwrap_or_else(|| {
@@ -239,6 +220,23 @@ macro_rules! impl_reflect_for_veclike {
239220
fn pop(&mut self) -> Option<Box<dyn Reflect>> {
240221
$pop(self).map(|value| Box::new(value) as Box<dyn Reflect>)
241222
}
223+
224+
#[inline]
225+
fn len(&self) -> usize {
226+
<$sub>::len(self)
227+
}
228+
229+
#[inline]
230+
fn iter(&self) -> $crate::ListIter {
231+
$crate::ListIter::new(self)
232+
}
233+
234+
#[inline]
235+
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
236+
self.into_iter()
237+
.map(|value| Box::new(value) as Box<dyn Reflect>)
238+
.collect()
239+
}
242240
}
243241

244242
impl<T: FromReflect> Reflect for $ty {
@@ -296,11 +294,11 @@ macro_rules! impl_reflect_for_veclike {
296294
}
297295

298296
fn clone_value(&self) -> Box<dyn Reflect> {
299-
Box::new(List::clone_dynamic(self))
297+
Box::new(self.clone_dynamic())
300298
}
301299

302300
fn reflect_hash(&self) -> Option<u64> {
303-
crate::array_hash(self)
301+
crate::list_hash(self)
304302
}
305303

306304
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {

crates/bevy_reflect/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ mod tests {
394394
list.push(3isize);
395395
list.push(4isize);
396396
list.push(5isize);
397-
foo_patch.insert("c", List::clone_dynamic(&list));
397+
foo_patch.insert("c", list.clone_dynamic());
398398

399399
let mut map = DynamicMap::default();
400400
map.insert(2usize, 3i8);
@@ -607,11 +607,11 @@ mod tests {
607607
#[test]
608608
fn dynamic_names() {
609609
let list = Vec::<usize>::new();
610-
let dyn_list = List::clone_dynamic(&list);
610+
let dyn_list = list.clone_dynamic();
611611
assert_eq!(dyn_list.type_name(), std::any::type_name::<Vec<usize>>());
612612

613613
let array = [b'0'; 4];
614-
let dyn_array = Array::clone_dynamic(&array);
614+
let dyn_array = array.clone_dynamic();
615615
assert_eq!(dyn_array.type_name(), std::any::type_name::<[u8; 4]>());
616616

617617
let map = HashMap::<usize, String>::default();

crates/bevy_reflect/src/list.rs

Lines changed: 88 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
use std::any::{Any, TypeId};
22
use std::fmt::{Debug, Formatter};
3+
use std::hash::{Hash, Hasher};
34

45
use crate::utility::NonGenericTypeInfoCell;
56
use crate::{
6-
Array, ArrayIter, DynamicArray, DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned,
7-
ReflectRef, TypeInfo, Typed,
7+
DynamicInfo, FromReflect, Reflect, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, Typed,
88
};
99

1010
/// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`].
1111
///
12-
/// This is a sub-trait of [`Array`], however as it implements [insertion](List::insert) and [removal](List::remove),
13-
/// it's internal size may change.
12+
/// Unlike the [`Array`](crate::Array) trait, implementors of this type are not expected to
13+
/// maintain a constant length.
14+
/// Methods like [insertion](List::insert) and [removal](List::remove) explicitly allow for their
15+
/// internal size to change.
1416
///
1517
/// This trait expects index 0 to contain the _front_ element.
1618
/// The _back_ element must refer to the element with the largest index.
1719
/// These two rules above should be upheld by manual implementors.
1820
///
1921
/// [`push`](List::push) and [`pop`](List::pop) have default implementations,
2022
/// however it may be faster to implement them manually.
21-
pub trait List: Reflect + Array {
23+
pub trait List: Reflect {
24+
/// Returns a reference to the element at `index`, or `None` if out of bounds.
25+
fn get(&self, index: usize) -> Option<&dyn Reflect>;
26+
27+
/// Returns a mutable reference to the element at `index`, or `None` if out of bounds.
28+
fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
29+
2230
/// Inserts an element at position `index` within the list,
2331
/// shifting all elements after it towards the back of the list.
2432
///
@@ -47,6 +55,20 @@ pub trait List: Reflect + Array {
4755
}
4856
}
4957

58+
/// Returns the number of elements in the list.
59+
fn len(&self) -> usize;
60+
61+
/// Returns `true` if the collection contains no elements.
62+
fn is_empty(&self) -> bool {
63+
self.len() == 0
64+
}
65+
66+
/// Returns an iterator over the list.
67+
fn iter(&self) -> ListIter;
68+
69+
/// Drain the elements of this list to get a vector of owned values.
70+
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>>;
71+
5072
/// Clones the list, producing a [`DynamicList`].
5173
fn clone_dynamic(&self) -> DynamicList {
5274
DynamicList {
@@ -162,7 +184,7 @@ impl DynamicList {
162184
}
163185
}
164186

165-
impl Array for DynamicList {
187+
impl List for DynamicList {
166188
fn get(&self, index: usize) -> Option<&dyn Reflect> {
167189
self.values.get(index).map(|value| &**value)
168190
}
@@ -171,31 +193,6 @@ impl Array for DynamicList {
171193
self.values.get_mut(index).map(|value| &mut **value)
172194
}
173195

174-
fn len(&self) -> usize {
175-
self.values.len()
176-
}
177-
178-
fn iter(&self) -> ArrayIter {
179-
ArrayIter::new(self)
180-
}
181-
182-
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
183-
self.values
184-
}
185-
186-
fn clone_dynamic(&self) -> DynamicArray {
187-
DynamicArray {
188-
name: self.name.clone(),
189-
values: self
190-
.values
191-
.iter()
192-
.map(|value| value.clone_value())
193-
.collect(),
194-
}
195-
}
196-
}
197-
198-
impl List for DynamicList {
199196
fn insert(&mut self, index: usize, element: Box<dyn Reflect>) {
200197
self.values.insert(index, element);
201198
}
@@ -212,6 +209,18 @@ impl List for DynamicList {
212209
self.values.pop()
213210
}
214211

212+
fn len(&self) -> usize {
213+
self.values.len()
214+
}
215+
216+
fn iter(&self) -> ListIter {
217+
ListIter::new(self)
218+
}
219+
220+
fn drain(self: Box<Self>) -> Vec<Box<dyn Reflect>> {
221+
self.values
222+
}
223+
215224
fn clone_dynamic(&self) -> DynamicList {
216225
DynamicList {
217226
name: self.name.clone(),
@@ -292,12 +301,12 @@ impl Reflect for DynamicList {
292301

293302
#[inline]
294303
fn clone_value(&self) -> Box<dyn Reflect> {
295-
Box::new(List::clone_dynamic(self))
304+
Box::new(self.clone_dynamic())
296305
}
297306

298307
#[inline]
299308
fn reflect_hash(&self) -> Option<u64> {
300-
crate::array_hash(self)
309+
list_hash(self)
301310
}
302311

303312
fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
@@ -333,6 +342,51 @@ impl IntoIterator for DynamicList {
333342
}
334343
}
335344

345+
/// An iterator over an [`List`].
346+
pub struct ListIter<'a> {
347+
list: &'a dyn List,
348+
index: usize,
349+
}
350+
351+
impl<'a> ListIter<'a> {
352+
/// Creates a new [`ListIter`].
353+
#[inline]
354+
pub const fn new(list: &'a dyn List) -> ListIter {
355+
ListIter { list, index: 0 }
356+
}
357+
}
358+
359+
impl<'a> Iterator for ListIter<'a> {
360+
type Item = &'a dyn Reflect;
361+
362+
#[inline]
363+
fn next(&mut self) -> Option<Self::Item> {
364+
let value = self.list.get(self.index);
365+
self.index += 1;
366+
value
367+
}
368+
369+
#[inline]
370+
fn size_hint(&self) -> (usize, Option<usize>) {
371+
let size = self.list.len();
372+
(size, Some(size))
373+
}
374+
}
375+
376+
impl<'a> ExactSizeIterator for ListIter<'a> {}
377+
378+
/// Returns the `u64` hash of the given [list](List).
379+
#[inline]
380+
pub fn list_hash<L: List>(list: &L) -> Option<u64> {
381+
let mut hasher = crate::ReflectHasher::default();
382+
std::any::Any::type_id(list).hash(&mut hasher);
383+
list.len().hash(&mut hasher);
384+
for value in list.iter() {
385+
hasher.write_u64(value.reflect_hash()?);
386+
}
387+
Some(hasher.finish())
388+
}
389+
336390
/// Applies the elements of `b` to the corresponding elements of `a`.
337391
///
338392
/// If the length of `b` is greater than that of `a`, the excess elements of `b`
@@ -350,7 +404,7 @@ pub fn list_apply<L: List>(a: &mut L, b: &dyn Reflect) {
350404
v.apply(value);
351405
}
352406
} else {
353-
List::push(a, value.clone_value());
407+
a.push(value.clone_value());
354408
}
355409
}
356410
} else {

0 commit comments

Comments
 (0)