diff --git a/editor/src/asset/inspector/mod.rs b/editor/src/asset/inspector/mod.rs index ba2c9ed6e..6e1275789 100644 --- a/editor/src/asset/inspector/mod.rs +++ b/editor/src/asset/inspector/mod.rs @@ -18,7 +18,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -use crate::fyrox::core::reflect::Reflect; use crate::fyrox::graph::BaseSceneGraph; use crate::fyrox::{ asset::{manager::ResourceManager, options::BaseImportOptions}, diff --git a/editor/src/light.rs b/editor/src/light.rs index b2660ffd8..c738b827f 100644 --- a/editor/src/light.rs +++ b/editor/src/light.rs @@ -47,7 +47,7 @@ use std::{ sync::Arc, }; -#[derive(Reflect, Debug)] +#[derive(Reflect, Clone, Debug)] struct LightmapperSettings { #[reflect( description = "Amount of texels per unit. It defines 'pixels density' per unit of area (square meters). The \ diff --git a/editor/src/plugins/ragdoll.rs b/editor/src/plugins/ragdoll.rs index 150cfe4d8..0c9fa5ded 100644 --- a/editor/src/plugins/ragdoll.rs +++ b/editor/src/plugins/ragdoll.rs @@ -69,7 +69,7 @@ use fyrox::asset::manager::ResourceManager; use fyrox::gui::inspector::InspectorContextArgs; use std::{ops::Range, sync::Arc}; -#[derive(Reflect, Debug)] +#[derive(Reflect, Clone, Debug)] pub struct RagdollPreset { #[reflect(description = "A handle of a hips (pelvis) bone.")] hips: Handle, diff --git a/editor/src/plugins/tilemap/autotile.rs b/editor/src/plugins/tilemap/autotile.rs index e72bc8226..9b249ddd0 100644 --- a/editor/src/plugins/tilemap/autotile.rs +++ b/editor/src/plugins/tilemap/autotile.rs @@ -172,6 +172,10 @@ impl ResourceData for AutoTileInstance { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } pub struct TileSetTerrainSource<'a, 'b> { diff --git a/editor/src/plugins/tilemap/macro_inspector.rs b/editor/src/plugins/tilemap/macro_inspector.rs index 455ace492..a114a49af 100644 --- a/editor/src/plugins/tilemap/macro_inspector.rs +++ b/editor/src/plugins/tilemap/macro_inspector.rs @@ -39,7 +39,7 @@ const REMOVE_TOOLTIP: &str = "Remove the selected cell from this macro."; const CELL_WITH_MACRO_COLOR: Color = Color::DARK_SLATE_BLUE; const CELL_WITHOUT_MACRO_COLOR: Color = Color::opaque(50, 50, 50); -#[derive(Visit, Reflect)] +#[derive(Visit, Clone, Reflect)] pub struct MacroInspector { handle: Handle, content: Handle, @@ -66,16 +66,19 @@ impl Debug for MacroInspector { } } +#[derive(Clone)] struct Item { macro_id: Uuid, editor: Option, } +#[derive(Clone)] struct ItemEditor { handle: Handle, header: ItemHeader, } +#[derive(Clone)] struct ItemHeader { handle: Handle, label: Handle, diff --git a/editor/src/plugins/tilemap/tile_inspector.rs b/editor/src/plugins/tilemap/tile_inspector.rs index 8f8b84957..718f5977e 100644 --- a/editor/src/plugins/tilemap/tile_inspector.rs +++ b/editor/src/plugins/tilemap/tile_inspector.rs @@ -722,7 +722,7 @@ impl ColliderEditors { } } -#[derive(Visit, Reflect)] +#[derive(Visit, Reflect, Clone)] pub struct TileInspector { handle: Handle, /// The shared state that represents the user's currently selected tool and tiles. diff --git a/editor/src/plugins/tilemap/wfc.rs b/editor/src/plugins/tilemap/wfc.rs index b3d36d8ef..a75aa38e5 100644 --- a/editor/src/plugins/tilemap/wfc.rs +++ b/editor/src/plugins/tilemap/wfc.rs @@ -254,6 +254,10 @@ impl ResourceData for WfcInstance { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl BrushMacro for WfcMacro { diff --git a/editor/src/scene/mod.rs b/editor/src/scene/mod.rs index 418de92ca..a00530c4c 100644 --- a/editor/src/scene/mod.rs +++ b/editor/src/scene/mod.rs @@ -255,7 +255,7 @@ impl GameScene { let scene = &mut engine.scenes[self.scene]; let editor_root = self.editor_objects_root; - let (pure_scene, _) = scene.clone( + let (pure_scene, _) = scene.clone_ex( self.scene_content_root, &mut |node, _| node != editor_root, &mut |_, _| {}, diff --git a/fyrox-animation/src/lib.rs b/fyrox-animation/src/lib.rs index 0d091762b..cbeb75818 100644 --- a/fyrox-animation/src/lib.rs +++ b/fyrox-animation/src/lib.rs @@ -135,6 +135,10 @@ impl ResourceData for AnimationTracksData { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// A resource that holds animation tracks. This resource can be shared across multiple animations. diff --git a/fyrox-animation/src/machine/transition.rs b/fyrox-animation/src/machine/transition.rs index 488d6e74c..b832dbdc6 100644 --- a/fyrox-animation/src/machine/transition.rs +++ b/fyrox-animation/src/machine/transition.rs @@ -74,6 +74,10 @@ macro_rules! define_two_args_node { Self::derived_types() } + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + fn type_name(&self) -> &'static str { type_name::() } @@ -347,6 +351,10 @@ impl Reflect for NotNode { let this = std::mem::replace(self, value.take()?); Ok(Box::new(this)) } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// A node responsible for logical operations evaluation. It can have any number of descendant nodes. diff --git a/fyrox-animation/src/value.rs b/fyrox-animation/src/value.rs index 0b9ca1cdb..9f075a8a6 100644 --- a/fyrox-animation/src/value.rs +++ b/fyrox-animation/src/value.rs @@ -473,7 +473,7 @@ mod test { use crate::value::{BoundValue, TrackValue, ValueBinding, ValueType}; use fyrox_core::{reflect::prelude::*, variable::InheritableVariable}; - #[derive(Reflect, Debug, PartialEq)] + #[derive(Reflect, Debug, Clone, PartialEq)] struct OtherStruct { field: u32, inheritable_variable: InheritableVariable, @@ -488,7 +488,7 @@ mod test { } } - #[derive(Default, Reflect, Debug, PartialEq)] + #[derive(Default, Reflect, Clone, Debug, PartialEq)] struct MyStruct { some_bool: bool, some_property: f32, diff --git a/fyrox-core-derive/src/reflect.rs b/fyrox-core-derive/src/reflect.rs index ef5cc3402..ffc8f7cf2 100644 --- a/fyrox-core-derive/src/reflect.rs +++ b/fyrox-core-derive/src/reflect.rs @@ -321,6 +321,20 @@ fn gen_impl( } }); + let try_clone_box = if ty_args.non_cloneable { + quote! { + fn try_clone_box(&self) -> Option> { + None + } + } + } else { + quote! { + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + } + }; + let types = ty_args .derived_type .iter() @@ -337,6 +351,8 @@ fn gen_impl( file!() } + #try_clone_box + fn type_name(&self) -> &'static str { std::any::type_name::() } diff --git a/fyrox-core-derive/src/reflect/args.rs b/fyrox-core-derive/src/reflect/args.rs index d85df3f98..c0ac27281 100644 --- a/fyrox-core-derive/src/reflect/args.rs +++ b/fyrox-core-derive/src/reflect/args.rs @@ -23,6 +23,7 @@ use darling::*; use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use syn::__private::bool; use syn::*; pub type Fields = ast::Fields; @@ -58,6 +59,9 @@ pub struct TypeArgs { #[darling(multiple)] pub derived_type: Vec, + + #[darling(default)] + pub non_cloneable: bool, } impl TypeArgs { diff --git a/fyrox-core-derive/tests/it/reflect.rs b/fyrox-core-derive/tests/it/reflect.rs index 5df785602..1cce9c204 100644 --- a/fyrox-core-derive/tests/it/reflect.rs +++ b/fyrox-core-derive/tests/it/reflect.rs @@ -40,10 +40,10 @@ pub struct Struct { hidden: usize, } -#[derive(Reflect, Debug)] +#[derive(Reflect, Clone, Debug)] pub struct Tuple(usize, usize); -#[derive(Reflect, Debug)] +#[derive(Reflect, Clone, Debug)] pub enum Enum { Named { field: usize }, Tuple(usize), @@ -122,7 +122,7 @@ fn reflect_field_accessors() { #[test] fn reflect_containers() { - #[derive(Debug)] + #[derive(Debug, Clone)] struct DerefContainer { data: T, } @@ -140,7 +140,7 @@ fn reflect_containers() { } } - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct X { #[reflect(deref)] container: DerefContainer, @@ -161,8 +161,8 @@ fn reflect_containers() { x.get_resolve_path::("container.field", &mut |result| assert_eq!(result, Ok(&0))); - #[derive(Reflect, Debug)] - #[reflect(bounds = "T: Reflect")] + #[derive(Reflect, Clone, Debug)] + #[reflect(bounds = "T: Reflect + Clone")] struct B { #[reflect(deref)] data: Box, @@ -181,7 +181,7 @@ fn reflect_containers() { #[test] fn reflect_path() { - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct Hierarchy { s: Struct, e: Enum, @@ -222,12 +222,12 @@ fn reflect_list_path() { let data = vec![vec![0usize, 1], vec![2, 3, 4]]; data.get_resolve_path("[0][1]", &mut |result| assert_eq!(result, Ok(&1usize))); - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct X { data: Vec, } - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct A { xs: Vec, } @@ -248,7 +248,8 @@ fn reflect_list_path() { #[test] fn reflect_custom_setter() { - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] + #[reflect(bounds = "T: Reflect + Clone")] pub struct Wrapper { #[reflect(setter = "set_value")] value: T, @@ -276,7 +277,7 @@ fn reflect_custom_setter() { #[test] fn reflect_fields_list_of_struct() { - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct Foo { field_a: f32, field_b: String, @@ -306,7 +307,7 @@ fn reflect_fields_list_of_struct() { #[test] fn reflect_fields_list_of_enum() { - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] enum Foo { Bar { field_a: f32 }, Baz { field_b: u32, field_c: String }, @@ -362,7 +363,7 @@ fn default_prop_metadata() -> FieldMetadata<'static> { #[test] fn inspect_default() { - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] pub struct Data { the_field: String, another_field: f32, @@ -398,13 +399,13 @@ fn inspect_default() { #[test] fn inspect_attributes() { - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] pub struct AarGee { aar: u32, gee: u32, } - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] pub struct Data { // NOTE: Even though this field is skipped, the next field is given index `1` for simplicity #[reflect(hidden)] @@ -459,7 +460,7 @@ fn inspect_attributes() { #[test] fn inspect_struct() { - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] struct Tuple(f32, f32); let x = Tuple::default(); @@ -488,7 +489,7 @@ fn inspect_struct() { ) }); - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] struct Unit; let x = Unit; @@ -497,12 +498,12 @@ fn inspect_struct() { #[test] fn inspect_enum() { - #[derive(Debug, Reflect)] + #[derive(Debug, Clone, Reflect)] pub struct NonCopy { inner: u32, } - #[derive(Debug, Reflect)] + #[derive(Debug, Clone, Reflect)] pub enum Data { Named { x: u32, y: u32, z: NonCopy }, Tuple(f32, f32), @@ -596,7 +597,7 @@ fn inspect_enum() { #[test] fn inspect_prop_key_constants() { #[allow(dead_code)] - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] pub struct SStruct { field: usize, #[reflect(hidden)] @@ -609,11 +610,11 @@ fn inspect_prop_key_constants() { // hidden properties // assert_eq!(SStruct::HIDDEN, "hidden"); - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] pub struct STuple(usize); assert_eq!(STuple::F_0, "0"); - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] #[allow(unused)] pub enum E { Tuple(usize), @@ -689,7 +690,7 @@ fn test_hash_map() { }); // Check path resolution. - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] struct Something { hash_map: HashMap, } diff --git a/fyrox-core/src/math/mod.rs b/fyrox-core/src/math/mod.rs index e9efa1a9f..c167b4a3c 100644 --- a/fyrox-core/src/math/mod.rs +++ b/fyrox-core/src/math/mod.rs @@ -38,7 +38,7 @@ use fyrox_core_derive::{impl_reflect, impl_visit}; use std::fmt::Debug; impl_reflect!( - pub struct Rect {} + pub struct Rect {} ); impl Visit for Rect diff --git a/fyrox-core/src/pool/handle.rs b/fyrox-core/src/pool/handle.rs index 5b1e59b4e..953b6999e 100644 --- a/fyrox-core/src/pool/handle.rs +++ b/fyrox-core/src/pool/handle.rs @@ -123,6 +123,10 @@ impl Reflect for Handle { T::derived_types() } + fn try_clone_box(&self) -> Option> { + Some(Box::new(*self)) + } + fn query_derived_types(&self) -> &'static [TypeId] { Self::derived_types() } diff --git a/fyrox-core/src/pool/mod.rs b/fyrox-core/src/pool/mod.rs index 091b36312..c41659a9b 100644 --- a/fyrox-core/src/pool/mod.rs +++ b/fyrox-core/src/pool/mod.rs @@ -98,6 +98,7 @@ impl Reflect for Pool where T: Reflect, P: PayloadContainer + Reflect, + Pool: Clone, { #[inline] fn source_path() -> &'static str { @@ -111,6 +112,10 @@ where &[] } + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + fn query_derived_types(&self) -> &'static [TypeId] { Self::derived_types() } @@ -189,6 +194,7 @@ impl ReflectArray for Pool where T: Reflect, P: PayloadContainer + Reflect, + Pool: Clone, { #[inline] fn reflect_index(&self, index: usize) -> Option<&dyn Reflect> { diff --git a/fyrox-core/src/reflect.rs b/fyrox-core/src/reflect.rs index ae84b76d0..6bd232ea7 100644 --- a/fyrox-core/src/reflect.rs +++ b/fyrox-core/src/reflect.rs @@ -219,7 +219,10 @@ pub trait ReflectBase: Any + Debug { fn as_any_raw_mut(&mut self) -> &mut dyn Any; } -impl ReflectBase for T { +impl ReflectBase for T +where + T: Reflect, +{ fn as_any_raw(&self) -> &dyn Any { self } @@ -257,6 +260,8 @@ pub trait Reflect: ReflectBase { where Self: Sized; + fn try_clone_box(&self) -> Option>; + fn query_derived_types(&self) -> &'static [TypeId]; fn type_name(&self) -> &'static str; @@ -1203,6 +1208,10 @@ macro_rules! blank_reflect { &[] } + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + fn query_derived_types(&self) -> &'static [std::any::TypeId] { Self::derived_types() } @@ -1279,6 +1288,10 @@ macro_rules! delegate_reflect { &[] } + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + fn query_derived_types(&self) -> &'static [std::any::TypeId] { Self::derived_types() } @@ -1456,7 +1469,7 @@ mod test { use std::any::TypeId; use std::collections::HashMap; - #[derive(Reflect, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug)] struct Foo { bar: Bar, baz: f32, @@ -1464,12 +1477,12 @@ mod test { hash_map: HashMap, } - #[derive(Reflect, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug)] struct Item { payload: u32, } - #[derive(Reflect, Default, Debug)] + #[derive(Reflect, Clone, Default, Debug)] struct Bar { stuff: String, } @@ -1503,7 +1516,7 @@ mod test { assert_eq!(names[9], "hash_map[Foobar].payload"); } - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] #[reflect(derived_type = "Derived")] struct Base; diff --git a/fyrox-core/src/reflect/external_impls.rs b/fyrox-core/src/reflect/external_impls.rs index 082814b9a..a92e7b863 100644 --- a/fyrox-core/src/reflect/external_impls.rs +++ b/fyrox-core/src/reflect/external_impls.rs @@ -27,24 +27,24 @@ use std::fmt::Debug; use crate::reflect::prelude::*; impl_reflect! { - pub struct Matrix { + pub struct Matrix { pub data: S, // _phantoms: PhantomData<(T, R, C)>, } } impl_reflect! { - pub struct ArrayStorage(pub [[T; R]; C]); + pub struct ArrayStorage(pub [[T; R]; C]); } impl_reflect! { - pub struct Unit { + pub struct Unit { // pub(crate) value: T, } } impl_reflect! { - pub struct Quaternion { + pub struct Quaternion { pub coords: Vector4, } } diff --git a/fyrox-core/src/reflect/std_impls.rs b/fyrox-core/src/reflect/std_impls.rs index 037b858e0..42fe1bb79 100644 --- a/fyrox-core/src/reflect/std_impls.rs +++ b/fyrox-core/src/reflect/std_impls.rs @@ -67,7 +67,7 @@ macro_rules! impl_reflect_tuple { )* ) => { $( - impl< $($t: Reflect),* > Reflect for ( $($t,)* ) { + impl< $($t: Clone + Reflect),* > Reflect for ( $($t,)* ) { blank_reflect!(); } )* @@ -82,7 +82,7 @@ impl_reflect_tuple! { (T0, T1, T2, T3, T4,); } -impl Reflect for [T; N] { +impl Reflect for [T; N] { blank_reflect!(); fn as_array(&self, func: &mut dyn FnMut(Option<&dyn ReflectArray>)) { @@ -94,7 +94,7 @@ impl Reflect for [T; N] { } } -impl ReflectArray for [T; N] { +impl ReflectArray for [T; N] { fn reflect_index(&self, index: usize) -> Option<&dyn Reflect> { if let Some(item) = self.get(index) { Some(item) @@ -118,10 +118,10 @@ impl ReflectArray for [T; N] { impl_reflect! { #[reflect(ReflectList, ReflectArray)] - pub struct Vec; + pub struct Vec; } -impl ReflectArray for Vec { +impl ReflectArray for Vec { fn reflect_index(&self, index: usize) -> Option<&dyn Reflect> { self.get(index).map(|x| x as &dyn Reflect) } @@ -136,7 +136,7 @@ impl ReflectArray for Vec { } /// REMARK: `Reflect` is implemented for `Vec` where `T: Reflect` only. -impl ReflectList for Vec { +impl ReflectList for Vec { fn reflect_push(&mut self, value: Box) -> Result<(), Box> { self.push(*value.downcast::()?); Ok(()) @@ -170,9 +170,9 @@ impl ReflectList for Vec { impl Reflect for HashMap where - K: Reflect + Eq + Hash + 'static, - V: Reflect, - S: BuildHasher + 'static, + K: Reflect + Eq + Hash + Clone + 'static, + V: Reflect + Clone, + S: BuildHasher + Clone + 'static, { blank_reflect!(); @@ -187,9 +187,9 @@ where impl ReflectHashMap for HashMap where - K: Reflect + Eq + Hash + 'static, - V: Reflect, - S: BuildHasher + 'static, + K: Reflect + Eq + Hash + Clone + 'static, + V: Reflect + Clone, + S: BuildHasher + Clone + 'static, { fn reflect_insert( &mut self, @@ -281,20 +281,20 @@ impl_reflect! { } impl_reflect! { - pub enum Option { + pub enum Option { Some(T), None } } impl_reflect! { - pub struct Range { + pub struct Range { pub start: Idx, pub end: Idx, } } -impl Reflect for Box { +impl Reflect for Box { delegate_reflect!(); } @@ -310,6 +310,11 @@ macro_rules! impl_reflect_inner_mutability { &[] } + fn try_clone_box(&$self) -> Option> { + let guard = $acquire_lock_guard; + Some(Box::new(guard.clone())) + } + fn query_derived_types(&self) -> &'static [std::any::TypeId] { T::derived_types() } @@ -438,24 +443,24 @@ macro_rules! impl_reflect_inner_mutability { }; } -impl Reflect for parking_lot::Mutex { +impl Reflect for parking_lot::Mutex { impl_reflect_inner_mutability!(self, { self.lock() }, { self.into_inner() }); } -impl Reflect for parking_lot::RwLock { +impl Reflect for parking_lot::RwLock { impl_reflect_inner_mutability!(self, { self.write() }, { self.into_inner() }); } #[allow(clippy::mut_mutex_lock)] -impl Reflect for std::sync::Mutex { +impl Reflect for std::sync::Mutex { impl_reflect_inner_mutability!(self, { self.lock().unwrap() }, { self.into_inner() }); } -impl Reflect for std::sync::RwLock { +impl Reflect for std::sync::RwLock { impl_reflect_inner_mutability!(self, { self.write().unwrap() }, { self.into_inner() }); } -impl Reflect for Arc> { +impl Reflect for Arc> { impl_reflect_inner_mutability!(self, { self.lock() }, { Arc::into_inner(*self) .expect("Value cannot be shared!") @@ -463,7 +468,7 @@ impl Reflect for Arc> { }); } -impl Reflect for Arc> { +impl Reflect for Arc> { impl_reflect_inner_mutability!(self, { self.lock().unwrap() }, { Arc::into_inner(*self) .expect("Value cannot be shared!") @@ -471,7 +476,7 @@ impl Reflect for Arc> { }); } -impl Reflect for Arc> { +impl Reflect for Arc> { impl_reflect_inner_mutability!(self, { self.write().unwrap() }, { Arc::into_inner(*self) .expect("Value cannot be shared!") @@ -479,7 +484,7 @@ impl Reflect for Arc> { }); } -impl Reflect for Arc> { +impl Reflect for Arc> { impl_reflect_inner_mutability!(self, { self.write() }, { Arc::into_inner(*self) .expect("Value cannot be shared!") @@ -487,11 +492,11 @@ impl Reflect for Arc> { }); } -impl Reflect for RefCell { +impl Reflect for RefCell { impl_reflect_inner_mutability!(self, { self.borrow_mut() }, { self.into_inner() }); } -impl Reflect for Rc> { +impl Reflect for Rc> { impl_reflect_inner_mutability!(self, { self.borrow_mut() }, { Rc::into_inner(*self) .expect("Value cannot be shared!") diff --git a/fyrox-core/src/variable.rs b/fyrox-core/src/variable.rs index 06856fbd4..46e553a44 100644 --- a/fyrox-core/src/variable.rs +++ b/fyrox-core/src/variable.rs @@ -381,6 +381,10 @@ where file!() } + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } + fn derived_types() -> &'static [TypeId] where Self: Sized, @@ -839,7 +843,7 @@ mod test { assert!(va.value_equals(&vb)) } - #[derive(Reflect, Debug)] + #[derive(Reflect, Clone, Debug)] enum SomeEnum { Bar(InheritableVariable), Baz { diff --git a/fyrox-graph/src/lib.rs b/fyrox-graph/src/lib.rs index bea1f40e4..2e0ee1887 100644 --- a/fyrox-graph/src/lib.rs +++ b/fyrox-graph/src/lib.rs @@ -1598,6 +1598,10 @@ mod test { fn query_derived_types(&self) -> &'static [TypeId] { Self::derived_types() } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl NameProvider for Node { @@ -1622,7 +1626,7 @@ mod test { /// A wrapper for node pool record that allows to define custom visit method to have full /// control over instantiation process at deserialization. - #[derive(Debug, Default, Reflect)] + #[derive(Debug, Default, Clone, Reflect)] pub struct NodeContainer(Option); impl Visit for NodeContainer { @@ -1711,7 +1715,7 @@ mod test { } } - #[derive(Default, TypeUuidProvider, Visit, Reflect, Debug)] + #[derive(Default, Clone, TypeUuidProvider, Visit, Reflect, Debug)] #[type_uuid(id = "fc887063-7780-44af-8710-5e0bcf9a83fd")] pub struct Graph { root: Handle, @@ -1730,6 +1734,10 @@ mod test { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl PrefabData for Graph { diff --git a/fyrox-impl/src/engine/mod.rs b/fyrox-impl/src/engine/mod.rs index 2a0bedf08..bdd9d4869 100644 --- a/fyrox-impl/src/engine/mod.rs +++ b/fyrox-impl/src/engine/mod.rs @@ -283,6 +283,7 @@ struct SceneLoadingOptions { /// use std::path::Path; /// /// #[derive(Visit, Reflect, Debug)] +/// #[reflect(non_cloneable)] /// struct MyGame { /// scene: Handle, /// } @@ -1707,7 +1708,7 @@ impl Engine { // some methods (`Base::root_resource` in particular) won't work // correctly. scene: scene - .clone( + .clone_ex( scene.graph.get_root(), &mut |_, _| true, &mut |_, _| {}, diff --git a/fyrox-impl/src/engine/task.rs b/fyrox-impl/src/engine/task.rs index e5a3048dd..ee8b572da 100644 --- a/fyrox-impl/src/engine/task.rs +++ b/fyrox-impl/src/engine/task.rs @@ -103,6 +103,7 @@ impl TaskPoolHandler { /// # use std::{fs::File, io::Read}; /// /// #[derive(Visit, Reflect, Debug)] + /// #[reflect(non_cloneable)] /// struct MyGame { /// data: Option>, /// } diff --git a/fyrox-impl/src/material/mod.rs b/fyrox-impl/src/material/mod.rs index 0da3805a8..00fccdaaf 100644 --- a/fyrox-impl/src/material/mod.rs +++ b/fyrox-impl/src/material/mod.rs @@ -765,6 +765,10 @@ impl ResourceData for Material { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// A set of possible errors that can occur when working with materials. diff --git a/fyrox-impl/src/material/shader/mod.rs b/fyrox-impl/src/material/shader/mod.rs index 44eaab8f9..d42f5268d 100644 --- a/fyrox-impl/src/material/shader/mod.rs +++ b/fyrox-impl/src/material/shader/mod.rs @@ -543,7 +543,7 @@ pub const STANDARD_SHADER_SOURCES: [&str; 6] = [ /// /// Usually you don't need to access internals of the shader, but there sometimes could be a need to /// read shader definition, to get supported passes and properties. -#[derive(Default, Debug, Reflect, Visit)] +#[derive(Default, Debug, Clone, Reflect, Visit)] pub struct Shader { /// Shader definition contains description of properties and render passes. #[visit(optional)] @@ -561,7 +561,7 @@ impl TypeUuidProvider for Shader { } /// A render pass definition. See [`ShaderResource`] docs for more info about render passes. -#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Eq, Reflect, Visit)] +#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Reflect, Visit)] pub struct RenderPassDefinition { /// A name of render pass. pub name: String, @@ -581,7 +581,7 @@ pub struct RenderPassDefinition { } /// A definition of the shader. -#[derive(Default, Serialize, Deserialize, Debug, PartialEq, Reflect, Visit)] +#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Reflect, Visit)] pub struct ShaderDefinition { /// A name of the shader. pub name: String, @@ -845,6 +845,10 @@ impl ResourceData for Shader { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// A set of possible error variants that can occur during shader loading. diff --git a/fyrox-impl/src/plugin/mod.rs b/fyrox-impl/src/plugin/mod.rs index ca28d0a45..5bf4b1175 100644 --- a/fyrox-impl/src/plugin/mod.rs +++ b/fyrox-impl/src/plugin/mod.rs @@ -227,6 +227,7 @@ impl dyn Plugin { /// # use std::str::FromStr; /// /// #[derive(Default, Visit, Reflect, Debug)] +/// #[reflect(non_cloneable)] /// struct MyPlugin {} /// /// impl Plugin for MyPlugin { diff --git a/fyrox-impl/src/resource/curve/mod.rs b/fyrox-impl/src/resource/curve/mod.rs index 3ddd3bb47..a6d8dc721 100644 --- a/fyrox-impl/src/resource/curve/mod.rs +++ b/fyrox-impl/src/resource/curve/mod.rs @@ -74,7 +74,7 @@ impl From for CurveResourceError { } /// State of the [`CurveResource`] -#[derive(Debug, Visit, Default, Reflect)] +#[derive(Debug, Clone, Visit, Default, Reflect)] pub struct CurveResourceState { /// Actual curve. pub curve: Curve, @@ -93,6 +93,10 @@ impl ResourceData for CurveResourceState { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl TypeUuidProvider for CurveResourceState { diff --git a/fyrox-impl/src/resource/model/mod.rs b/fyrox-impl/src/resource/model/mod.rs index 9499f3ad1..bcd2282fc 100644 --- a/fyrox-impl/src/resource/model/mod.rs +++ b/fyrox-impl/src/resource/model/mod.rs @@ -80,7 +80,7 @@ use strum_macros::{AsRefStr, EnumString, VariantNames}; pub mod loader; /// See module docs. -#[derive(Debug, Visit, Reflect)] +#[derive(Debug, Clone, Visit, Reflect)] pub struct Model { #[visit(skip)] pub(crate) mapping: NodeMapping, @@ -612,6 +612,10 @@ impl ResourceData for Model { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl Default for Model { diff --git a/fyrox-impl/src/scene/graph/mod.rs b/fyrox-impl/src/scene/graph/mod.rs index 93c9d6708..f25ef96bf 100644 --- a/fyrox-impl/src/scene/graph/mod.rs +++ b/fyrox-impl/src/scene/graph/mod.rs @@ -186,6 +186,18 @@ pub struct Graph { instance_id_map: FxHashMap>, } +impl Clone for Graph { + fn clone(&self) -> Self { + self.clone_ex( + self.root, + &mut |_, _| true, + &mut |_, _| {}, + &mut |_, _, _| {}, + ) + .0 + } +} + impl Default for Graph { fn default() -> Self { let (script_message_sender, script_message_receiver) = channel(); @@ -1408,7 +1420,7 @@ impl Graph { /// Creates deep copy of graph. Allows filtering while copying, returns copy and /// old-to-new node mapping. #[inline] - pub fn clone( + pub fn clone_ex( &self, root: Handle, filter: &mut F, diff --git a/fyrox-impl/src/scene/mesh/surface.rs b/fyrox-impl/src/scene/mesh/surface.rs index 312ae1916..326f92773 100644 --- a/fyrox-impl/src/scene/mesh/surface.rs +++ b/fyrox-impl/src/scene/mesh/surface.rs @@ -250,6 +250,10 @@ impl ResourceData for SurfaceData { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl SurfaceData { diff --git a/fyrox-impl/src/scene/mod.rs b/fyrox-impl/src/scene/mod.rs index eb941f86e..16a18dc56 100644 --- a/fyrox-impl/src/scene/mod.rs +++ b/fyrox-impl/src/scene/mod.rs @@ -238,6 +238,12 @@ pub struct Scene { pub enabled: InheritableVariable, } +impl Clone for Scene { + fn clone(&self) -> Self { + self.clone_one_to_one().0 + } +} + impl Default for Scene { fn default() -> Self { Self { @@ -465,7 +471,7 @@ impl Scene { /// Creates deep copy of a scene, filter predicate allows you to filter out nodes /// by your criteria. - pub fn clone( + pub fn clone_ex( &self, root: Handle, filter: &mut F, @@ -479,7 +485,7 @@ impl Scene { { let (graph, old_new_map) = self.graph - .clone(root, filter, pre_process_callback, post_process_callback); + .clone_ex(root, filter, pre_process_callback, post_process_callback); ( Self { @@ -495,7 +501,7 @@ impl Scene { /// Creates deep copy of a scene. Same as [`Self::clone`], but does 1:1 cloning. pub fn clone_one_to_one(&self) -> (Self, NodeHandleMap) { - self.clone( + self.clone_ex( self.graph.get_root(), &mut |_, _| true, &mut |_, _| {}, diff --git a/fyrox-impl/src/scene/node/container.rs b/fyrox-impl/src/scene/node/container.rs index a8d40b73b..234dd3c32 100644 --- a/fyrox-impl/src/scene/node/container.rs +++ b/fyrox-impl/src/scene/node/container.rs @@ -35,7 +35,7 @@ use fyrox_core::visitor::error::VisitError; /// A wrapper for node pool record that allows to define custom visit method to have full /// control over instantiation process at deserialization. -#[derive(Debug, Default, Reflect)] +#[derive(Debug, Clone, Default, Reflect)] pub struct NodeContainer(Option); fn read_node(name: &str, visitor: &mut Visitor) -> Result { diff --git a/fyrox-impl/src/scene/node/mod.rs b/fyrox-impl/src/scene/node/mod.rs index f28b11f84..458171b28 100644 --- a/fyrox-impl/src/scene/node/mod.rs +++ b/fyrox-impl/src/scene/node/mod.rs @@ -611,6 +611,10 @@ impl Reflect for Node { fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) { self.0.deref_mut().field_mut(name, func) } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } #[cfg(test)] diff --git a/fyrox-impl/src/scene/ragdoll.rs b/fyrox-impl/src/scene/ragdoll.rs index 36920574a..6d90d8094 100644 --- a/fyrox-impl/src/scene/ragdoll.rs +++ b/fyrox-impl/src/scene/ragdoll.rs @@ -243,6 +243,10 @@ impl Reflect for Limb { let this = std::mem::replace(self, value.take()?); Ok(Box::new(this)) } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl Visit for Limb { diff --git a/fyrox-impl/src/scene/tilemap/brush.rs b/fyrox-impl/src/scene/tilemap/brush.rs index d6219af40..02c1d366e 100644 --- a/fyrox-impl/src/scene/tilemap/brush.rs +++ b/fyrox-impl/src/scene/tilemap/brush.rs @@ -568,6 +568,10 @@ impl ResourceData for TileMapBrush { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// Standard tile map brush loader. diff --git a/fyrox-impl/src/scene/tilemap/data.rs b/fyrox-impl/src/scene/tilemap/data.rs index f462c60e3..2c042d01d 100644 --- a/fyrox-impl/src/scene/tilemap/data.rs +++ b/fyrox-impl/src/scene/tilemap/data.rs @@ -207,6 +207,10 @@ impl ResourceData for TileMapData { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl TileSource for TileMapData { diff --git a/fyrox-impl/src/scene/tilemap/mod.rs b/fyrox-impl/src/scene/tilemap/mod.rs index 4fd7ffa80..c25579084 100644 --- a/fyrox-impl/src/scene/tilemap/mod.rs +++ b/fyrox-impl/src/scene/tilemap/mod.rs @@ -402,7 +402,7 @@ pub enum PageType { /// Both pages and tiles have a TileDefinitionHandle and are rendered using /// [`TileRenderData`]. For pages this is due to having an icon to allow the user to select the page. /// Both pages and tiles can be selected by the user, moved, and deleted. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Reflect)] pub enum ResourceTilePosition { /// This position refers to some page, and so it lacks tile coordinates. Page(Vector2), diff --git a/fyrox-impl/src/scene/tilemap/tile_collider.rs b/fyrox-impl/src/scene/tilemap/tile_collider.rs index 023422496..721fee548 100644 --- a/fyrox-impl/src/scene/tilemap/tile_collider.rs +++ b/fyrox-impl/src/scene/tilemap/tile_collider.rs @@ -194,6 +194,10 @@ impl ResourceData for CustomTileCollider { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl OrthoTransform for CustomTileCollider { diff --git a/fyrox-impl/src/scene/tilemap/tile_source.rs b/fyrox-impl/src/scene/tilemap/tile_source.rs index 0aa94cc17..44aa43776 100644 --- a/fyrox-impl/src/scene/tilemap/tile_source.rs +++ b/fyrox-impl/src/scene/tilemap/tile_source.rs @@ -57,22 +57,22 @@ fn position_to_vector(source: PalettePosition) -> Vector2 { /// A 2D grid that contains tile data. #[derive(Default, Debug, Clone, PartialEq, Reflect)] -pub struct TileGridMap(FxHashMap, V>); +pub struct TileGridMap(FxHashMap, V>); -impl Visit for TileGridMap { +impl Visit for TileGridMap { fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult { self.0.visit(name, visitor) } } -impl Deref for TileGridMap { +impl Deref for TileGridMap { type Target = FxHashMap, V>; fn deref(&self) -> &Self::Target { &self.0 } } -impl DerefMut for TileGridMap { +impl DerefMut for TileGridMap { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } @@ -381,7 +381,7 @@ pub struct Stamp { /// Each cell of a stamp must have a tile handle and it may optionally have /// the handle of a brush cell where the tile was taken from. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Reflect)] pub struct StampElement { /// The stamp cell's tile handle pub handle: TileDefinitionHandle, diff --git a/fyrox-impl/src/scene/tilemap/tileset.rs b/fyrox-impl/src/scene/tilemap/tileset.rs index b7d48d3de..4b759f1b3 100644 --- a/fyrox-impl/src/scene/tilemap/tileset.rs +++ b/fyrox-impl/src/scene/tilemap/tileset.rs @@ -2118,6 +2118,10 @@ impl ResourceData for TileSet { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// An alias for `Resource`. diff --git a/fyrox-impl/src/scene/tilemap/update.rs b/fyrox-impl/src/scene/tilemap/update.rs index 6eed42c70..4ed6b06dd 100644 --- a/fyrox-impl/src/scene/tilemap/update.rs +++ b/fyrox-impl/src/scene/tilemap/update.rs @@ -585,7 +585,7 @@ impl TileSetUpdate { /// A stamp element plus the transformation of the [`Stamp`] where the element is taken from, /// allowing the stamp element itself to be later transformed before it is applied to a tile map, /// tile set, or brush. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Reflect)] pub struct RotTileHandle { /// The transformation of the element. pub transform: OrthoTransformation, diff --git a/fyrox-impl/src/script/mod.rs b/fyrox-impl/src/script/mod.rs index 6c8daf1db..b112c2869 100644 --- a/fyrox-impl/src/script/mod.rs +++ b/fyrox-impl/src/script/mod.rs @@ -334,6 +334,7 @@ pub struct ScriptContext<'a, 'b, 'c> { /// # }; /// # /// #[derive(Visit, Reflect, Default, Debug)] + /// #[reflect(non_cloneable)] /// struct Game { /// player_name: String, /// } @@ -751,6 +752,10 @@ impl Reflect for Script { fn as_list_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectList>)) { self.instance.deref_mut().as_list_mut(func) } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl Deref for Script { diff --git a/fyrox-impl/src/utils/behavior/mod.rs b/fyrox-impl/src/utils/behavior/mod.rs index bd8e5dcd1..a1af2365f 100644 --- a/fyrox-impl/src/utils/behavior/mod.rs +++ b/fyrox-impl/src/utils/behavior/mod.rs @@ -126,7 +126,7 @@ where #[derive(Debug, PartialEq, Visit, Clone)] pub struct BehaviorTree where - B: Clone, + B: Clone + 'static, { nodes: Pool>, root: Handle>, diff --git a/fyrox-math/Cargo.toml b/fyrox-math/Cargo.toml index 19c5de331..17a5aaa05 100644 --- a/fyrox-math/Cargo.toml +++ b/fyrox-math/Cargo.toml @@ -14,7 +14,7 @@ repository = "https://github.com/FyroxEngine/Fyrox" rust-version = "1.86" [dependencies] -rectutils = "0.3.0" +rectutils = "0.4.0" nalgebra = { version = "0.33", features = ["bytemuck"] } arrayvec = "0.7.4" num-traits = "0.2.18" diff --git a/fyrox-resource/src/builtin.rs b/fyrox-resource/src/builtin.rs index 15ea01ff0..66f282a20 100644 --- a/fyrox-resource/src/builtin.rs +++ b/fyrox-resource/src/builtin.rs @@ -93,7 +93,7 @@ pub struct UntypedBuiltInResource { /// }; /// use std::{error::Error, path::Path}; /// -/// #[derive(TypeUuidProvider, Default, Debug, Visit, Reflect)] +/// #[derive(TypeUuidProvider, Default, Debug, Clone, Visit, Reflect)] /// #[type_uuid(id = "00d036bb-fbed-47f7-94e3-b3fce93dee17")] /// struct MyResource { /// some_data: String, @@ -111,6 +111,10 @@ pub struct UntypedBuiltInResource { /// fn can_be_saved(&self) -> bool { /// false /// } +/// +/// fn try_clone_box(&self) -> Option> { +/// Some(Box::new(self.clone())) +/// } /// } /// /// fn register_built_in_resource(resource_manager: &ResourceManager) { diff --git a/fyrox-resource/src/constructor.rs b/fyrox-resource/src/constructor.rs index 5ce91f9a5..08f881f44 100644 --- a/fyrox-resource/src/constructor.rs +++ b/fyrox-resource/src/constructor.rs @@ -112,7 +112,7 @@ mod test { use super::*; - #[derive(Debug, Default, Reflect, Visit)] + #[derive(Debug, Default, Clone, Reflect, Visit)] struct Stub {} impl ResourceData for Stub { @@ -127,6 +127,10 @@ mod test { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl TypeUuidProvider for Stub { diff --git a/fyrox-resource/src/lib.rs b/fyrox-resource/src/lib.rs index cec8ffa7c..53f6a0332 100644 --- a/fyrox-resource/src/lib.rs +++ b/fyrox-resource/src/lib.rs @@ -96,6 +96,10 @@ pub trait ResourceData: Debug + Visit + Send + Reflect { /// resource type supports saving, for example there might be temporary resource type that is /// used only at runtime which does not need saving at all. fn can_be_saved(&self) -> bool; + + /// Tries to clone the resource data. This method can return `None` if the underlying type is + /// non-cloneable. + fn try_clone_box(&self) -> Option>; } /// Extension trait for a resource data of a particular type, which adds additional functionality, @@ -159,10 +163,7 @@ where /// /// Default state of the resource will be [`ResourceState::Ok`] with `T::default`. #[derive(Debug, Reflect)] -pub struct Resource -where - T: TypedResourceData, -{ +pub struct Resource { untyped: UntypedResource, #[reflect(hidden)] phantom: PhantomData, @@ -409,10 +410,7 @@ where } } -impl Clone for Resource -where - T: TypedResourceData, -{ +impl Clone for Resource { #[inline] fn clone(&self) -> Self { Self { @@ -696,7 +694,7 @@ mod tests { sync::Arc, }; - #[derive(Serialize, Deserialize, Default, Debug, Visit, Reflect, TypeUuidProvider)] + #[derive(Serialize, Deserialize, Default, Debug, Clone, Visit, Reflect, TypeUuidProvider)] #[type_uuid(id = "241d14c7-079e-4395-a63c-364f0fc3e6ea")] struct MyData { data: u32, @@ -741,6 +739,10 @@ mod tests { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } struct MyDataLoader {} diff --git a/fyrox-resource/src/manager.rs b/fyrox-resource/src/manager.rs index c1af9defa..0ae9b9900 100644 --- a/fyrox-resource/src/manager.rs +++ b/fyrox-resource/src/manager.rs @@ -22,6 +22,7 @@ //! docs for more info. pub use crate::builtin::*; +use crate::state::ResourceDataWrapper; use crate::{ constructor::ResourceConstructorContainer, core::{ @@ -737,7 +738,7 @@ impl ResourceManagerState { assert!(mutex_guard.kind.is_external()); mutex_guard.state.commit(ResourceState::Ok { - data, + data: ResourceDataWrapper(data), resource_uuid, }); @@ -947,7 +948,7 @@ mod test { }; use std::{error::Error, fs::File, time::Duration}; - #[derive(Debug, Default, Reflect, Visit)] + #[derive(Debug, Default, Clone, Reflect, Visit)] struct Stub {} impl TypeUuidProvider for Stub { @@ -968,6 +969,10 @@ mod test { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl ResourceLoader for Stub { diff --git a/fyrox-resource/src/state.rs b/fyrox-resource/src/state.rs index a7cc41944..e782a7daa 100644 --- a/fyrox-resource/src/state.rs +++ b/fyrox-resource/src/state.rs @@ -26,7 +26,9 @@ use crate::{ manager::ResourceManager, ResourceData, ResourceLoadError, }; +use fyrox_core::reflect::ReflectHandle; use fyrox_core::warn; +use std::any::{Any, TypeId}; use std::path::PathBuf; use std::{ ops::{Deref, DerefMut}, @@ -75,6 +77,168 @@ impl LoadError { } } +#[doc(hidden)] +#[derive(Debug)] +pub struct ResourceDataWrapper(pub Box); + +impl Reflect for ResourceDataWrapper { + fn source_path() -> &'static str + where + Self: Sized, + { + file!() + } + + fn derived_types() -> &'static [TypeId] + where + Self: Sized, + { + &[] + } + + fn try_clone_box(&self) -> Option> { + Reflect::try_clone_box(&*self.0) + } + + fn query_derived_types(&self) -> &'static [TypeId] { + self.deref().query_derived_types() + } + + fn type_name(&self) -> &'static str { + self.deref().type_name() + } + + fn doc(&self) -> &'static str { + self.deref().doc() + } + + fn fields_ref(&self, func: &mut dyn FnMut(&[FieldRef])) { + self.deref().fields_ref(func) + } + + fn fields_mut(&mut self, func: &mut dyn FnMut(&mut [FieldMut])) { + self.deref_mut().fields_mut(func) + } + + fn into_any(self: Box) -> Box { + self + } + + fn as_any(&self, func: &mut dyn FnMut(&dyn Any)) { + self.deref().as_any(func) + } + + fn as_any_mut(&mut self, func: &mut dyn FnMut(&mut dyn Any)) { + self.deref_mut().as_any_mut(func) + } + + fn as_reflect(&self, func: &mut dyn FnMut(&dyn Reflect)) { + self.deref().as_reflect(func) + } + + fn as_reflect_mut(&mut self, func: &mut dyn FnMut(&mut dyn Reflect)) { + self.deref_mut().as_reflect_mut(func) + } + + fn set(&mut self, value: Box) -> Result, Box> { + self.deref_mut().set(value) + } + + fn assembly_name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn type_assembly_name() -> &'static str + where + Self: Sized, + { + env!("CARGO_PKG_NAME") + } + + fn set_field( + &mut self, + field: &str, + value: Box, + func: &mut dyn FnMut(Result, Box>), + ) { + self.deref_mut().set_field(field, value, func) + } + + fn field(&self, name: &str, func: &mut dyn FnMut(Option<&dyn Reflect>)) { + self.deref().field(name, func) + } + + fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) { + self.deref_mut().field_mut(name, func) + } + + fn as_array(&self, func: &mut dyn FnMut(Option<&dyn ReflectArray>)) { + self.deref().as_array(func) + } + + fn as_array_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectArray>)) { + self.deref_mut().as_array_mut(func) + } + + fn as_list(&self, func: &mut dyn FnMut(Option<&dyn ReflectList>)) { + self.deref().as_list(func) + } + + fn as_list_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectList>)) { + self.deref_mut().as_list_mut(func) + } + + fn as_inheritable_variable( + &self, + func: &mut dyn FnMut(Option<&dyn ReflectInheritableVariable>), + ) { + self.deref().as_inheritable_variable(func) + } + + fn as_inheritable_variable_mut( + &mut self, + func: &mut dyn FnMut(Option<&mut dyn ReflectInheritableVariable>), + ) { + self.deref_mut().as_inheritable_variable_mut(func) + } + + fn as_hash_map(&self, func: &mut dyn FnMut(Option<&dyn ReflectHashMap>)) { + self.deref().as_hash_map(func) + } + + fn as_hash_map_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHashMap>)) { + self.deref_mut().as_hash_map_mut(func) + } + + fn as_handle(&self, func: &mut dyn FnMut(Option<&dyn ReflectHandle>)) { + self.deref().as_handle(func) + } + + fn as_handle_mut(&mut self, func: &mut dyn FnMut(Option<&mut dyn ReflectHandle>)) { + self.deref_mut().as_handle_mut(func) + } +} + +impl Deref for ResourceDataWrapper { + type Target = dyn ResourceData; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl DerefMut for ResourceDataWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.0 + } +} + +impl Clone for ResourceDataWrapper { + fn clone(&self) -> Self { + Self(ResourceData::try_clone_box(&*self.0).unwrap()) + } +} + /// Resource could be in three possible states (a small state machine): /// /// 1. Pending - it is loading or queued for loading. @@ -101,7 +265,7 @@ impl LoadError { /// to get the UUID earlier: the UUID is stored in a metadata file which exists only if the resource /// is present. It is somewhat possible to get a UUID when a resource is failed to load, but not in /// 100% cases. -#[derive(Debug, Reflect)] +#[derive(Debug, Clone, Reflect)] pub enum ResourceState { /// Resource is loading from external resource or in the queue to load. Pending { @@ -127,7 +291,7 @@ pub enum ResourceState { /// Unique id of the resource. resource_uuid: Uuid, /// Actual data of the resource. - data: Box, + data: ResourceDataWrapper, }, } @@ -185,7 +349,7 @@ impl ResourceState { *self = Self::Ok { resource_uuid, - data: instance, + data: ResourceDataWrapper(instance), }; } else { return Err(VisitError::User(format!( @@ -235,7 +399,7 @@ impl ResourceState { pub fn new_ok(resource_uuid: Uuid, data: T) -> Self { Self::Ok { resource_uuid, - data: Box::new(data), + data: ResourceDataWrapper(Box::new(data)), } } @@ -244,7 +408,7 @@ impl ResourceState { pub fn new_ok_untyped(resource_uuid: Uuid, data: Box) -> Self { Self::Ok { resource_uuid, - data, + data: ResourceDataWrapper(data), } } @@ -294,7 +458,7 @@ impl ResourceState { pub fn commit_ok(&mut self, resource_uuid: Uuid, data: T) { self.commit(ResourceState::Ok { resource_uuid, - data: Box::new(data), + data: ResourceDataWrapper(Box::new(data)), }) } @@ -318,7 +482,7 @@ mod test { use super::*; - #[derive(Debug, Default, Reflect, Visit)] + #[derive(Debug, Default, Clone, Reflect, Visit)] struct Stub {} impl ResourceData for Stub { @@ -333,6 +497,10 @@ mod test { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl TypeUuidProvider for Stub { diff --git a/fyrox-resource/src/untyped.rs b/fyrox-resource/src/untyped.rs index dafe96bbf..90683f227 100644 --- a/fyrox-resource/src/untyped.rs +++ b/fyrox-resource/src/untyped.rs @@ -20,6 +20,7 @@ //! A module for untyped resources. See [`UntypedResource`] docs for more info. +use crate::state::ResourceDataWrapper; use crate::{ core::{ math::curve::Curve, parking_lot::Mutex, reflect::prelude::*, uuid, uuid::Uuid, @@ -154,7 +155,7 @@ impl Display for ResourceKind { /// Header of a resource, it contains a common data about the resource, such as its data type uuid, /// its kind, etc. -#[derive(Reflect, Debug)] +#[derive(Reflect, Clone, Debug)] pub struct ResourceHeader { /// Kind of the resource. See [`ResourceKind`] for more info. pub kind: ResourceKind, @@ -214,7 +215,7 @@ impl Visit for ResourceHeader { instance.visit("Details", &mut region)?; self.state = ResourceState::Ok { - data: instance, + data: ResourceDataWrapper(instance), // The old format does not contain an uuid. resource_uuid: Uuid::nil(), }; @@ -609,6 +610,10 @@ mod test { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(*self)) + } } impl TypeUuidProvider for Stub { @@ -660,7 +665,7 @@ mod test { let mut r = UntypedResource(Arc::new(Mutex::new(ResourceHeader { kind: ResourceKind::External, state: ResourceState::Ok { - data: Box::new(stub), + data: ResourceDataWrapper(Box::new(stub)), resource_uuid: Uuid::new_v4(), }, old_format_path: None, diff --git a/fyrox-scripts/src/lib.rs b/fyrox-scripts/src/lib.rs index 643b70590..cb0483772 100644 --- a/fyrox-scripts/src/lib.rs +++ b/fyrox-scripts/src/lib.rs @@ -36,6 +36,7 @@ pub mod camera; /// # }; /// # /// # #[derive(Visit, Reflect, Debug)] +/// # #[reflect(non_cloneable)] /// # struct Game; /// # /// # impl Plugin for Game { diff --git a/fyrox-sound/src/buffer/generic.rs b/fyrox-sound/src/buffer/generic.rs index 8a2d8c2f3..f8c1f2b89 100644 --- a/fyrox-sound/src/buffer/generic.rs +++ b/fyrox-sound/src/buffer/generic.rs @@ -51,7 +51,7 @@ use std::time::Duration; use super::SoundBufferResourceLoadError; /// Samples container. -#[derive(Debug, Default, Visit, Reflect)] +#[derive(Debug, Default, Visit, Clone, Reflect)] pub struct Samples(pub Vec); impl Deref for Samples { @@ -69,7 +69,7 @@ impl DerefMut for Samples { } /// Generic sound buffer that contains decoded samples and allows random access. -#[derive(Debug, Default, Visit, Reflect)] +#[derive(Debug, Clone, Default, Visit, Reflect)] pub struct GenericBuffer { /// Interleaved decoded samples (mono sounds: L..., stereo sounds: LR...) /// For streaming buffers it contains only small part of decoded data diff --git a/fyrox-sound/src/buffer/mod.rs b/fyrox-sound/src/buffer/mod.rs index da0922244..e7762e5e3 100644 --- a/fyrox-sound/src/buffer/mod.rs +++ b/fyrox-sound/src/buffer/mod.rs @@ -239,6 +239,7 @@ impl std::error::Error for SoundBufferResourceLoadError {} /// Sound buffer is a data source for sound sources. See module documentation for more info. #[derive(Debug, Visit, Reflect)] +#[reflect(non_cloneable)] pub enum SoundBuffer { /// General-purpose buffer, usually contains all the data and allows random /// access to samples. It is also used to make streaming buffer via composition. @@ -357,4 +358,8 @@ impl ResourceData for SoundBuffer { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + None + } } diff --git a/fyrox-sound/src/buffer/streaming.rs b/fyrox-sound/src/buffer/streaming.rs index cf27c0265..c55adf8b5 100644 --- a/fyrox-sound/src/buffer/streaming.rs +++ b/fyrox-sound/src/buffer/streaming.rs @@ -61,6 +61,7 @@ use std::{ /// Streaming buffer for long sounds. Does not support random access. #[derive(Debug, Default, Visit, Reflect)] +#[reflect(non_cloneable)] pub struct StreamingBuffer { pub(crate) generic: GenericBuffer, /// Count of sources that share this buffer, it is important to keep only one diff --git a/fyrox-sound/src/renderer/hrtf.rs b/fyrox-sound/src/renderer/hrtf.rs index cf2fcdce8..b769d97f5 100644 --- a/fyrox-sound/src/renderer/hrtf.rs +++ b/fyrox-sound/src/renderer/hrtf.rs @@ -203,7 +203,7 @@ impl HrtfRenderer { /// Wrapper for [`HrirSphere`] to be able to use it in the resource manager, that will handle async resource /// loading automatically. -#[derive(Reflect, Default, Visit)] +#[derive(Reflect, Default, Clone, Visit)] pub struct HrirSphereResourceData { #[reflect(hidden)] #[visit(skip)] @@ -234,6 +234,10 @@ impl ResourceData for HrirSphereResourceData { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// Resource loader for [`HrirSphereResource`]. diff --git a/fyrox-texture/src/lib.rs b/fyrox-texture/src/lib.rs index 60a0f8a78..043ffd2ee 100644 --- a/fyrox-texture/src/lib.rs +++ b/fyrox-texture/src/lib.rs @@ -345,6 +345,10 @@ impl ResourceData for Texture { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } impl Visit for Texture { diff --git a/fyrox-ui/src/font/mod.rs b/fyrox-ui/src/font/mod.rs index 8f6fad6ac..b168eaadd 100644 --- a/fyrox-ui/src/font/mod.rs +++ b/fyrox-ui/src/font/mod.rs @@ -43,7 +43,7 @@ use std::{ pub mod loader; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FontGlyph { pub bitmap_top: f32, pub bitmap_left: f32, @@ -56,6 +56,7 @@ pub struct FontGlyph { } /// Page is a storage for rasterized glyphs. +#[derive(Clone)] pub struct Page { pub pixels: Vec, pub texture: Option, @@ -75,7 +76,7 @@ impl Debug for Page { /// Atlas is a storage for glyphs of a particular size, each atlas could have any number of pages to /// store the rasterized glyphs. -#[derive(Default, Debug)] +#[derive(Default, Clone, Debug)] pub struct Atlas { pub glyphs: Vec, pub char_map: FxHashMap, @@ -210,7 +211,7 @@ impl Atlas { } } -#[derive(Default, Debug, Reflect, Visit)] +#[derive(Default, Clone, Debug, Reflect, Visit)] #[reflect(hide_all)] pub struct Font { #[visit(skip)] @@ -235,6 +236,10 @@ impl ResourceData for Font { fn can_be_saved(&self) -> bool { false } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } #[derive(Copy, Clone, Default, Debug)] diff --git a/fyrox-ui/src/inspector/editors/mod.rs b/fyrox-ui/src/inspector/editors/mod.rs index be8d4e090..40a8af4f7 100644 --- a/fyrox-ui/src/inspector/editors/mod.rs +++ b/fyrox-ui/src/inspector/editors/mod.rs @@ -795,7 +795,7 @@ impl PropertyEditorDefinitionContainer { pub fn register_inheritable_styleable_inspectable(&self) where - T: Reflect + FieldValue, + T: Reflect + FieldValue + Clone + PartialEq, { assert!(self .insert(InspectablePropertyEditorDefinition::::new()) @@ -829,7 +829,13 @@ impl PropertyEditorDefinitionContainer { pub fn register_inheritable_styleable_enum(&self) where - T: InspectableEnum + FieldValue + VariantNames + AsRef + FromStr + Debug, + T: InspectableEnum + + FieldValue + + VariantNames + + AsRef + + FromStr + + Debug + + PartialEq, { assert!(self .insert(EnumPropertyEditorDefinition::::new()) diff --git a/fyrox-ui/src/lib.rs b/fyrox-ui/src/lib.rs index c59d23ba0..129800de9 100644 --- a/fyrox-ui/src/lib.rs +++ b/fyrox-ui/src/lib.rs @@ -338,7 +338,7 @@ use fyrox_core::pool::{BorrowAs, ErasedHandle}; use fyrox_resource::untyped::ResourceKind; pub use fyrox_texture as texture; -#[derive(Default, Reflect, Debug)] +#[derive(Default, Clone, Reflect, Debug)] pub(crate) struct RcUiNodeHandleInner { handle: Handle, #[reflect(hidden)] @@ -3548,6 +3548,10 @@ impl ResourceData for UserInterface { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } pub mod test { diff --git a/fyrox-ui/src/node/container.rs b/fyrox-ui/src/node/container.rs index 54365ec14..40f3cd9ff 100644 --- a/fyrox-ui/src/node/container.rs +++ b/fyrox-ui/src/node/container.rs @@ -35,7 +35,7 @@ use fyrox_core::visitor::error::VisitError; /// A wrapper for widget pool record that allows to define custom visit method to have full /// control over instantiation process at deserialization. -#[derive(Debug, Default, Reflect)] +#[derive(Debug, Clone, Default, Reflect)] pub struct WidgetContainer(Option); fn read_widget(name: &str, visitor: &mut Visitor) -> Result { diff --git a/fyrox-ui/src/node/mod.rs b/fyrox-ui/src/node/mod.rs index 19f93e9df..a6a1a24c7 100644 --- a/fyrox-ui/src/node/mod.rs +++ b/fyrox-ui/src/node/mod.rs @@ -355,4 +355,8 @@ impl Reflect for UiNode { fn field_mut(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut dyn Reflect>)) { self.0.deref_mut().field_mut(name, func) } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } diff --git a/fyrox-ui/src/style/mod.rs b/fyrox-ui/src/style/mod.rs index 0a53ca696..d926c575f 100644 --- a/fyrox-ui/src/style/mod.rs +++ b/fyrox-ui/src/style/mod.rs @@ -118,7 +118,8 @@ lazy_static! { /// the style and why do we need to store the value as well? The answer is flexibility. In this /// approach style becomes not necessary and the value can be hardcoded. Also, the values of such /// properties can be updated individually. -#[derive(Clone, Debug, Default, Reflect)] +#[derive(Clone, Debug, Reflect, Default)] +#[reflect(bounds = "T: Reflect + Clone")] pub struct StyledProperty { /// Property value. pub property: T, @@ -252,7 +253,7 @@ impl Visit for StyledProperty { /// ui.set_style(StyleResource::new_embedded(style)); /// } /// ``` -#[derive(Visit, Reflect, Default, Debug, TypeUuidProvider)] +#[derive(Visit, Reflect, Clone, Default, Debug, TypeUuidProvider)] #[type_uuid(id = "38a63b49-d765-4c01-8fb5-202cc43d607e")] pub struct Style { parent: Option, diff --git a/fyrox-ui/src/style/resource.rs b/fyrox-ui/src/style/resource.rs index 2e96ee6b6..abc8027bc 100644 --- a/fyrox-ui/src/style/resource.rs +++ b/fyrox-ui/src/style/resource.rs @@ -96,6 +96,10 @@ impl ResourceData for Style { fn can_be_saved(&self) -> bool { true } + + fn try_clone_box(&self) -> Option> { + Some(Box::new(self.clone())) + } } /// A loader for style resource. diff --git a/project-manager/src/settings.rs b/project-manager/src/settings.rs index 24e41e4d4..23a929f6a 100644 --- a/project-manager/src/settings.rs +++ b/project-manager/src/settings.rs @@ -91,7 +91,7 @@ pub static DATA_DIR: LazyLock = LazyLock::new(|| { data_dir }); -#[derive(Default, Serialize, Deserialize, Reflect, Debug)] +#[derive(Default, Serialize, Deserialize, Reflect, Clone, Debug)] pub struct SettingsData { #[serde(default = "default_open_ide_command")] #[reflect( @@ -203,7 +203,7 @@ impl Settings { } } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct Project { pub manifest_path: PathBuf, pub name: String,