From 4d30d75a4b9d1bd2aaf11ddcbc02d3009e799c8a Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Sun, 9 Mar 2025 10:57:03 -0700 Subject: [PATCH] Added `ReflectClone` type data --- crates/bevy_reflect/src/std_traits.rs | 65 ++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/crates/bevy_reflect/src/std_traits.rs b/crates/bevy_reflect/src/std_traits.rs index cad001132bd25..2b49ef859669e 100644 --- a/crates/bevy_reflect/src/std_traits.rs +++ b/crates/bevy_reflect/src/std_traits.rs @@ -1,4 +1,4 @@ -use crate::{FromType, Reflect}; +use crate::{FromType, PartialReflect, Reflect}; use alloc::boxed::Box; /// A struct used to provide the default value of a type. @@ -22,3 +22,66 @@ impl FromType for ReflectDefault { } } } + +/// Type data for the [`Clone`] trait. +/// +/// This type data can be used to attempt to clone a [`PartialReflect`] value +/// using the concrete type's [`Clone`] implementation. +#[derive(Clone)] +pub struct ReflectClone { + try_clone: fn(&dyn PartialReflect) -> Option>, +} + +impl ReflectClone { + /// Clones a [`PartialReflect`] value using the concrete type's [`Clone`] implementation. + /// + /// # Panics + /// + /// This function will panic if the provided value is not the same type as the type this [`ReflectClone`] was created for. + /// + /// For a non-panicking version, see [`ReflectClone::try_clone`]. + pub fn clone(&self, value: &dyn PartialReflect) -> Box { + self.try_clone(value).unwrap() + } + + /// Attempts to clone a [`PartialReflect`] value using the concrete type's [`Clone`] implementation. + /// + /// If the provided value is not the same type as the type this [`ReflectClone`] was created for, + /// this function will return `None`. + /// + /// For a panicking version, see [`ReflectClone::clone`]. + /// + /// # Example + /// + /// ``` + /// # use bevy_reflect::{Reflect, std_traits::ReflectClone, FromType, PartialReflect}; + /// # #[derive(Clone, Reflect, Debug, PartialEq)] + /// # #[reflect(Clone)] + /// # struct AnotherStruct(i32); + /// #[derive(Clone, Reflect, Debug, PartialEq)] + /// #[reflect(Clone)] + /// struct MyStruct(i32); + /// + /// let reflect_clone = >::from_type(); + /// let value: Box = Box::new(MyStruct(123)); + /// + /// let cloned_value = reflect_clone.try_clone(&*value); + /// assert!(cloned_value.is_some()); + /// assert_eq!(MyStruct(123), cloned_value.unwrap().take::().unwrap()); + /// + /// // Attempting to clone a value of a different type will return None + /// let another_value: Box = Box::new(AnotherStruct(123)); + /// assert!(reflect_clone.try_clone(&*another_value).is_none()); + /// ``` + pub fn try_clone(&self, value: &dyn PartialReflect) -> Option> { + (self.try_clone)(value) + } +} + +impl FromType for ReflectClone { + fn from_type() -> Self { + ReflectClone { + try_clone: |value| Some(Box::new(value.try_downcast_ref::()?.clone())), + } + } +}