From f2a9dc0ca081755de3ceab68ba80e639cc6cb88e Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sun, 25 Sep 2022 22:56:19 +0200 Subject: [PATCH 1/4] add Wrapper subtrait and type info --- crates/bevy_reflect/src/lib.rs | 3 ++ crates/bevy_reflect/src/reflect.rs | 4 +- crates/bevy_reflect/src/serde/de.rs | 1 + crates/bevy_reflect/src/serde/ser.rs | 1 + crates/bevy_reflect/src/type_info.rs | 4 ++ crates/bevy_reflect/src/wrapper.rs | 62 ++++++++++++++++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_reflect/src/wrapper.rs diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index a9e57d3fbfac0..4e72d9620fe13 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -12,6 +12,8 @@ mod tuple_struct; mod type_info; mod type_registry; mod type_uuid; +mod wrapper; + mod impls { #[cfg(feature = "glam")] mod glam; @@ -58,6 +60,7 @@ pub use tuple_struct::*; pub use type_info::*; pub use type_registry::*; pub use type_uuid::*; +pub use wrapper::*; pub use bevy_reflect_derive::*; pub use erased_serde; diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index fb8285fd9de0c..9fd2b1bc04c34 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -1,7 +1,7 @@ use crate::{ array_debug, enum_debug, list_debug, map_debug, serde::Serializable, struct_debug, tuple_debug, tuple_struct_debug, Array, Enum, List, Map, Struct, Tuple, TupleStruct, TypeInfo, Typed, - ValueInfo, + ValueInfo, Wrapper, }; use std::{ any::{self, Any, TypeId}, @@ -24,6 +24,7 @@ pub enum ReflectRef<'a> { List(&'a dyn List), Array(&'a dyn Array), Map(&'a dyn Map), + Wrapper(&'a dyn Wrapper), Enum(&'a dyn Enum), Value(&'a dyn Reflect), } @@ -42,6 +43,7 @@ pub enum ReflectMut<'a> { Array(&'a mut dyn Array), Map(&'a mut dyn Map), Enum(&'a mut dyn Enum), + Wrapper(&'a mut dyn Wrapper), Value(&'a mut dyn Reflect), } diff --git a/crates/bevy_reflect/src/serde/de.rs b/crates/bevy_reflect/src/serde/de.rs index d0f03d0f8631b..8cdbb9b320cd0 100644 --- a/crates/bevy_reflect/src/serde/de.rs +++ b/crates/bevy_reflect/src/serde/de.rs @@ -361,6 +361,7 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { dynamic_enum.set_name(type_name.to_string()); Ok(Box::new(dynamic_enum)) } + TypeInfo::Wrapper(_wrapper_info) => todo!("wrapper deserialize"), TypeInfo::Value(_) => { // This case should already be handled Err(de::Error::custom(format_args!( diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index 8425f1e0a015b..261b18a2d2cc7 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -156,6 +156,7 @@ impl<'a> Serialize for TypedReflectSerializer<'a> { registry: self.registry, } .serialize(serializer), + ReflectRef::Wrapper(_) => todo!("serialize wrapper"), ReflectRef::Value(_) => Err(serializable.err().unwrap()), } } diff --git a/crates/bevy_reflect/src/type_info.rs b/crates/bevy_reflect/src/type_info.rs index 9e5519d500ad6..572e17872f9c4 100644 --- a/crates/bevy_reflect/src/type_info.rs +++ b/crates/bevy_reflect/src/type_info.rs @@ -1,5 +1,6 @@ use crate::{ ArrayInfo, EnumInfo, ListInfo, MapInfo, Reflect, StructInfo, TupleInfo, TupleStructInfo, + WrapperInfo, }; use std::any::{Any, TypeId}; @@ -102,6 +103,7 @@ pub enum TypeInfo { Array(ArrayInfo), Map(MapInfo), Enum(EnumInfo), + Wrapper(WrapperInfo), Value(ValueInfo), /// Type information for "dynamic" types whose metadata can't be known at compile-time. /// @@ -120,6 +122,7 @@ impl TypeInfo { Self::Array(info) => info.type_id(), Self::Map(info) => info.type_id(), Self::Enum(info) => info.type_id(), + Self::Wrapper(info) => info.type_id(), Self::Value(info) => info.type_id(), Self::Dynamic(info) => info.type_id(), } @@ -137,6 +140,7 @@ impl TypeInfo { Self::Array(info) => info.type_name(), Self::Map(info) => info.type_name(), Self::Enum(info) => info.type_name(), + Self::Wrapper(info) => info.type_name(), Self::Value(info) => info.type_name(), Self::Dynamic(info) => info.type_name(), } diff --git a/crates/bevy_reflect/src/wrapper.rs b/crates/bevy_reflect/src/wrapper.rs new file mode 100644 index 0000000000000..23a13b35ac855 --- /dev/null +++ b/crates/bevy_reflect/src/wrapper.rs @@ -0,0 +1,62 @@ +use std::any::{Any, TypeId}; + +use crate::{FromReflect, Reflect}; + +pub trait Wrapper: Reflect { + fn get(&self) -> &dyn Reflect; + fn get_mut(&mut self) -> &mut dyn Reflect; +} + +#[derive(Clone, Debug)] +pub struct WrapperInfo { + type_name: &'static str, + type_id: TypeId, + inner_type_name: &'static str, + inner_type_id: TypeId, +} + +impl WrapperInfo { + /// Create a new [`WrapperInfo`]. + pub fn new() -> Self { + Self { + type_name: std::any::type_name::(), + type_id: TypeId::of::(), + inner_type_name: std::any::type_name::(), + inner_type_id: TypeId::of::(), + } + } + + /// The [type name] of the wrapper. + /// + /// [type name]: std::any::type_name + pub fn type_name(&self) -> &'static str { + self.type_name + } + + /// The [`TypeId`] of the wrapper. + pub fn type_id(&self) -> TypeId { + self.type_id + } + + /// Check if the given type matches the wrapper type. + pub fn is(&self) -> bool { + TypeId::of::() == self.type_id + } + + /// The [type name] of the inner type. + /// + /// [type name]: std::any::type_name + pub fn inner_type_name(&self) -> &'static str { + self.inner_type_name + } + + /// The [`TypeId`] of the inner type. + pub fn inner_type_id(&self) -> TypeId { + self.inner_type_id + } + + /// Check if the given type matches the wrapper inner type. + pub fn inner_is(&self) -> bool { + TypeId::of::() == self.inner_type_id + } +} From 1b8b8a50f4ef4c9b55ff86dae18ae364a992aa2b Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sun, 25 Sep 2022 23:04:24 +0200 Subject: [PATCH 2/4] implement Reflect for Box --- crates/bevy_reflect/src/impls/std.rs | 81 +++++++++++++++++++++++++++- crates/bevy_reflect/src/wrapper.rs | 8 +-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 1d7acbabf096a..a839ec248f763 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,4 +1,4 @@ -use crate::{self as bevy_reflect, ReflectFromPtr}; +use crate::{self as bevy_reflect, ReflectFromPtr, Wrapper, WrapperInfo}; use crate::{ map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, DynamicMap, Enum, EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, Map, MapInfo, MapIter, @@ -891,6 +891,85 @@ impl FromReflect for Cow<'static, str> { } } +impl Typed for Box { + fn type_info() -> &'static TypeInfo { + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Wrapper(WrapperInfo::new::())) + } +} + +impl Reflect for Box { + fn type_name(&self) -> &str { + std::any::type_name::() + } + + fn get_type_info(&self) -> &'static TypeInfo { + ::type_info() + } + + fn into_any(self: Box) -> Box { + self + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + match value.reflect_ref() { + ReflectRef::Wrapper(wrapper) => { + (**self).apply(wrapper.get()); + } + _ => panic!("Value is not a {}.", std::any::type_name::()), + } + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take::()?; + Ok(()) + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Wrapper(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Wrapper(self) + } + + fn clone_value(&self) -> Box { + todo!("clone value box") + } +} + +impl Wrapper for Box { + fn get(&self) -> &dyn Reflect { + &**self + } + + fn get_mut(&mut self) -> &mut dyn Reflect { + &mut **self + } +} + +impl GetTypeRegistration for Box { + fn get_type_registration() -> TypeRegistration { + TypeRegistration::of::() + } +} + #[cfg(test)] mod tests { use crate as bevy_reflect; diff --git a/crates/bevy_reflect/src/wrapper.rs b/crates/bevy_reflect/src/wrapper.rs index 23a13b35ac855..2c280958640e8 100644 --- a/crates/bevy_reflect/src/wrapper.rs +++ b/crates/bevy_reflect/src/wrapper.rs @@ -1,6 +1,6 @@ use std::any::{Any, TypeId}; -use crate::{FromReflect, Reflect}; +use crate::Reflect; pub trait Wrapper: Reflect { fn get(&self) -> &dyn Reflect; @@ -17,12 +17,12 @@ pub struct WrapperInfo { impl WrapperInfo { /// Create a new [`WrapperInfo`]. - pub fn new() -> Self { + pub fn new() -> Self { Self { type_name: std::any::type_name::(), type_id: TypeId::of::(), - inner_type_name: std::any::type_name::(), - inner_type_id: TypeId::of::(), + inner_type_name: std::any::type_name::(), + inner_type_id: TypeId::of::(), } } From 1041941a9b203d28c97c6c3da494bcd5c6dc0b9f Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sun, 25 Sep 2022 23:20:07 +0200 Subject: [PATCH 3/4] add DynamicWrapper --- crates/bevy_reflect/src/impls/std.rs | 2 +- crates/bevy_reflect/src/wrapper.rs | 122 ++++++++++++++++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index a839ec248f763..4dc73671cd696 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -950,7 +950,7 @@ impl Reflect for Box { } fn clone_value(&self) -> Box { - todo!("clone value box") + Box::new(Wrapper::clone_dynamic(self)) } } diff --git a/crates/bevy_reflect/src/wrapper.rs b/crates/bevy_reflect/src/wrapper.rs index 2c280958640e8..309f49d103674 100644 --- a/crates/bevy_reflect/src/wrapper.rs +++ b/crates/bevy_reflect/src/wrapper.rs @@ -1,10 +1,20 @@ use std::any::{Any, TypeId}; -use crate::Reflect; +use crate::{ + utility::NonGenericTypeInfoCell, DynamicInfo, Reflect, ReflectMut, ReflectRef, TypeInfo, Typed, +}; pub trait Wrapper: Reflect { fn get(&self) -> &dyn Reflect; + fn get_mut(&mut self) -> &mut dyn Reflect; + + fn clone_dynamic(&self) -> DynamicWrapper { + DynamicWrapper { + name: self.type_name().to_string(), + value: self.get().clone_value(), + } + } } #[derive(Clone, Debug)] @@ -60,3 +70,113 @@ impl WrapperInfo { TypeId::of::() == self.inner_type_id } } + +pub struct DynamicWrapper { + name: String, + value: Box, +} +impl DynamicWrapper { + /// Returns the type name of the wrapper. + /// + /// The value returned by this method is the same value returned by + /// [`Reflect::type_name`]. + pub fn name(&self) -> &str { + &self.name + } + + /// Sets the type name of the wrapper. + /// + /// The value set by this method is the value returned by + /// [`Reflect::type_name`]. + pub fn set_name(&mut self, name: String) { + self.name = name; + } + + /// Appends an element with value `value` to the tuple struct. + pub fn insert_boxed(&mut self, value: Box) { + self.value = value; + } + + /// Appends a typed element with value `value` to the tuple struct. + pub fn insert(&mut self, value: T) { + self.insert_boxed(Box::new(value)); + } +} + +impl Wrapper for DynamicWrapper { + fn get(&self) -> &dyn Reflect { + &*self.value + } + + fn get_mut(&mut self) -> &mut dyn Reflect { + &mut *self.value + } + + fn clone_dynamic(&self) -> DynamicWrapper { + DynamicWrapper { + name: self.name.clone(), + value: self.value.clone_value(), + } + } +} + +impl Typed for DynamicWrapper { + fn type_info() -> &'static TypeInfo { + static CELL: NonGenericTypeInfoCell = NonGenericTypeInfoCell::new(); + CELL.get_or_set(|| TypeInfo::Dynamic(DynamicInfo::new::())) + } +} + +impl Reflect for DynamicWrapper { + fn type_name(&self) -> &str { + self.name() + } + + fn get_type_info(&self) -> &'static crate::TypeInfo { + ::type_info() + } + + fn into_any(self: Box) -> Box { + self + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + match value.reflect_ref() { + ReflectRef::Wrapper(wrapper) => self.get_mut().apply(wrapper.get()), + _ => panic!("Attempted to apply a non-wrapper type to a wrapper type."), + } + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Wrapper(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Wrapper(self) + } + + fn clone_value(&self) -> Box { + Box::new(Wrapper::clone_dynamic(self)) + } +} From 60a1fef272b38a5d5c92da7f788d0e1a5edc3cf6 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Sun, 25 Sep 2022 23:28:45 +0200 Subject: [PATCH 4/4] serialize/deserialize reflect wrapper --- crates/bevy_reflect/src/serde/de.rs | 25 ++++++++++++++++++++----- crates/bevy_reflect/src/serde/ser.rs | 22 ++++++++++++++++++++-- crates/bevy_reflect/src/wrapper.rs | 4 ++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/crates/bevy_reflect/src/serde/de.rs b/crates/bevy_reflect/src/serde/de.rs index 8cdbb9b320cd0..bfad14330a8be 100644 --- a/crates/bevy_reflect/src/serde/de.rs +++ b/crates/bevy_reflect/src/serde/de.rs @@ -1,10 +1,10 @@ use crate::serde::SerializationData; use crate::{ ArrayInfo, DynamicArray, DynamicEnum, DynamicList, DynamicMap, DynamicStruct, DynamicTuple, - DynamicTupleStruct, DynamicVariant, EnumInfo, ListInfo, Map, MapInfo, NamedField, Reflect, - ReflectDeserialize, StructInfo, StructVariantInfo, Tuple, TupleInfo, TupleStruct, - TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry, UnnamedField, - VariantInfo, + DynamicTupleStruct, DynamicVariant, DynamicWrapper, EnumInfo, ListInfo, Map, MapInfo, + NamedField, Reflect, ReflectDeserialize, StructInfo, StructVariantInfo, Tuple, TupleInfo, + TupleStruct, TupleStructInfo, TupleVariantInfo, TypeInfo, TypeRegistration, TypeRegistry, + UnnamedField, VariantInfo, }; use erased_serde::Deserializer; use serde::de::{ @@ -361,7 +361,22 @@ impl<'a, 'de> DeserializeSeed<'de> for TypedReflectDeserializer<'a> { dynamic_enum.set_name(type_name.to_string()); Ok(Box::new(dynamic_enum)) } - TypeInfo::Wrapper(_wrapper_info) => todo!("wrapper deserialize"), + TypeInfo::Wrapper(wrapper_info) => { + let registration = get_registration( + wrapper_info.inner_type_id(), + wrapper_info.inner_type_name(), + self.registry, + )?; + let inner = TypedReflectDeserializer { + registration, + registry: self.registry, + } + .deserialize(deserializer)?; + + let dynamic_wrapper = + DynamicWrapper::new(wrapper_info.type_name().to_string(), inner); + Ok(Box::new(dynamic_wrapper)) + } TypeInfo::Value(_) => { // This case should already be handled Err(de::Error::custom(format_args!( diff --git a/crates/bevy_reflect/src/serde/ser.rs b/crates/bevy_reflect/src/serde/ser.rs index 261b18a2d2cc7..acb9781bb1306 100644 --- a/crates/bevy_reflect/src/serde/ser.rs +++ b/crates/bevy_reflect/src/serde/ser.rs @@ -1,6 +1,6 @@ use crate::{ Array, Enum, List, Map, Reflect, ReflectRef, ReflectSerialize, Struct, Tuple, TupleStruct, - TypeInfo, TypeRegistry, VariantInfo, VariantType, + TypeInfo, TypeRegistry, VariantInfo, VariantType, Wrapper, }; use serde::ser::{ Error, SerializeStruct, SerializeStructVariant, SerializeTuple, SerializeTupleStruct, @@ -156,7 +156,11 @@ impl<'a> Serialize for TypedReflectSerializer<'a> { registry: self.registry, } .serialize(serializer), - ReflectRef::Wrapper(_) => todo!("serialize wrapper"), + ReflectRef::Wrapper(value) => WrapperSerializer { + wrapper: value, + registry: self.registry, + } + .serialize(serializer), ReflectRef::Value(_) => Err(serializable.err().unwrap()), } } @@ -467,6 +471,20 @@ impl<'a> Serialize for ArraySerializer<'a> { } } +pub struct WrapperSerializer<'a> { + pub wrapper: &'a dyn Wrapper, + pub registry: &'a TypeRegistry, +} + +impl<'a> Serialize for WrapperSerializer<'a> { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + TypedReflectSerializer::new(self.wrapper.get(), self.registry).serialize(serializer) + } +} + #[cfg(test)] mod tests { use crate as bevy_reflect; diff --git a/crates/bevy_reflect/src/wrapper.rs b/crates/bevy_reflect/src/wrapper.rs index 309f49d103674..204f2a46a1e81 100644 --- a/crates/bevy_reflect/src/wrapper.rs +++ b/crates/bevy_reflect/src/wrapper.rs @@ -76,6 +76,10 @@ pub struct DynamicWrapper { value: Box, } impl DynamicWrapper { + pub fn new(name: String, value: Box) -> DynamicWrapper { + DynamicWrapper { name, value } + } + /// Returns the type name of the wrapper. /// /// The value returned by this method is the same value returned by