From 9619cc67538d49948e54599d261b273621de5887 Mon Sep 17 00:00:00 2001 From: Anciety Date: Tue, 26 Sep 2023 15:24:41 +0800 Subject: [PATCH] implement Reflect for Box --- crates/bevy_reflect/src/impls/std.rs | 200 ++++++++++++++++++++++++++- crates/bevy_reflect/src/reflect.rs | 6 + 2 files changed, 205 insertions(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 0f594a7f81235..af3975ffbcfc0 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -1,5 +1,8 @@ use crate::std_traits::ReflectDefault; -use crate::{self as bevy_reflect, ReflectFromPtr, ReflectFromReflect, ReflectOwned}; +use crate::{ + self as bevy_reflect, DynamicTupleStruct, ReflectFromPtr, ReflectFromReflect, ReflectOwned, + TupleStruct, TupleStructFieldIter, TupleStructInfo, +}; use crate::{ impl_type_path, map_apply, map_partial_eq, Array, ArrayInfo, ArrayIter, DynamicEnum, DynamicMap, Enum, EnumInfo, FromReflect, FromType, GetTypeRegistration, List, ListInfo, @@ -793,6 +796,201 @@ impl_array_get_type_registration! { 30 31 32 } +impl TupleStruct for Box { + fn field(&self, index: usize) -> Option<&dyn Reflect> { + if index == 0 { + Some(self.as_ref()) + } else { + None + } + } + + fn field_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> { + if index == 0 { + Some(self.as_mut()) + } else { + None + } + } + + fn field_len(&self) -> usize { + 1 + } + + fn iter_fields(&self) -> bevy_reflect::TupleStructFieldIter { + TupleStructFieldIter { + tuple_struct: self, + index: 0, + } + } + + fn clone_dynamic(&self) -> DynamicTupleStruct { + let mut dyn_tuple_struct = DynamicTupleStruct::default(); + dyn_tuple_struct.set_represented_type(self.get_represented_type_info()); + dyn_tuple_struct.insert_boxed(self.as_ref().clone_value()); + dyn_tuple_struct + } +} + +impl GetTypeRegistration for Box { + fn get_type_registration() -> TypeRegistration { + let mut registration = TypeRegistration::of::(); + registration.insert::(FromType::::from_type()); + registration + } +} + +impl FromReflect for Box { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let Some(value) = reflect.downcast_ref::() { + return Some(Box::new(T::from_reflect(value.as_ref().as_reflect())?)); + } else if let Some(value) = reflect.downcast_ref::() { + return Some(Box::new(T::from_reflect(value.as_reflect())?)); + } else if let Some(value) = reflect.downcast_ref::() { + if value + .get_represented_type_info() + .map(|t| t.type_id() == Self::type_info().type_id()) + .unwrap_or_default() + { + return Some(Box::new(T::from_reflect(value.field(0).unwrap())?)); + } + } + + None + } +} + +impl TypePath for Box { + fn type_path() -> &'static str { + static CELL: GenericTypePathCell = GenericTypePathCell::new(); + CELL.get_or_insert::(|| format!("std::boxed::Box::<{}>", Self::type_path())) + } + + fn short_type_path() -> &'static str { + static CELL: GenericTypePathCell = GenericTypePathCell::new(); + CELL.get_or_insert::(|| format!("Box<{}>", Self::short_type_path())) + } + + fn type_ident() -> Option<&'static str> { + Some("Box") + } + + fn crate_name() -> Option<&'static str> { + Some("std") + } + + fn module_path() -> Option<&'static str> { + Some("std::boxed") + } +} + +impl Reflect for Box { + fn type_name(&self) -> &str { + std::any::type_name::() + } + + 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 into_reflect(self: Box) -> Box { + self + } + + fn as_inner(&self) -> Option<&dyn Reflect> { + Some(self.as_ref().as_reflect()) + } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + let value = value.as_any(); + let value = if let Some(value) = value.downcast_ref::() { + value.as_ref() + } else if let Some(value) = value.downcast_ref::() { + value + } else { + panic!("Value is not a {}.", std::any::type_name::()); + }; + + self.as_mut().apply(value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + if value.is::() { + *self = value.downcast()?; + } else if let Ok(value) = value.take() { + *self = value; + } + Ok(()) + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::TupleStruct(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::TupleStruct(self) + } + + fn reflect_owned(self: Box) -> ReflectOwned { + ReflectOwned::TupleStruct(self) + } + + fn clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) + } + + fn reflect_hash(&self) -> Option { + self.as_ref().reflect_hash() + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + let value = value.as_inner().unwrap_or(value); + self.as_ref().reflect_partial_eq(value) + } + + fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Box(")?; + self.as_ref().debug(f)?; + write!(f, ")") + } + + fn serializable(&self) -> Option { + self.as_ref().serializable() + } +} + +impl Typed for Box { + fn type_info() -> &'static TypeInfo { + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); + CELL.get_or_insert::(|| { + TypeInfo::TupleStruct(TupleStructInfo::new::( + "Box", + &[UnnamedField::new::(0)], + )) + }) + } +} + impl GetTypeRegistration for Option { fn get_type_registration() -> TypeRegistration { TypeRegistration::of::>() diff --git a/crates/bevy_reflect/src/reflect.rs b/crates/bevy_reflect/src/reflect.rs index 9c33ff6753bb5..d532810795879 100644 --- a/crates/bevy_reflect/src/reflect.rs +++ b/crates/bevy_reflect/src/reflect.rs @@ -93,6 +93,12 @@ pub trait Reflect: DynamicTypePath + Any + Send + Sync { /// [`TypeRegistry::get_type_info`]: crate::TypeRegistry::get_type_info fn get_represented_type_info(&self) -> Option<&'static TypeInfo>; + /// Returns the internal boxed value when the value itself is wrapped in a [`Box`]. + /// If the value is not a [`Box`], returns None. + fn as_inner(&self) -> Option<&dyn Reflect> { + None + } + /// Returns the value as a [`Box`][std::any::Any]. fn into_any(self: Box) -> Box;