Implement FromIterator/IntoIterator for dynamic types (#14250)

# Objective

Implement FromIterator/IntoIterator for dynamic types where missing

Note:
- can't impl `IntoIterator` for `&Array` & co because of orphan rules
- `into_iter().collect()` is a no-op for `Vec`s because of
specialization

---

## Migration Guide

- Change `DynamicArray::from_vec` to `DynamicArray::from_iter`
This commit is contained in:
SpecificProtagonist 2024-07-15 17:38:11 +02:00 committed by GitHub
parent 18abe2186c
commit ab255aefc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 186 additions and 22 deletions

View File

@ -203,15 +203,9 @@ impl DynamicArray {
}
}
#[deprecated(since = "0.15.0", note = "use from_iter")]
pub fn from_vec<T: Reflect>(values: Vec<T>) -> Self {
Self {
represented_type: None,
values: values
.into_iter()
.map(|field| Box::new(field) as Box<dyn Reflect>)
.collect::<Vec<_>>()
.into_boxed_slice(),
}
Self::from_iter(values)
}
/// Sets the [type] to be represented by this `DynamicArray`.
@ -369,6 +363,42 @@ impl Array for DynamicArray {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicArray {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect::<Vec<_>>().into_boxed_slice(),
}
}
}
impl<T: Reflect> FromIterator<T> for DynamicArray {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|value| Box::new(value).into_reflect())
.collect()
}
}
impl IntoIterator for DynamicArray {
type Item = Box<dyn Reflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.values.into_vec().into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicArray {
type Item = &'a dyn Reflect;
type IntoIter = ArrayIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl_type_path!((in bevy_reflect) DynamicArray);
#[cfg(feature = "functions")]
crate::func::macros::impl_function_traits!(DynamicArray);

View File

@ -1092,7 +1092,7 @@ mod tests {
});
foo_patch.insert("g", composite);
let array = DynamicArray::from_vec(vec![2u32, 2u32]);
let array = DynamicArray::from_iter([2u32, 2u32]);
foo_patch.insert("h", array);
foo.apply(&foo_patch);

View File

@ -388,6 +388,24 @@ impl Debug for DynamicList {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicList {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(values: I) -> Self {
Self {
represented_type: None,
values: values.into_iter().collect(),
}
}
}
impl<T: Reflect> FromIterator<T> for DynamicList {
fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
values
.into_iter()
.map(|field| Box::new(field).into_reflect())
.collect()
}
}
impl IntoIterator for DynamicList {
type Item = Box<dyn Reflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
@ -397,6 +415,15 @@ impl IntoIterator for DynamicList {
}
}
impl<'a> IntoIterator for &'a DynamicList {
type Item = &'a dyn Reflect;
type IntoIter = ListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
/// An iterator over an [`List`].
pub struct ListIter<'a> {
list: &'a dyn List,

View File

@ -478,6 +478,26 @@ impl<'a> Iterator for MapIter<'a> {
}
}
impl FromIterator<(Box<dyn Reflect>, Box<dyn Reflect>)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (Box<dyn Reflect>, Box<dyn Reflect>)>>(items: I) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert_boxed(key, value);
}
map
}
}
impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
fn from_iter<I: IntoIterator<Item = (K, V)>>(items: I) -> Self {
let mut map = Self::default();
for (key, value) in items.into_iter() {
map.insert(key, value);
}
map
}
}
impl IntoIterator for DynamicMap {
type Item = (Box<dyn Reflect>, Box<dyn Reflect>);
type IntoIter = std::vec::IntoIter<Self::Item>;
@ -487,6 +507,15 @@ impl IntoIterator for DynamicMap {
}
}
impl<'a> IntoIterator for &'a DynamicMap {
type Item = (&'a dyn Reflect, &'a dyn Reflect);
type IntoIter = MapIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> ExactSizeIterator for MapIter<'a> {}
/// Compares a [`Map`] with a [`Reflect`] value.

View File

@ -508,6 +508,39 @@ impl Debug for DynamicStruct {
}
}
impl<'a, N> FromIterator<(N, Box<dyn Reflect>)> for DynamicStruct
where
N: Into<Cow<'a, str>>,
{
/// Create a dynamic struct that doesn't represent a type from the
/// field name, field value pairs.
fn from_iter<I: IntoIterator<Item = (N, Box<dyn Reflect>)>>(fields: I) -> Self {
let mut dynamic_struct = Self::default();
for (name, value) in fields.into_iter() {
dynamic_struct.insert_boxed(name, value);
}
dynamic_struct
}
}
impl IntoIterator for DynamicStruct {
type Item = Box<dyn Reflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicStruct {
type Item = &'a dyn Reflect;
type IntoIter = FieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Compares a [`Struct`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:

View File

@ -391,6 +391,33 @@ impl Reflect for DynamicTuple {
impl_type_path!((in bevy_reflect) DynamicTuple);
impl FromIterator<Box<dyn Reflect>> for DynamicTuple {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
}
}
}
impl IntoIterator for DynamicTuple {
type Item = Box<dyn Reflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicTuple {
type Item = &'a dyn Reflect;
type IntoIter = TupleFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Applies the elements of `b` to the corresponding elements of `a`.
///
/// # Panics

View File

@ -426,6 +426,33 @@ impl From<DynamicTuple> for DynamicTupleStruct {
}
}
impl FromIterator<Box<dyn Reflect>> for DynamicTupleStruct {
fn from_iter<I: IntoIterator<Item = Box<dyn Reflect>>>(fields: I) -> Self {
Self {
represented_type: None,
fields: fields.into_iter().collect(),
}
}
}
impl IntoIterator for DynamicTupleStruct {
type Item = Box<dyn Reflect>;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.fields.into_iter()
}
}
impl<'a> IntoIterator for &'a DynamicTupleStruct {
type Item = &'a dyn Reflect;
type IntoIter = TupleStructFieldIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_fields()
}
}
/// Compares a [`TupleStruct`] with a [`Reflect`] value.
///
/// Returns true if and only if all of the following are true:

View File

@ -135,10 +135,7 @@ fn main() {
// Lastly, while dynamic types are commonly generated via reflection methods like
// `Reflect::clone_value` or via the reflection deserializers,
// you can also construct them manually.
let mut my_dynamic_list = DynamicList::default();
my_dynamic_list.push(1u32);
my_dynamic_list.push(2u32);
my_dynamic_list.push(3u32);
let mut my_dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
// This is useful when you just need to apply some subset of changes to a type.
let mut my_list: Vec<u32> = Vec::new();
@ -167,7 +164,7 @@ fn main() {
// 2. `DynamicArray`
{
let dynamic_array = DynamicArray::from_vec(vec![1u32, 2u32, 3u32]);
let dynamic_array = DynamicArray::from_iter([1u32, 2u32, 3u32]);
let mut my_array = [0u32; 3];
my_array.apply(&dynamic_array);
@ -176,10 +173,7 @@ fn main() {
// 3. `DynamicList`
{
let mut dynamic_list = DynamicList::default();
dynamic_list.push(1u32);
dynamic_list.push(2u32);
dynamic_list.push(3u32);
let dynamic_list = DynamicList::from_iter([1u32, 2u32, 3u32]);
let mut my_list: Vec<u32> = Vec::new();
my_list.apply(&dynamic_list);
@ -188,10 +182,7 @@ fn main() {
// 4. `DynamicMap`
{
let mut dynamic_map = DynamicMap::default();
dynamic_map.insert("x", 1u32);
dynamic_map.insert("y", 2u32);
dynamic_map.insert("z", 3u32);
let dynamic_map = DynamicMap::from_iter([("x", 1u32), ("y", 2u32), ("z", 3u32)]);
let mut my_map: HashMap<&str, u32> = HashMap::new();
my_map.apply(&dynamic_map);