diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 8b5bdeb67d42af..cdfbf0a19bd8f1 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -3,6 +3,7 @@ mod map; mod path; mod reflect; mod struct_trait; +mod tuple; mod tuple_struct; mod type_registry; mod type_uuid; @@ -46,6 +47,7 @@ pub use map::*; pub use path::*; pub use reflect::*; pub use struct_trait::*; +pub use tuple::*; pub use tuple_struct::*; pub use type_registry::*; pub use type_uuid::*; @@ -208,6 +210,7 @@ mod tests { c: Vec, d: HashMap, e: Bar, + f: (i32, Vec, Bar), } #[derive(Reflect, Eq, PartialEq, Debug)] @@ -224,6 +227,7 @@ mod tests { c: vec![1, 2], d: hash_map, e: Bar { x: 1 }, + f: (1, vec![1, 2], Bar { x: 1 }), }; let mut foo_patch = DynamicStruct::default(); @@ -234,7 +238,7 @@ mod tests { list.push(3isize); list.push(4isize); list.push(5isize); - foo_patch.insert("c", list); + foo_patch.insert("c", list.clone_dynamic()); let mut map = DynamicMap::default(); map.insert(2usize, 3i8); @@ -242,7 +246,13 @@ mod tests { let mut bar_patch = DynamicStruct::default(); bar_patch.insert("x", 2u32); - foo_patch.insert("e", bar_patch); + foo_patch.insert("e", bar_patch.clone_dynamic()); + + let mut tuple = DynamicTuple::default(); + tuple.insert(2i32); + tuple.insert(list); + tuple.insert(bar_patch); + foo_patch.insert("f", tuple); foo.apply(&foo_patch); @@ -255,6 +265,7 @@ mod tests { c: vec![3, 4, 5], d: hash_map, e: Bar { x: 2 }, + f: (2, vec![3, 4, 5], Bar { x: 2 }), }; assert_eq!(foo, expected_foo); @@ -271,6 +282,7 @@ mod tests { d: HashMap, e: Bar, f: String, + g: (i32, Vec, Bar), } #[derive(Reflect)] @@ -288,6 +300,7 @@ mod tests { d: hash_map, e: Bar { x: 1 }, f: "hi".to_string(), + g: (1, vec![1, 2], Bar { x: 1 }), }; let mut registry = TypeRegistry::default(); @@ -297,6 +310,7 @@ mod tests { registry.register::(); registry.register::(); registry.register::(); + registry.register::(); let serializer = ReflectSerializer::new(&foo, ®istry); let serialized = to_string_pretty(&serializer, PrettyConfig::default()).unwrap(); diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index ee7a1caca29880..9ae0a06540dd3f 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, TupleStruct}; +use crate::{serde::Serializable, List, Map, Struct, Tuple, TupleStruct}; use std::{any::Any, fmt::Debug}; pub use bevy_utils::AHasher as ReflectHasher; @@ -6,6 +6,7 @@ pub use bevy_utils::AHasher as ReflectHasher; pub enum ReflectRef<'a> { Struct(&'a dyn Struct), TupleStruct(&'a dyn TupleStruct), + Tuple(&'a dyn Tuple), List(&'a dyn List), Map(&'a dyn Map), Value(&'a dyn Reflect), @@ -14,6 +15,7 @@ pub enum ReflectRef<'a> { pub enum ReflectMut<'a> { Struct(&'a mut dyn Struct), TupleStruct(&'a mut dyn TupleStruct), + Tuple(&'a dyn Tuple), List(&'a mut dyn List), 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 29203b065f3e53..b7bf5ec9b48586 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, DynamicTupleStruct, Reflect, - ReflectDeserialize, TypeRegistry, + serde::type_fields, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, DynamicTupleStruct, + Reflect, ReflectDeserialize, TypeRegistry, }; use erased_serde::Deserializer; use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor}; @@ -176,6 +176,15 @@ impl<'a, 'de> Visitor<'de> for ReflectVisitor<'a> { tuple_struct.set_name(type_name); return Ok(Box::new(tuple_struct)); } + type_fields::TUPLE => { + let _type_name = type_name + .take() + .ok_or_else(|| de::Error::missing_field(type_fields::TYPE))?; + let tuple = map.next_value_seed(TupleDeserializer { + registry: self.registry, + })?; + return Ok(Box::new(tuple)); + } type_fields::LIST => { let _type_name = type_name .take() @@ -401,3 +410,45 @@ impl<'a, 'de> Visitor<'de> for TupleStructVisitor<'a> { Ok(tuple_struct) } } + +struct TupleDeserializer<'a> { + registry: &'a TypeRegistry, +} + +impl<'a, 'de> DeserializeSeed<'de> for TupleDeserializer<'a> { + type Value = DynamicTuple; + + fn deserialize(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_seq(TupleVisitor { + registry: self.registry, + }) + } +} + +struct TupleVisitor<'a> { + registry: &'a TypeRegistry, +} + +impl<'a, 'de> Visitor<'de> for TupleVisitor<'a> { + type Value = DynamicTuple; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("tuple value") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: SeqAccess<'de>, + { + let mut tuple = DynamicTuple::default(); + while let Some(value) = seq.next_element_seed(ReflectDeserializer { + registry: self.registry, + })? { + tuple.insert_boxed(value); + } + Ok(tuple) + } +} diff --git a/crates/bevy_reflect/src/serde/mod.rs b/crates/bevy_reflect/src/serde/mod.rs index 9f89cda3954c7e..9354d864261eff 100644 --- a/crates/bevy_reflect/src/serde/mod.rs +++ b/crates/bevy_reflect/src/serde/mod.rs @@ -9,6 +9,7 @@ pub(crate) mod type_fields { pub const MAP: &str = "map"; pub const STRUCT: &str = "struct"; pub const TUPLE_STRUCT: &str = "tuple_struct"; + pub const TUPLE: &str = "tuple"; pub const LIST: &str = "list"; pub const VALUE: &str = "value"; } diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index 778b0fb658bc0f..a865bd13b438bf 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -1,5 +1,5 @@ use crate::{ - serde::type_fields, List, Map, Reflect, ReflectRef, Struct, TupleStruct, TypeRegistry, + serde::type_fields, List, Map, Reflect, ReflectRef, Struct, Tuple, TupleStruct, TypeRegistry, }; use serde::{ ser::{SerializeMap, SerializeSeq}, @@ -57,6 +57,11 @@ impl<'a> Serialize for ReflectSerializer<'a> { registry: self.registry, } .serialize(serializer), + ReflectRef::Tuple(value) => TupleSerializer { + tuple: value, + registry: self.registry, + } + .serialize(serializer), ReflectRef::List(value) => ListSerializer { list: value, registry: self.registry, @@ -181,6 +186,48 @@ impl<'a> Serialize for TupleStructValueSerializer<'a> { } } +pub struct TupleSerializer<'a> { + pub tuple: &'a dyn Tuple, + pub registry: &'a TypeRegistry, +} + +impl<'a> Serialize for TupleSerializer<'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.tuple.type_name())?; + state.serialize_entry( + type_fields::TUPLE, + &TupleValueSerializer { + tuple: self.tuple, + registry: self.registry, + }, + )?; + state.end() + } +} + +pub struct TupleValueSerializer<'a> { + pub tuple: &'a dyn Tuple, + pub registry: &'a TypeRegistry, +} + +impl<'a> Serialize for TupleValueSerializer<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_seq(Some(self.tuple.field_len()))?; + for value in self.tuple.iter_fields() { + state.serialize_element(&ReflectSerializer::new(value, self.registry))?; + } + state.end() + } +} + pub struct MapSerializer<'a> { pub map: &'a dyn Map, pub registry: &'a TypeRegistry, diff --git a/crates/bevy_reflect/src/tuple.rs b/crates/bevy_reflect/src/tuple.rs new file mode 100644 index 00000000000000..901a8610e5e114 --- /dev/null +++ b/crates/bevy_reflect/src/tuple.rs @@ -0,0 +1,310 @@ +use std::any::Any; + +use crate::{serde::Serializable, Reflect, ReflectMut, ReflectRef}; + +pub trait Tuple: Reflect { + fn field(&self, index: usize) -> Option<&dyn Reflect>; + fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>; + fn field_len(&self) -> usize; + fn iter_fields(&self) -> TupleFieldIter; + fn clone_dynamic(&self) -> DynamicTuple; +} + +pub struct TupleFieldIter<'a> { + pub(crate) tuple: &'a dyn Tuple, + pub(crate) index: usize, +} + +impl<'a> TupleFieldIter<'a> { + pub fn new(value: &'a dyn Tuple) -> Self { + TupleFieldIter { + tuple: value, + index: 0, + } + } +} + +impl<'a> Iterator for TupleFieldIter<'a> { + type Item = &'a dyn Reflect; + + fn next(&mut self) -> Option { + let value = self.tuple.field(self.index); + self.index += 1; + value + } +} + +pub trait GetTupleField { + fn get_field(&self, index: usize) -> Option<&T>; + fn get_field_mut(&mut self, index: usize) -> Option<&mut T>; +} + +impl GetTupleField for S { + fn get_field(&self, index: usize) -> Option<&T> { + self.field(index) + .and_then(|value| value.downcast_ref::()) + } + + fn get_field_mut(&mut self, index: usize) -> Option<&mut T> { + self.field_mut(index) + .and_then(|value| value.downcast_mut::()) + } +} + +impl GetTupleField for dyn Tuple { + fn get_field(&self, index: usize) -> Option<&T> { + self.field(index) + .and_then(|value| value.downcast_ref::()) + } + + fn get_field_mut(&mut self, index: usize) -> Option<&mut T> { + self.field_mut(index) + .and_then(|value| value.downcast_mut::()) + } +} + +#[derive(Default)] +pub struct DynamicTuple { + pub(crate) fields: Vec>, +} + +impl DynamicTuple { + pub fn insert_boxed(&mut self, value: Box) { + self.fields.push(value); + } + + pub fn insert(&mut self, value: T) { + self.insert_boxed(Box::new(value)); + } +} + +impl Tuple for DynamicTuple { + #[inline] + fn field(&self, index: usize) -> Option<&dyn Reflect> { + self.fields.get(index).map(|field| &**field) + } + + #[inline] + fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + self.fields.get_mut(index).map(|field| &mut **field) + } + + #[inline] + fn field_len(&self) -> usize { + self.fields.len() + } + + #[inline] + fn iter_fields(&self) -> TupleFieldIter { + TupleFieldIter { + tuple: self, + index: 0, + } + } + + #[inline] + fn clone_dynamic(&self) -> DynamicTuple { + DynamicTuple { + fields: self + .fields + .iter() + .map(|value| value.clone_value()) + .collect(), + } + } +} + +impl Reflect for DynamicTuple { + #[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 clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + #[inline] + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Tuple(self) + } + + #[inline] + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Tuple(self) + } + + fn apply(&mut self, value: &dyn Reflect) { + tuple_apply(self, value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + fn reflect_hash(&self) -> Option { + None + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + tuple_partial_eq(self, value) + } + + fn serializable(&self) -> Option { + None + } +} + +#[inline] +pub fn tuple_apply(a: &mut T, b: &dyn Reflect) { + if let ReflectRef::Tuple(tuple) = b.reflect_ref() { + for (i, value) in tuple.iter_fields().enumerate() { + if let Some(v) = a.field_mut(i) { + v.apply(value) + } + } + } else { + panic!("Attempted to apply non-Tuple type to Tuple type."); + } +} + +#[inline] +pub fn tuple_partial_eq(a: &T, b: &dyn Reflect) -> Option { + let b = if let ReflectRef::Tuple(tuple) = b.reflect_ref() { + tuple + } else { + return Some(false); + }; + + if a.field_len() != b.field_len() { + return Some(false); + } + + for (a_field, b_field) in a.iter_fields().zip(b.iter_fields()) { + match a_field.reflect_partial_eq(b_field) { + Some(false) | None => return Some(false), + Some(true) => {} + } + } + + Some(true) +} + +macro_rules! impl_reflect_tuple { + {$($index:tt : $name:tt),*} => { + impl<$($name: Reflect),*> Tuple for ($($name,)*) { + #[inline] + fn field(&self, index: usize) -> Option<&dyn Reflect> { + match index { + $($index => Some(&self.$index as &dyn Reflect),)* + _ => None, + } + } + + #[inline] + fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + match index { + $($index => Some(&mut self.$index as &mut dyn Reflect),)* + _ => None, + } + } + + #[inline] + fn field_len(&self) -> usize { + let indices: &[usize] = &[$($index as usize),*]; + indices.len() + } + + #[inline] + fn iter_fields(&self) -> TupleFieldIter { + TupleFieldIter { + tuple: self, + index: 0, + } + } + + #[inline] + fn clone_dynamic(&self) -> DynamicTuple { + DynamicTuple { + fields: self + .iter_fields() + .map(|value| value.clone_value()) + .collect(), + } + } + } + + impl<$($name: Reflect),*> Reflect for ($($name,)*) { + fn type_name(&self) -> &str { + std::any::type_name::() + } + + fn any(&self) -> &dyn Any { + self + } + + fn any_mut(&mut self) -> &mut dyn Any { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + crate::tuple_apply(self, value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Tuple(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Tuple(self) + } + + fn clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + fn reflect_hash(&self) -> Option { + None + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + crate::tuple_partial_eq(self, value) + } + + fn serializable(&self) -> Option { + None + } + } + } +} + +impl_reflect_tuple! {} +impl_reflect_tuple! {0: A} +impl_reflect_tuple! {0: A, 1: B} +impl_reflect_tuple! {0: A, 1: B, 2: C} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K} +impl_reflect_tuple! {0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L} diff --git a/examples/reflection/reflection_types.rs b/examples/reflection/reflection_types.rs index 3759f3bfbf5f08..25de5fbb900483 100644 --- a/examples/reflection/reflection_types.rs +++ b/examples/reflection/reflection_types.rs @@ -71,6 +71,10 @@ fn setup() { // `TupleStruct` is a trait automatically implemented for tuple structs that derive Reflect. This trait allows you // to interact with fields via their indices ReflectRef::TupleStruct(_) => {} + // `Tuple` is a special trait that can be manually implemented (instead of deriving Reflect). This exposes "tuple" + // operations on your type, allowing you to interact with fields via their indices. Tuple is automatically + // implemented for tuples of 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