diff --git a/crates/bevy_reflect/src/array.rs b/crates/bevy_reflect/src/array.rs new file mode 100644 index 0000000000000..b4b3e29851ad7 --- /dev/null +++ b/crates/bevy_reflect/src/array.rs @@ -0,0 +1,300 @@ +use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use serde::ser::SerializeSeq; +use std::{ + any::Any, + hash::{Hash, Hasher}, +}; + +/// A static-sized array of [`Reflect`] items. +/// +/// This corresponds to types like `[T; N]` (arrays). +/// +/// Currently, this only supports arrays of up to 32 items. It can technically +/// contain more than 32, but the blanket [`GetTypeRegistration`] is only +/// implemented up to the 32 item limit due to a [limitation] on `Deserialize`. +/// +/// [`GetTypeRegistration`]: crate::GetTypeRegistration +/// [limitation]: https://github.com/serde-rs/serde/issues/1937 +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. + 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. + fn iter(&self) -> ArrayIter; + + fn clone_dynamic(&self) -> DynamicArray { + DynamicArray { + name: self.type_name().to_string(), + values: self.iter().map(|value| value.clone_value()).collect(), + } + } +} + +/// A fixed-size list of reflected values. +/// +/// This differs from [`DynamicList`] in that the size of the [`DynamicArray`] +/// is constant, whereas a [`DynamicList`] can have items added and removed. +/// +/// This isn't to say that a [`DynamicArray`] is immutable— its items +/// can be mutated— just that the _number_ of items cannot change. +/// +/// [`DynamicList`]: crate::DynamicList +pub struct DynamicArray { + pub(crate) name: String, + pub(crate) values: Box<[Box]>, +} + +impl DynamicArray { + #[inline] + pub fn new(values: Box<[Box]>) -> Self { + Self { + name: String::default(), + values, + } + } + + pub fn from_vec(values: Vec) -> Self { + Self { + name: String::default(), + values: values + .into_iter() + .map(|field| Box::new(field) as Box) + .collect::>() + .into_boxed_slice(), + } + } + + #[inline] + pub fn name(&self) -> &str { + &self.name + } + + #[inline] + pub fn set_name(&mut self, name: String) { + self.name = name; + } +} + +// SAFE: any and any_mut both return self +unsafe impl Reflect for DynamicArray { + #[inline] + fn type_name(&self) -> &str { + self.name.as_str() + } + + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn as_reflect(&self) -> &dyn Reflect { + self + } + + #[inline] + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + array_apply(self, value); + } + + #[inline] + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + #[inline] + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Array(self) + } + + #[inline] + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Array(self) + } + + #[inline] + fn clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + #[inline] + fn reflect_hash(&self) -> Option { + array_hash(self) + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + array_partial_eq(self, value) + } + + fn serializable(&self) -> Option { + Some(Serializable::Borrowed(self)) + } +} + +impl Array for DynamicArray { + #[inline] + fn get(&self, index: usize) -> Option<&dyn Reflect> { + self.values.get(index).map(|value| &**value) + } + + #[inline] + fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + self.values.get_mut(index).map(|value| &mut **value) + } + + #[inline] + fn len(&self) -> usize { + self.values.len() + } + + #[inline] + fn iter(&self) -> ArrayIter { + ArrayIter { + array: self, + index: 0, + } + } + + #[inline] + fn clone_dynamic(&self) -> DynamicArray { + DynamicArray { + name: self.name.clone(), + values: self + .values + .iter() + .map(|value| value.clone_value()) + .collect(), + } + } +} + +/// An iterator over an [`Array`]. +pub struct ArrayIter<'a> { + pub(crate) array: &'a dyn Array, + pub(crate) index: usize, +} + +impl<'a> Iterator for ArrayIter<'a> { + type Item = &'a dyn Reflect; + + #[inline] + fn next(&mut self) -> Option { + let value = self.array.get(self.index); + self.index += 1; + value + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.array.len(); + (size, Some(size)) + } +} + +impl<'a> ExactSizeIterator for ArrayIter<'a> {} + +impl<'a> serde::Serialize for dyn Array { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + array_serialize(self, serializer) + } +} + +impl serde::Serialize for DynamicArray { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + array_serialize(self, serializer) + } +} + +/// Serializes the given [array](Array). +#[inline] +pub fn array_serialize(array: &A, serializer: S) -> Result +where + S: serde::Serializer, +{ + let mut seq = serializer.serialize_seq(Some(array.len()))?; + for element in array.iter() { + let serializable = element.serializable().ok_or_else(|| { + serde::ser::Error::custom(format!( + "Type '{}' does not support `Reflect` serialization", + element.type_name() + )) + })?; + seq.serialize_element(serializable.borrow())?; + } + seq.end() +} + +/// Returns the `u64` hash of the given [array](Array). +#[inline] +pub fn array_hash(array: &A) -> Option { + let mut hasher = crate::ReflectHasher::default(); + std::any::Any::type_id(array).hash(&mut hasher); + array.len().hash(&mut hasher); + for value in array.iter() { + hasher.write_u64(value.reflect_hash()?) + } + Some(hasher.finish()) +} + +/// Applies the reflected [array](Array) data to the given [array](Array). +/// +/// # Panics +/// +/// * Panics if the two arrays have differing lengths. +/// * Panics if the reflected value is not a [valid array](ReflectRef::Array). +/// +#[inline] +pub fn array_apply(array: &mut A, reflect: &dyn Reflect) { + if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() { + if array.len() != reflect_array.len() { + panic!("Attempted to apply different sized `Array` types."); + } + for (i, value) in reflect_array.iter().enumerate() { + let v = array.get_mut(i).unwrap(); + v.apply(value); + } + } else { + panic!("Attempted to apply a non-`Array` type to an `Array` type."); + } +} + +/// Compares two [arrays](Array) (one concrete and one reflected) to see if they +/// are equal. +#[inline] +pub fn array_partial_eq(array: &A, reflect: &dyn Reflect) -> Option { + match reflect.reflect_ref() { + ReflectRef::Array(reflect_array) if reflect_array.len() == array.len() => { + for (a, b) in array.iter().zip(reflect_array.iter()) { + if let Some(false) | None = a.reflect_partial_eq(b) { + return Some(false); + } + } + } + _ => return Some(false), + } + + Some(true) +} diff --git a/crates/bevy_reflect/src/impls/smallvec.rs b/crates/bevy_reflect/src/impls/smallvec.rs index a38fb67459068..6bd32dc0b25c9 100644 --- a/crates/bevy_reflect/src/impls/smallvec.rs +++ b/crates/bevy_reflect/src/impls/smallvec.rs @@ -1,9 +1,11 @@ -use smallvec::{Array, SmallVec}; +use smallvec::SmallVec; use std::any::Any; -use crate::{serde::Serializable, FromReflect, List, ListIter, Reflect, ReflectMut, ReflectRef}; +use crate::{ + serde::Serializable, Array, ArrayIter, FromReflect, List, Reflect, ReflectMut, ReflectRef, +}; -impl List for SmallVec +impl Array for SmallVec where T::Item: FromReflect + Clone, { @@ -27,9 +29,21 @@ where >::len(self) } + fn iter(&self) -> ArrayIter { + ArrayIter { + array: self, + index: 0, + } + } +} + +impl List for SmallVec +where + T::Item: FromReflect + Clone, +{ fn push(&mut self, value: Box) { let value = value.take::().unwrap_or_else(|value| { - ::Item::from_reflect(&*value).unwrap_or_else(|| { + ::Item::from_reflect(&*value).unwrap_or_else(|| { panic!( "Attempted to push invalid value of type {}.", value.type_name() @@ -38,17 +52,10 @@ where }); SmallVec::push(self, value); } - - fn iter(&self) -> ListIter { - ListIter { - list: self, - index: 0, - } - } } // SAFE: any and any_mut both return self -unsafe impl Reflect for SmallVec +unsafe impl Reflect for SmallVec where T::Item: FromReflect + Clone, { @@ -90,7 +97,7 @@ where } fn clone_value(&self) -> Box { - Box::new(self.clone_dynamic()) + Box::new(List::clone_dynamic(self)) } fn reflect_hash(&self) -> Option { @@ -106,7 +113,7 @@ where } } -impl FromReflect for SmallVec +impl FromReflect for SmallVec where T::Item: FromReflect + Clone, { @@ -114,7 +121,7 @@ where if let ReflectRef::List(ref_list) = reflect.reflect_ref() { let mut new_list = Self::with_capacity(ref_list.len()); for field in ref_list.iter() { - new_list.push(::Item::from_reflect(field)?); + new_list.push(::Item::from_reflect(field)?); } Some(new_list) } else { diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index b84b18a93f637..f678627c4a410 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,7 +1,7 @@ use crate as bevy_reflect; use crate::{ - map_partial_eq, serde::Serializable, DynamicMap, FromReflect, FromType, GetTypeRegistration, - List, ListIter, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, + map_partial_eq, serde::Serializable, Array, ArrayIter, DynamicMap, FromReflect, FromType, + GetTypeRegistration, List, Map, MapIter, Reflect, ReflectDeserialize, ReflectMut, ReflectRef, TypeRegistration, }; @@ -63,26 +63,32 @@ impl_from_reflect_value!( ); impl_from_reflect_value!(Duration); -impl List for Vec { +impl Array for Vec { + #[inline] fn get(&self, index: usize) -> Option<&dyn Reflect> { <[T]>::get(self, index).map(|value| value as &dyn Reflect) } + #[inline] fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { <[T]>::get_mut(self, index).map(|value| value as &mut dyn Reflect) } + #[inline] fn len(&self) -> usize { <[T]>::len(self) } - fn iter(&self) -> ListIter { - ListIter { - list: self, + #[inline] + fn iter(&self) -> ArrayIter { + ArrayIter { + array: self, index: 0, } } +} +impl List for Vec { fn push(&mut self, value: Box) { let value = value.take::().unwrap_or_else(|value| { T::from_reflect(&*value).unwrap_or_else(|| { @@ -136,11 +142,11 @@ unsafe impl Reflect for Vec { } fn clone_value(&self) -> Box { - Box::new(self.clone_dynamic()) + Box::new(List::clone_dynamic(self)) } fn reflect_hash(&self) -> Option { - None + crate::array_hash(self) } fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { @@ -148,7 +154,7 @@ unsafe impl Reflect for Vec { } fn serializable(&self) -> Option { - None + Some(Serializable::Owned(Box::new(SerializeArrayLike(self)))) } } @@ -306,6 +312,152 @@ impl FromReflect for HashMap { } } +impl Array for [T; N] { + #[inline] + fn get(&self, index: usize) -> Option<&dyn Reflect> { + <[T]>::get(self, index).map(|value| value as &dyn Reflect) + } + + #[inline] + fn get_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + <[T]>::get_mut(self, index).map(|value| value as &mut dyn Reflect) + } + + #[inline] + fn len(&self) -> usize { + N + } + + #[inline] + fn iter(&self) -> ArrayIter { + ArrayIter { + array: self, + index: 0, + } + } +} + +// SAFE: any and any_mut both return self +unsafe impl Reflect for [T; N] { + #[inline] + fn type_name(&self) -> &str { + std::any::type_name::() + } + + #[inline] + fn any(&self) -> &dyn Any { + self + } + + #[inline] + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn as_reflect(&self) -> &dyn Reflect { + self + } + + #[inline] + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + #[inline] + fn apply(&mut self, value: &dyn Reflect) { + crate::array_apply(self, value); + } + + #[inline] + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + #[inline] + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Array(self) + } + + #[inline] + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Array(self) + } + + #[inline] + fn clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + #[inline] + fn reflect_hash(&self) -> Option { + crate::array_hash(self) + } + + #[inline] + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + crate::array_partial_eq(self, value) + } + + #[inline] + fn serializable(&self) -> Option { + Some(Serializable::Owned(Box::new(SerializeArrayLike(self)))) + } +} + +impl FromReflect for [T; N] { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let ReflectRef::Array(ref_array) = reflect.reflect_ref() { + let mut temp_vec = Vec::with_capacity(ref_array.len()); + for field in ref_array.iter() { + temp_vec.push(T::from_reflect(field)?); + } + temp_vec.try_into().ok() + } else { + None + } + } +} + +// Supports dynamic serialization for types that implement `Array`. +struct SerializeArrayLike<'a>(&'a dyn Array); + +impl<'a> serde::Serialize for SerializeArrayLike<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + crate::array_serialize(self.0, serializer) + } +} + +// TODO: +// `FromType::from_type` requires `Deserialize<'de>` to be implemented for `T`. +// Currently serde only supports `Deserialize<'de>` for arrays up to size 32. +// This can be changed to use const generics once serde utilizes const generics for arrays. +// Tracking issue: https://github.com/serde-rs/serde/issues/1937 +macro_rules! impl_array_get_type_registration { + ($($N:expr)+) => { + $( + impl Deserialize<'de>> GetTypeRegistration for [T; $N] { + fn get_type_registration() -> TypeRegistration { + let mut registration = TypeRegistration::of::<[T; $N]>(); + registration.insert::(FromType::<[T; $N]>::from_type()); + registration + } + } + )+ + }; +} + +impl_array_get_type_registration! { + 0 1 2 3 4 5 6 7 8 9 + 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 + 30 31 32 +} + // SAFE: any and any_mut both return self unsafe impl Reflect for Cow<'static, str> { fn type_name(&self) -> &str { diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 90def413de98b..b484e47738cfd 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1,5 +1,6 @@ #![doc = include_str!("../README.md")] +mod array; mod list; mod map; mod path; @@ -35,6 +36,7 @@ pub mod prelude { }; } +pub use array::*; pub use impls::*; pub use list::*; pub use map::*; @@ -242,6 +244,7 @@ mod tests { e: Bar, f: (i32, Vec, Bar), g: Vec<(Baz, HashMap)>, + h: [u32; 2], } #[derive(Reflect, Eq, PartialEq, Clone, Debug, FromReflect)] @@ -268,6 +271,7 @@ mod tests { e: Bar { x: 1 }, f: (1, vec![1, 2], Bar { x: 1 }), g: vec![(Baz("string".to_string()), hash_map_baz)], + h: [2; 2], }; let mut foo_patch = DynamicStruct::default(); @@ -278,7 +282,7 @@ mod tests { list.push(3isize); list.push(4isize); list.push(5isize); - foo_patch.insert("c", list.clone_dynamic()); + foo_patch.insert("c", List::clone_dynamic(&list)); let mut map = DynamicMap::default(); map.insert(2usize, 3i8); @@ -315,6 +319,9 @@ mod tests { }); foo_patch.insert("g", composite); + let array = DynamicArray::from_vec(vec![2u32, 2u32]); + foo_patch.insert("h", array); + foo.apply(&foo_patch); let mut hash_map = HashMap::default(); @@ -332,6 +339,7 @@ mod tests { e: Bar { x: 2 }, f: (2, vec![3, 4, 5], Bar { x: 2 }), g: vec![(Baz("new_string".to_string()), hash_map_baz.clone())], + h: [2; 2], }; assert_eq!(foo, expected_foo); @@ -350,6 +358,7 @@ mod tests { e: Bar { x: 2 }, f: (2, vec![3, 4, 5], Bar { x: 2 }), g: vec![(Baz("new_string".to_string()), hash_map_baz)], + h: [2; 2], }; assert_eq!(new_foo, expected_new_foo); @@ -367,6 +376,7 @@ mod tests { e: Bar, f: String, g: (i32, Vec, Bar), + h: [u32; 2], } #[derive(Reflect)] @@ -385,6 +395,7 @@ mod tests { e: Bar { x: 1 }, f: "hi".to_string(), g: (1, vec![1, 2], Bar { x: 1 }), + h: [2; 2], }; let mut registry = TypeRegistry::default(); @@ -423,9 +434,13 @@ mod tests { #[test] fn dynamic_names() { let list = Vec::::new(); - let dyn_list = list.clone_dynamic(); + let dyn_list = List::clone_dynamic(&list); assert_eq!(dyn_list.type_name(), std::any::type_name::>()); + let array = [b'0'; 4]; + let dyn_array = Array::clone_dynamic(&array); + assert_eq!(dyn_array.type_name(), std::any::type_name::<[u8; 4]>()); + let map = HashMap::::default(); let dyn_map = map.clone_dynamic(); assert_eq!( diff --git a/crates/bevy_reflect/src/list.rs b/crates/bevy_reflect/src/list.rs index 8de4038866015..f2927556eadd3 100644 --- a/crates/bevy_reflect/src/list.rs +++ b/crates/bevy_reflect/src/list.rs @@ -1,29 +1,15 @@ use std::any::Any; -use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; +use crate::{serde::Serializable, Array, ArrayIter, DynamicArray, Reflect, ReflectMut, ReflectRef}; /// An ordered, mutable list of [Reflect] items. This corresponds to types like [`std::vec::Vec`]. -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>; - +/// +/// This is a sub-trait of [`Array`] as it implements a [`push`](List::push) function, allowing +/// it's internal size to grow. +pub trait List: Reflect + Array { /// Appends an element to the list. fn push(&mut self, value: Box); - /// Returns the number of elements in the list. - fn len(&self) -> usize; - - /// Returns `true` if the list contains no elements. - fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns an iterator over the list. - fn iter(&self) -> ListIter; - /// Clones the list, producing a [`DynamicList`]. fn clone_dynamic(&self) -> DynamicList { DynamicList { @@ -68,7 +54,7 @@ impl DynamicList { } } -impl List for DynamicList { +impl Array for DynamicList { fn get(&self, index: usize) -> Option<&dyn Reflect> { self.values.get(index).map(|value| &**value) } @@ -81,8 +67,15 @@ impl List for DynamicList { self.values.len() } - fn clone_dynamic(&self) -> DynamicList { - DynamicList { + fn iter(&self) -> ArrayIter { + ArrayIter { + array: self, + index: 0, + } + } + + fn clone_dynamic(&self) -> DynamicArray { + DynamicArray { name: self.name.clone(), values: self .values @@ -91,17 +84,23 @@ impl List for DynamicList { .collect(), } } +} - fn iter(&self) -> ListIter { - ListIter { - list: self, - index: 0, - } - } - +impl List for DynamicList { fn push(&mut self, value: Box) { DynamicList::push_box(self, value); } + + fn clone_dynamic(&self) -> DynamicList { + DynamicList { + name: self.name.clone(), + values: self + .values + .iter() + .map(|value| value.clone_value()) + .collect(), + } + } } // SAFE: any and any_mut both return self @@ -153,12 +152,12 @@ unsafe impl Reflect for DynamicList { #[inline] fn clone_value(&self) -> Box { - Box::new(self.clone_dynamic()) + Box::new(List::clone_dynamic(self)) } #[inline] fn reflect_hash(&self) -> Option { - None + crate::array_hash(self) } fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { @@ -166,28 +165,16 @@ unsafe impl Reflect for DynamicList { } fn serializable(&self) -> Option { - None + Some(Serializable::Borrowed(self)) } } -/// An iterator over the elements of a [`List`]. -pub struct ListIter<'a> { - pub(crate) list: &'a dyn List, - pub(crate) index: usize, -} - -impl<'a> Iterator for ListIter<'a> { - type Item = &'a dyn Reflect; - - fn next(&mut self) -> Option { - let value = self.list.get(self.index); - self.index += 1; - value - } - - fn size_hint(&self) -> (usize, Option) { - let size = self.list.len(); - (size, Some(size)) +impl serde::Serialize for DynamicList { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + crate::array_serialize(self, serializer) } } @@ -200,8 +187,6 @@ impl IntoIterator for DynamicList { } } -impl<'a> ExactSizeIterator for ListIter<'a> {} - /// 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` @@ -257,6 +242,7 @@ pub fn list_partial_eq(a: &L, b: &dyn Reflect) -> Option { #[cfg(test)] mod tests { use super::DynamicList; + use std::assert_eq; #[test] fn test_into_iter() { diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 0168a0d797c9f..aeb72669faab9 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,4 +1,4 @@ -use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; +use crate::{serde::Serializable, Array, List, Map, Struct, Tuple, TupleStruct}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -14,6 +14,7 @@ pub enum ReflectRef<'a> { TupleStruct(&'a dyn TupleStruct), Tuple(&'a dyn Tuple), List(&'a dyn List), + Array(&'a dyn Array), Map(&'a dyn Map), Value(&'a dyn Reflect), } @@ -29,6 +30,7 @@ pub enum ReflectMut<'a> { TupleStruct(&'a mut dyn TupleStruct), Tuple(&'a mut dyn Tuple), List(&'a mut dyn List), + Array(&'a mut dyn Array), Map(&'a mut dyn Map), Value(&'a mut dyn Reflect), } diff --git a/crates/bevy_reflect/src/serde/de.rs b/crates/bevy_reflect/src/serde/de.rs index 216b25e106f40..5ffc141c6a178 100644 --- a/crates/bevy_reflect/src/serde/de.rs +++ b/crates/bevy_reflect/src/serde/de.rs @@ -1,6 +1,6 @@ use crate::{ - serde::type_fields, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, DynamicTupleStruct, - Reflect, ReflectDeserialize, TypeRegistry, + serde::type_fields, DynamicArray, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, + DynamicTupleStruct, Reflect, ReflectDeserialize, TypeRegistry, }; use erased_serde::Deserializer; use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor}; @@ -194,6 +194,15 @@ impl<'a, 'de> Visitor<'de> for ReflectVisitor<'a> { })?; return Ok(Box::new(list)); } + type_fields::ARRAY => { + let _type_name = type_name + .take() + .ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?; + let array = map.next_value_seed(ArrayDeserializer { + registry: self.registry, + })?; + return Ok(Box::new(array)); + } type_fields::VALUE => { let type_name = type_name .take() @@ -282,6 +291,49 @@ impl<'a, 'de> Visitor<'de> for ListVisitor<'a> { } } +struct ArrayDeserializer<'a> { + registry: &'a TypeRegistry, +} + +impl<'a, 'de> DeserializeSeed<'de> for ArrayDeserializer<'a> { + type Value = DynamicArray; + + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_seq(ArrayVisitor { + registry: self.registry, + }) + } +} + +struct ArrayVisitor<'a> { + registry: &'a TypeRegistry, +} + +impl<'a, 'de> Visitor<'de> for ArrayVisitor<'a> { + type Value = DynamicArray; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("array value") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let mut vec = Vec::with_capacity(seq.size_hint().unwrap_or_default()); + while let Some(value) = seq.next_element_seed(ReflectDeserializer { + registry: self.registry, + })? { + vec.push(value); + } + + Ok(DynamicArray::new(Box::from(vec))) + } +} + struct MapDeserializer<'a> { registry: &'a TypeRegistry, } diff --git a/crates/bevy_reflect/src/serde/mod.rs b/crates/bevy_reflect/src/serde/mod.rs index 9354d864261ef..5e664112a8860 100644 --- a/crates/bevy_reflect/src/serde/mod.rs +++ b/crates/bevy_reflect/src/serde/mod.rs @@ -11,5 +11,6 @@ pub(crate) mod type_fields { pub const TUPLE_STRUCT: &str = "tuple_struct"; pub const TUPLE: &str = "tuple"; pub const LIST: &str = "list"; + pub const ARRAY: &str = "array"; pub const VALUE: &str = "value"; } diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index fc14f7097da2f..180bac1c81069 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -1,5 +1,6 @@ use crate::{ - serde::type_fields, List, Map, Reflect, ReflectRef, Struct, Tuple, TupleStruct, TypeRegistry, + serde::type_fields, Array, List, Map, Reflect, ReflectRef, Struct, Tuple, TupleStruct, + TypeRegistry, }; use serde::{ ser::{SerializeMap, SerializeSeq}, @@ -67,6 +68,11 @@ impl<'a> Serialize for ReflectSerializer<'a> { registry: self.registry, } .serialize(serializer), + ReflectRef::Array(value) => ArraySerializer { + array: value, + registry: self.registry, + } + .serialize(serializer), ReflectRef::Map(value) => MapSerializer { map: value, registry: self.registry, @@ -313,3 +319,44 @@ impl<'a> Serialize for ListValueSerializer<'a> { state.end() } } + +pub struct ArraySerializer<'a> { + pub array: &'a dyn Array, + pub registry: &'a TypeRegistry, +} + +impl<'a> Serialize for ArraySerializer<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_map(Some(2))?; + state.serialize_entry(type_fields::TYPE, self.array.type_name())?; + state.serialize_entry( + type_fields::ARRAY, + &ArrayValueSerializer { + array: self.array, + registry: self.registry, + }, + )?; + state.end() + } +} + +pub struct ArrayValueSerializer<'a> { + pub array: &'a dyn Array, + pub registry: &'a TypeRegistry, +} + +impl<'a> Serialize for ArrayValueSerializer<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_seq(Some(self.array.len()))?; + for value in self.array.iter() { + state.serialize_element(&ReflectSerializer::new(value, self.registry))?; + } + state.end() + } +} diff --git a/examples/reflection/reflection_types.rs b/examples/reflection/reflection_types.rs index 392f9819ea950..8df74149c7c5c 100644 --- a/examples/reflection/reflection_types.rs +++ b/examples/reflection/reflection_types.rs @@ -80,9 +80,13 @@ fn setup() { // arity 12 or less. ReflectRef::Tuple(_) => {} // `List` is a special trait that can be manually implemented (instead of deriving Reflect). - // This exposes "list" operations on your type, such as indexing and insertion. List - // is automatically implemented for relevant core types like Vec + // This exposes "list" operations on your type, such as insertion. `List` is automatically + // implemented for relevant core types like Vec. ReflectRef::List(_) => {} + // `Array` is a special trait that can be manually implemented (instead of deriving Reflect). + // This exposes "array" operations on your type, such as indexing. `Array` + // is automatically implemented for relevant core types like [T; N]. + ReflectRef::Array(_) => {} // `Map` is a special trait that can be manually implemented (instead of deriving Reflect). // This exposes "map" operations on your type, such as getting / inserting by key. // Map is automatically implemented for relevant core types like HashMap