From c171b68830ca3fad3556e0733ae50d2a582025b0 Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Thu, 13 Mar 2025 20:52:28 +0300 Subject: [PATCH] `Reflect::fields_info_mut` + optimizations - allows iterating over fields while be able to mutate them - reduced FieldInfoRef/Mut size even more to just a pointer+fat pointer --- editor/src/plugins/animation/track.rs | 4 +- .../src/plugins/inspector/editors/texture.rs | 2 +- editor/src/scene/property.rs | 4 +- fyrox-animation/src/machine/transition.rs | 81 ++++++++++-- fyrox-core-derive/src/reflect.rs | 65 +++++++--- fyrox-core-derive/tests/it/reflect.rs | 48 ++----- fyrox-core/src/pool/handle.rs | 84 ++++++++----- fyrox-core/src/pool/mod.rs | 7 +- fyrox-core/src/reflect.rs | 119 ++++++++++++++---- fyrox-core/src/reflect/std_impls.rs | 7 +- fyrox-core/src/variable.rs | 7 +- fyrox-graph/src/lib.rs | 6 +- fyrox-impl/src/scene/node/mod.rs | 6 +- fyrox-impl/src/scene/ragdoll.rs | 73 +++++++++-- fyrox-impl/src/script/mod.rs | 9 +- fyrox-resource/src/manager.rs | 2 +- fyrox-resource/src/state.rs | 2 +- fyrox-ui/src/inspector/editors/array.rs | 10 +- fyrox-ui/src/inspector/editors/collection.rs | 10 +- fyrox-ui/src/inspector/editors/inherit.rs | 6 +- fyrox-ui/src/inspector/editors/inspectable.rs | 2 +- fyrox-ui/src/inspector/editors/mod.rs | 4 +- fyrox-ui/src/inspector/editors/refcell.rs | 6 +- fyrox-ui/src/inspector/editors/style.rs | 6 +- fyrox-ui/src/inspector/mod.rs | 10 +- fyrox-ui/src/node/mod.rs | 6 +- 26 files changed, 411 insertions(+), 175 deletions(-) diff --git a/editor/src/plugins/animation/track.rs b/editor/src/plugins/animation/track.rs index db102499d..107dfc500 100644 --- a/editor/src/plugins/animation/track.rs +++ b/editor/src/plugins/animation/track.rs @@ -1110,8 +1110,8 @@ impl TrackList { let mut descriptors = Vec::new(); if let Some(node) = graph.try_get(node) { node.as_reflect(&mut |node| { - descriptors = object_to_property_tree("", node, &mut |field: &FieldInfo| { - let type_id = field.reflect_value.type_id(); + descriptors = object_to_property_tree("", node, &mut |field: &FieldInfoRef| { + let type_id = field.value.field_value_as_reflect().type_id(); type_id != TypeId::of::() // Vertex buffer cannot be animated (mainly because it contains untyped data). && type_id != TypeId::of::() diff --git a/editor/src/plugins/inspector/editors/texture.rs b/editor/src/plugins/inspector/editors/texture.rs index d5f52f4e3..c9f78bf9b 100644 --- a/editor/src/plugins/inspector/editors/texture.rs +++ b/editor/src/plugins/inspector/editors/texture.rs @@ -183,7 +183,7 @@ pub struct TexturePropertyEditorDefinition { } impl TexturePropertyEditorDefinition { - fn value(&self, field_info: &FieldInfo) -> Result, InspectorError> { + fn value(&self, field_info: &FieldInfoRef) -> Result, InspectorError> { if self.untyped { let value = field_info.cast_value::>()?; let casted = value.as_ref().and_then(|r| r.try_cast::()); diff --git a/editor/src/scene/property.rs b/editor/src/scene/property.rs index b5ced1cb1..576b3cb4e 100644 --- a/editor/src/scene/property.rs +++ b/editor/src/scene/property.rs @@ -170,7 +170,7 @@ pub fn object_to_property_tree( filter: &mut F, ) -> Vec where - F: FnMut(&FieldInfo) -> bool, + F: FnMut(&FieldInfoRef) -> bool, { let mut descriptors = Vec::new(); @@ -180,7 +180,7 @@ where continue; } - let field_ref = field_info.reflect_value; + let field_ref = field_info.value.field_value_as_reflect(); let path = if parent_path.is_empty() { field_info.name.to_owned() diff --git a/fyrox-animation/src/machine/transition.rs b/fyrox-animation/src/machine/transition.rs index 6788b34a9..92f947140 100644 --- a/fyrox-animation/src/machine/transition.rs +++ b/fyrox-animation/src/machine/transition.rs @@ -90,7 +90,7 @@ macro_rules! define_two_args_node { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[ { static METADATA: FieldMetadata = FieldMetadata { @@ -107,10 +107,9 @@ macro_rules! define_two_args_node { doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &*self.lhs, - reflect_value: &*self.lhs, } }, { @@ -127,15 +126,59 @@ macro_rules! define_two_args_node { precision: None,doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &*self.rhs, - reflect_value: &*self.rhs, } }, ]) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut [ + { + static METADATA: FieldMetadata = FieldMetadata { + name: "Lhs", + display_name: "Lhs", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", + }; + + FieldInfoMut { + metadata: &METADATA, + value: &mut *self.lhs, + } + }, + { + static METADATA: FieldMetadata = FieldMetadata { + name: "Rhs", + display_name: "Rhs", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None,doc: "", + }; + + FieldInfoMut { + metadata: &METADATA, + value: &mut *self.rhs, + } + }, + ]) + } + + fn into_any(self: Box) -> Box { self } @@ -262,7 +305,7 @@ impl Reflect for NotNode { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[{ static METADATA: FieldMetadata = FieldMetadata { name: "Lhs", @@ -278,10 +321,32 @@ impl Reflect for NotNode { doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &*self.lhs, - reflect_value: &*self.lhs, + } + }]) + } + + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut [{ + static METADATA: FieldMetadata = FieldMetadata { + name: "Lhs", + display_name: "Lhs", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", + }; + + FieldInfoMut { + metadata: &METADATA, + value: &mut *self.lhs, } }]) } diff --git a/fyrox-core-derive/src/reflect.rs b/fyrox-core-derive/src/reflect.rs index 8c6594abf..d751e8b38 100644 --- a/fyrox-core-derive/src/reflect.rs +++ b/fyrox-core-derive/src/reflect.rs @@ -41,6 +41,7 @@ pub fn impl_reflect(ty_args: &args::TypeArgs) -> TokenStream2 { quote!(func(&mut [])), None, quote!(func(&[])), + quote!(func(&mut [])), ); } @@ -59,6 +60,7 @@ pub fn gen_fields_metadata_body( props: &[Property], field_getters: &[TokenStream2], field_args: &ast::Fields, + is_mut: bool, ) -> TokenStream2 { let props = field_args .fields @@ -67,7 +69,7 @@ pub fn gen_fields_metadata_body( .filter(|(_i, f)| !f.hidden) .zip(props.iter().zip(field_getters)) .map(|((i, field), (prop, field_getter))| { - self::quote_field_prop(&prop.value, i, field_getter, field) + self::quote_field_prop(&prop.value, i, field_getter, field, is_mut) }); quote! { @@ -81,6 +83,7 @@ fn quote_field_prop( nth_field: usize, field_getter: &TokenStream2, field: &args::FieldArgs, + is_mut: bool, ) -> TokenStream2 { let field_ident = match &field.ident { Some(ident) => quote!(#ident), @@ -126,6 +129,12 @@ fn quote_field_prop( let description = field.description.clone().unwrap_or_default(); + let variant = if is_mut { + quote! { FieldInfoMut } + } else { + quote! { FieldInfoRef } + }; + quote! { { static METADATA: FieldMetadata = FieldMetadata { @@ -142,10 +151,9 @@ fn quote_field_prop( description: #description, }; - FieldInfo { + #variant { metadata: &METADATA, value: #field_getter, - reflect_value: #field_getter, } } } @@ -168,7 +176,8 @@ fn impl_reflect_struct(ty_args: &args::TypeArgs, field_args: &args::Fields) -> T let fields = fields.collect::>(); let field_muts = field_muts.collect::>(); - let metadata = gen_fields_metadata_body(&props, &fields, field_args); + let metadata_ref = gen_fields_metadata_body(&props, &fields, field_args, false); + let metadata_mut = gen_fields_metadata_body(&props, &field_muts, field_args, true); let field_body = quote! { match name { @@ -213,7 +222,10 @@ fn impl_reflect_struct(ty_args: &args::TypeArgs, field_args: &args::Fields) -> T fields_mut_body, set_field_body, quote! { - func(&[#metadata]) + func(&[#metadata_ref]) + }, + quote! { + func(&mut [#metadata_mut]) }, ) } @@ -266,7 +278,8 @@ fn struct_set_field_body(ty_args: &args::TypeArgs) -> Option { fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs]) -> TokenStream2 { let mut fields_list = Vec::new(); let mut fields_list_mut = Vec::new(); - let mut fields_info = Vec::new(); + let mut fields_info_ref = Vec::new(); + let mut fields_info_mut = Vec::new(); let (fields, field_muts): (Vec<_>, Vec<_>) = variant_args .iter() .map(|v| { @@ -299,7 +312,8 @@ fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs let fields = fields.collect::>(); let field_muts = field_muts.collect::>(); - let metadata = gen_fields_metadata_body(&props, &fields, &v.fields); + let metadata_ref = gen_fields_metadata_body(&props, &fields, &v.fields, false); + let metadata_mut = gen_fields_metadata_body(&props, &field_muts, &v.fields, true); let fields_list_raw = quote! { #( @@ -339,8 +353,12 @@ fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs #matcher => func(&mut [ #fields_mut_list_raw ]), }); - fields_info.push(quote! { - #matcher => func(&[#metadata]), + fields_info_ref.push(quote! { + #matcher => func(&[#metadata_ref]), + }); + + fields_info_mut.push(quote! { + #matcher => func(&mut [#metadata_mut]), }); (fields, field_muts) @@ -356,6 +374,7 @@ fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs quote!(func(&mut [])), None, quote!(func(&[])), + quote!(func(&mut [])), ) } else { let field_body = quote! { @@ -394,15 +413,24 @@ fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs } }; - let fields_metadata_body = quote! { + let fields_metadata_ref_body = quote! { match self { #( - #fields_info + #fields_info_ref )* _ => func(&[]) } }; + let fields_metadata_mut_body = quote! { + match self { + #( + #fields_info_mut + )* + _ => func(&mut []) + } + }; + self::gen_impl( ty_args, field_body, @@ -410,11 +438,13 @@ fn impl_reflect_enum(ty_args: &args::TypeArgs, variant_args: &[args::VariantArgs fields_body, fields_mut_body, None, - fields_metadata_body, + fields_metadata_ref_body, + fields_metadata_mut_body, ) } } +#[allow(clippy::too_many_arguments)] fn gen_impl( ty_args: &args::TypeArgs, field: TokenStream2, @@ -422,7 +452,8 @@ fn gen_impl( fields: TokenStream2, fields_mut: TokenStream2, set_field: Option, - metadata: TokenStream2, + metadata_ref: TokenStream2, + metadata_mut: TokenStream2, ) -> TokenStream2 { let ty_ident = &ty_args.ident; let generics = ty_args.impl_generics(); @@ -486,8 +517,12 @@ fn gen_impl( #assembly_name } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { - #metadata + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { + #metadata_ref + } + + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + #metadata_mut } fn into_any(self: Box) -> Box { diff --git a/fyrox-core-derive/tests/it/reflect.rs b/fyrox-core-derive/tests/it/reflect.rs index 6da22ff2c..c5fb84d96 100644 --- a/fyrox-core-derive/tests/it/reflect.rs +++ b/fyrox-core-derive/tests/it/reflect.rs @@ -368,15 +368,13 @@ fn inspect_default() { }; let expected = vec![ - FieldInfo { + FieldInfoRef { metadata: &the_field_metadata, value: &data.the_field, - reflect_value: &data.the_field, }, - FieldInfo { + FieldInfoRef { metadata: &another_field_metadata, value: &data.another_field, - reflect_value: &data.another_field, }, ]; @@ -419,12 +417,11 @@ fn inspect_attributes() { }; let expected = vec![ - FieldInfo { + FieldInfoRef { metadata: &x_metadata, value: &data.x, - reflect_value: &data.x, }, - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "y", display_name: "Y", @@ -439,7 +436,6 @@ fn inspect_attributes() { doc: "", }, value: &data.y, - reflect_value: &data.y, }, ]; @@ -457,23 +453,21 @@ fn inspect_struct() { assert_eq!( fields_info, vec![ - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "0", display_name: "0", ..default_prop_metadata() }, value: &x.0, - reflect_value: &x.0, }, - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "1", display_name: "1", ..default_prop_metadata() }, value: &x.1, - reflect_value: &x.1, }, ] ) @@ -510,7 +504,7 @@ fn inspect_enum() { assert_eq!( fields_info, vec![ - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "Named@x", display_name: "X", @@ -520,12 +514,8 @@ fn inspect_enum() { Data::Named { ref x, .. } => x, _ => unreachable!(), }, - reflect_value: match data { - Data::Named { ref x, .. } => x, - _ => unreachable!(), - }, }, - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "Named@y", display_name: "Y", @@ -535,12 +525,8 @@ fn inspect_enum() { Data::Named { ref y, .. } => y, _ => unreachable!(), }, - reflect_value: match data { - Data::Named { ref y, .. } => y, - _ => unreachable!(), - }, }, - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "Named@z", display_name: "Z", @@ -550,10 +536,6 @@ fn inspect_enum() { Data::Named { ref z, .. } => z, _ => unreachable!(), }, - reflect_value: match data { - Data::Named { ref z, .. } => z, - _ => unreachable!(), - }, }, ] ) @@ -565,7 +547,7 @@ fn inspect_enum() { assert_eq!( fields_info, vec![ - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "Tuple@0", display_name: "0", @@ -575,12 +557,8 @@ fn inspect_enum() { Data::Tuple(ref f0, ref _f1) => f0, _ => unreachable!(), }, - reflect_value: match data { - Data::Tuple(ref f0, ref _f1) => f0, - _ => unreachable!(), - }, }, - FieldInfo { + FieldInfoRef { metadata: &FieldMetadata { name: "Tuple@1", display_name: "1", @@ -590,10 +568,6 @@ fn inspect_enum() { Data::Tuple(ref _f0, ref f1) => f1, _ => unreachable!(), }, - reflect_value: match data { - Data::Tuple(ref _f0, ref f1) => f1, - _ => unreachable!(), - }, }, ] ) diff --git a/fyrox-core/src/pool/handle.rs b/fyrox-core/src/pool/handle.rs index 2149d019b..8c6fca465 100644 --- a/fyrox-core/src/pool/handle.rs +++ b/fyrox-core/src/pool/handle.rs @@ -83,6 +83,34 @@ impl ReflectHandle for Handle { } } +static INDEX_METADATA: FieldMetadata = FieldMetadata { + name: "Index", + display_name: "Index", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", +}; + +static GENERATION_METADATA: FieldMetadata = FieldMetadata { + name: "Generation", + display_name: "Generation", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", +}; + impl Reflect for Handle { fn source_path() -> &'static str { file!() @@ -115,47 +143,35 @@ impl Reflect for Handle { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[ { - static METADATA: FieldMetadata = FieldMetadata { - name: "Index", - display_name: "Index", - description: "", - tag: "", - read_only: false, - immutable_collection: false, - min_value: None, - max_value: None, - step: None, - precision: None, - doc: "", - }; - FieldInfo { - metadata: &METADATA, + FieldInfoRef { + metadata: &INDEX_METADATA, value: &self.index, - reflect_value: &self.index, } }, { - static METADATA: FieldMetadata = FieldMetadata { - name: "Generation", - display_name: "Generation", - description: "", - tag: "", - read_only: false, - immutable_collection: false, - min_value: None, - max_value: None, - step: None, - precision: None, - doc: "", - }; - - FieldInfo { - metadata: &METADATA, + FieldInfoRef { + metadata: &GENERATION_METADATA, value: &self.generation, - reflect_value: &self.generation, + } + }, + ]) + } + + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut [ + { + FieldInfoMut { + metadata: &INDEX_METADATA, + value: &mut self.index, + } + }, + { + FieldInfoMut { + metadata: &GENERATION_METADATA, + value: &mut self.generation, } }, ]) diff --git a/fyrox-core/src/pool/mod.rs b/fyrox-core/src/pool/mod.rs index 8f2e1bea0..ec0fb8c60 100644 --- a/fyrox-core/src/pool/mod.rs +++ b/fyrox-core/src/pool/mod.rs @@ -126,10 +126,15 @@ where } #[inline] - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[]) } + #[inline] + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut []) + } + #[inline] fn into_any(self: Box) -> Box { self diff --git a/fyrox-core/src/reflect.rs b/fyrox-core/src/reflect.rs index 3f9064cd9..510c101b7 100644 --- a/fyrox-core/src/reflect.rs +++ b/fyrox-core/src/reflect.rs @@ -33,21 +33,39 @@ use std::{ pub mod prelude { pub use super::{ - FieldInfo, FieldMetadata, FieldValue, Reflect, ReflectArray, ReflectHashMap, - ReflectInheritableVariable, ReflectList, ResolvePath, SetFieldByPathError, + FieldInfoMut, FieldInfoRef, FieldMetadata, FieldValue, Reflect, ReflectArray, + ReflectHashMap, ReflectInheritableVariable, ReflectList, ResolvePath, SetFieldByPathError, }; } /// A value of a field.. pub trait FieldValue: Any + 'static { /// Casts `self` to a `&dyn Any` - fn as_any(&self) -> &dyn Any; + fn field_value_as_any_ref(&self) -> &dyn Any; + + /// Casts `self` to a `&mut dyn Any` + fn field_value_as_any_mut(&mut self) -> &mut dyn Any; + + fn field_value_as_reflect(&self) -> &dyn Reflect; + fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect; fn type_name(&self) -> &'static str; } -impl FieldValue for T { - fn as_any(&self) -> &dyn Any { +impl FieldValue for T { + fn field_value_as_any_ref(&self) -> &dyn Any { + self + } + + fn field_value_as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn field_value_as_reflect(&self) -> &dyn Reflect { + self + } + + fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect { self } @@ -110,7 +128,7 @@ pub struct FieldMetadata<'s> { pub precision: Option, } -pub struct FieldInfo<'a, 'b> { +pub struct FieldInfoRef<'a, 'b> { /// A reference to field's metadata. pub metadata: &'a FieldMetadata<'b>, @@ -118,12 +136,9 @@ pub struct FieldInfo<'a, 'b> { /// means that while `field/fields/field_mut/fields_mut` might return a reference to other value, /// than the actual field, the `value` is guaranteed to be a reference to the real value. pub value: &'a dyn FieldValue, - - /// A reference to the value casted to `Reflect`. - pub reflect_value: &'a dyn Reflect, } -impl<'b> Deref for FieldInfo<'_, 'b> { +impl<'b> Deref for FieldInfoRef<'_, 'b> { type Target = FieldMetadata<'b>; fn deref(&self) -> &Self::Target { @@ -131,10 +146,10 @@ impl<'b> Deref for FieldInfo<'_, 'b> { } } -impl FieldInfo<'_, '_> { +impl FieldInfoRef<'_, '_> { /// Tries to cast a value to a given type. pub fn cast_value(&self) -> Result<&T, CastError> { - match self.value.as_any().downcast_ref::() { + match self.value.field_value_as_any_ref().downcast_ref::() { Some(value) => Ok(value), None => Err(CastError::TypeMismatch { property_name: self.metadata.name.to_string(), @@ -145,7 +160,7 @@ impl FieldInfo<'_, '_> { } } -impl fmt::Debug for FieldInfo<'_, '_> { +impl fmt::Debug for FieldInfoRef<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FieldInfo") .field("metadata", &self.metadata) @@ -154,7 +169,43 @@ impl fmt::Debug for FieldInfo<'_, '_> { } } -impl PartialEq for FieldInfo<'_, '_> { +impl PartialEq for FieldInfoRef<'_, '_> { + fn eq(&self, other: &Self) -> bool { + let value_ptr_a = self.value as *const _ as *const (); + let value_ptr_b = other.value as *const _ as *const (); + + std::ptr::eq(value_ptr_a, value_ptr_b) + } +} + +pub struct FieldInfoMut<'a, 'b> { + /// A reference to field's metadata. + pub metadata: &'a FieldMetadata<'b>, + + /// An reference to the actual value of the property. This is "non-mangled" reference, which + /// means that while `field/fields/field_mut/fields_mut` might return a reference to other value, + /// than the actual field, the `value` is guaranteed to be a reference to the real value. + pub value: &'a mut dyn FieldValue, +} + +impl<'b> Deref for FieldInfoMut<'_, 'b> { + type Target = FieldMetadata<'b>; + + fn deref(&self) -> &Self::Target { + self.metadata + } +} + +impl fmt::Debug for FieldInfoMut<'_, '_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FieldInfo") + .field("metadata", &self.metadata) + .field("value", &format_args!("{:?}", self.value as *const _)) + .finish() + } +} + +impl PartialEq for FieldInfoMut<'_, '_> { fn eq(&self, other: &Self) -> bool { let value_ptr_a = self.value as *const _ as *const (); let value_ptr_b = other.value as *const _ as *const (); @@ -212,7 +263,9 @@ pub trait Reflect: ReflectBase { fn doc(&self) -> &'static str; - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])); + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])); + + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])); fn into_any(self: Box) -> Box; @@ -850,7 +903,7 @@ impl dyn Reflect { pub fn enumerate_fields_recursively(&self, func: &mut F, ignored_types: &[TypeId]) where - F: FnMut(&str, Option<&FieldInfo>, &dyn Reflect), + F: FnMut(&str, Option<&FieldInfoRef>, &dyn Reflect), { self.enumerate_fields_recursively_internal("", None, func, ignored_types) } @@ -858,11 +911,11 @@ impl dyn Reflect { fn enumerate_fields_recursively_internal( &self, path: &str, - field_info: Option<&FieldInfo>, + field_info: Option<&FieldInfoRef>, func: &mut F, ignored_types: &[TypeId], ) where - F: FnMut(&str, Option<&FieldInfo>, &dyn Reflect), + F: FnMut(&str, Option<&FieldInfoRef>, &dyn Reflect), { if ignored_types.contains(&self.type_id()) { return; @@ -961,12 +1014,15 @@ impl dyn Reflect { &compound_path }; - field.reflect_value.enumerate_fields_recursively_internal( - field_path, - Some(field), - func, - ignored_types, - ); + field + .value + .field_value_as_reflect() + .enumerate_fields_recursively_internal( + field_path, + Some(field), + func, + ignored_types, + ); } }) } @@ -1165,10 +1221,15 @@ macro_rules! blank_reflect { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[]) } + #[inline] + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut []) + } + fn into_any(self: Box) -> Box { self } @@ -1236,10 +1297,14 @@ macro_rules! delegate_reflect { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.deref().fields_info(func) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.deref_mut().fields_info_mut(func) + } + fn into_any(self: Box) -> Box { (*self).into_any() } @@ -1301,7 +1366,7 @@ macro_rules! newtype_reflect { self.0.doc() } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.0.fields_info(func) } diff --git a/fyrox-core/src/reflect/std_impls.rs b/fyrox-core/src/reflect/std_impls.rs index 8496b57bb..0f5170c78 100644 --- a/fyrox-core/src/reflect/std_impls.rs +++ b/fyrox-core/src/reflect/std_impls.rs @@ -330,11 +330,16 @@ macro_rules! impl_reflect_inner_mutability { env!("CARGO_PKG_NAME") } - fn fields_info(&$self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&$self, func: &mut dyn FnMut(&[FieldInfoRef])) { let guard = $acquire_lock_guard; guard.fields_info(func) } + fn fields_info_mut(&mut $self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + let mut guard = $acquire_lock_guard; + guard.fields_info_mut(func) + } + fn into_any($self: Box) -> Box { let inner = $into_inner; Box::new(inner) diff --git a/fyrox-core/src/variable.rs b/fyrox-core/src/variable.rs index 8a5a31d63..015b232d9 100644 --- a/fyrox-core/src/variable.rs +++ b/fyrox-core/src/variable.rs @@ -404,10 +404,15 @@ where } #[inline] - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.value.fields_info(func) } + #[inline] + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.value.fields_info_mut(func) + } + #[inline] fn into_any(self: Box) -> Box { Box::new(self.value).into_any() diff --git a/fyrox-graph/src/lib.rs b/fyrox-graph/src/lib.rs index e15e2e737..c8c47c1bd 100644 --- a/fyrox-graph/src/lib.rs +++ b/fyrox-graph/src/lib.rs @@ -1539,10 +1539,14 @@ mod test { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.0.deref().fields_info(func) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.0.deref_mut().fields_info_mut(func) + } + fn into_any(self: Box) -> Box { Reflect::into_any(self.0) } diff --git a/fyrox-impl/src/scene/node/mod.rs b/fyrox-impl/src/scene/node/mod.rs index f37e5be4a..5495106f0 100644 --- a/fyrox-impl/src/scene/node/mod.rs +++ b/fyrox-impl/src/scene/node/mod.rs @@ -557,10 +557,14 @@ impl Reflect for Node { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.0.deref().fields_info(func) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.0.deref_mut().fields_info_mut(func) + } + fn into_any(self: Box) -> Box { Reflect::into_any(self.0) } diff --git a/fyrox-impl/src/scene/ragdoll.rs b/fyrox-impl/src/scene/ragdoll.rs index 579c6fe03..6d3e7150a 100644 --- a/fyrox-impl/src/scene/ragdoll.rs +++ b/fyrox-impl/src/scene/ragdoll.rs @@ -95,7 +95,7 @@ impl Reflect for Limb { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { func(&[ { static METADATA: FieldMetadata = FieldMetadata { @@ -111,10 +111,9 @@ impl Reflect for Limb { precision: None, doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &self.bone, - reflect_value: &self.bone, } }, { @@ -131,10 +130,9 @@ impl Reflect for Limb { precision: None, doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &self.physical_bone, - reflect_value: &self.physical_bone, } }, { @@ -151,10 +149,71 @@ impl Reflect for Limb { precision: None, doc: "", }; - FieldInfo { + FieldInfoRef { metadata: &METADATA, value: &self.children, - reflect_value: &self.children, + } + }, + ]) + } + + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + func(&mut [ + { + static METADATA: FieldMetadata = FieldMetadata { + name: "Bone", + display_name: "Bone", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", + }; + FieldInfoMut { + metadata: &METADATA, + value: &mut self.bone, + } + }, + { + static METADATA: FieldMetadata = FieldMetadata { + name: "PhysicalBone", + display_name: "Physical Bone", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", + }; + FieldInfoMut { + metadata: &METADATA, + value: &mut self.physical_bone, + } + }, + { + static METADATA: FieldMetadata = FieldMetadata { + name: "Children", + display_name: "Children", + description: "", + tag: "", + read_only: false, + immutable_collection: false, + min_value: None, + max_value: None, + step: None, + precision: None, + doc: "", + }; + FieldInfoMut { + metadata: &METADATA, + value: &mut self.children, } }, ]) diff --git a/fyrox-impl/src/script/mod.rs b/fyrox-impl/src/script/mod.rs index 3d6227046..b27e9cd4b 100644 --- a/fyrox-impl/src/script/mod.rs +++ b/fyrox-impl/src/script/mod.rs @@ -27,7 +27,7 @@ use crate::{ core::{ log::Log, pool::Handle, - reflect::{FieldInfo, Reflect, ReflectArray, ReflectList}, + reflect::{FieldInfoRef, Reflect, ReflectArray, ReflectList}, type_traits::ComponentProvider, uuid::Uuid, visitor::{Visit, VisitResult, Visitor}, @@ -39,6 +39,7 @@ use crate::{ plugin::{Plugin, PluginContainer}, scene::{base::NodeScriptMessage, node::Node, Scene}, }; +use fyrox_core::reflect::FieldInfoMut; use std::{ any::{Any, TypeId}, fmt::{Debug, Formatter}, @@ -695,10 +696,14 @@ impl Reflect for Script { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.instance.fields_info(func) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.instance.fields_info_mut(func) + } + fn into_any(self: Box) -> Box { self.instance.into_any() } diff --git a/fyrox-resource/src/manager.rs b/fyrox-resource/src/manager.rs index eaaa38dbd..c0b06eb76 100644 --- a/fyrox-resource/src/manager.rs +++ b/fyrox-resource/src/manager.rs @@ -869,7 +869,7 @@ mod test { use fyrox_core::uuid::{uuid, Uuid}; use fyrox_core::{ - reflect::{FieldInfo, Reflect}, + reflect::prelude::*, visitor::{Visit, VisitResult, Visitor}, TypeUuidProvider, }; diff --git a/fyrox-resource/src/state.rs b/fyrox-resource/src/state.rs index 7482ee259..7c7c9d878 100644 --- a/fyrox-resource/src/state.rs +++ b/fyrox-resource/src/state.rs @@ -208,7 +208,7 @@ impl ResourceState { #[cfg(test)] mod test { use fyrox_core::{ - reflect::{FieldInfo, Reflect}, + reflect::{FieldInfoRef, Reflect}, TypeUuidProvider, }; use std::error::Error; diff --git a/fyrox-ui/src/inspector/editors/array.rs b/fyrox-ui/src/inspector/editors/array.rs index 5aaff3f6f..7d21e9675 100644 --- a/fyrox-ui/src/inspector/editors/array.rs +++ b/fyrox-ui/src/inspector/editors/array.rs @@ -120,7 +120,7 @@ fn create_items<'a, 'b, T, I>( iter: I, environment: Option>, definition_container: Arc, - property_info: &FieldInfo<'a, 'b>, + property_info: &FieldInfoRef<'a, 'b>, ctx: &mut BuildContext, sync_flag: u64, layer_index: usize, @@ -153,10 +153,9 @@ where doc: property_info.doc, }; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &metadata, value: item, - reflect_value: item, }; let editor = @@ -248,7 +247,7 @@ where pub fn build( self, ctx: &mut BuildContext, - property_info: &FieldInfo<'a, '_>, + property_info: &FieldInfoRef<'a, '_>, sync_flag: u64, name_column_width: f32, ) -> Result, InspectorError> { @@ -413,10 +412,9 @@ where doc: property_info.doc, }; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &metadata, value: obj, - reflect_value: obj, }; if let Some(message) = diff --git a/fyrox-ui/src/inspector/editors/collection.rs b/fyrox-ui/src/inspector/editors/collection.rs index 9605c1531..be2c4c60f 100644 --- a/fyrox-ui/src/inspector/editors/collection.rs +++ b/fyrox-ui/src/inspector/editors/collection.rs @@ -231,7 +231,7 @@ fn create_items<'a, 'b, T, I>( iter: I, environment: Option>, definition_container: Arc, - property_info: &FieldInfo<'a, 'b>, + property_info: &FieldInfoRef<'a, 'b>, ctx: &mut BuildContext, sync_flag: u64, layer_index: usize, @@ -251,7 +251,7 @@ where let name = format!("{}[{index}]", property_info.name); let display_name = format!("{}[{index}]", property_info.display_name); - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: &name, display_name: &display_name, @@ -266,7 +266,6 @@ where doc: property_info.doc, }, value: item, - reflect_value: item, }; let editor = @@ -384,7 +383,7 @@ where pub fn build( self, ctx: &mut BuildContext, - property_info: &FieldInfo<'a, '_>, + property_info: &FieldInfoRef<'a, '_>, sync_flag: u64, name_column_width: f32, ) -> Result, InspectorError> { @@ -581,7 +580,7 @@ where let name = format!("{}[{index}]", property_info.name); let display_name = format!("{}[{index}]", property_info.display_name); - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: &name, display_name: &display_name, @@ -596,7 +595,6 @@ where doc: property_info.doc, }, value: obj, - reflect_value: obj, }; if let Some(message) = diff --git a/fyrox-ui/src/inspector/editors/inherit.rs b/fyrox-ui/src/inspector/editors/inherit.rs index f5c9c60d4..c8d57d52e 100644 --- a/fyrox-ui/src/inspector/editors/inherit.rs +++ b/fyrox-ui/src/inspector/editors/inherit.rs @@ -233,7 +233,7 @@ where let value = property_info.cast_value::>()?; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -248,7 +248,6 @@ where doc: property_info.doc, }, value: &**value, - reflect_value: &**value, }; let instance = @@ -324,7 +323,7 @@ where let value = property_info.cast_value::>()?; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -339,7 +338,6 @@ where doc: property_info.doc, }, value: &**value, - reflect_value: &**value, }; return definition diff --git a/fyrox-ui/src/inspector/editors/inspectable.rs b/fyrox-ui/src/inspector/editors/inspectable.rs index a20c88962..305e51501 100644 --- a/fyrox-ui/src/inspector/editors/inspectable.rs +++ b/fyrox-ui/src/inspector/editors/inspectable.rs @@ -44,7 +44,7 @@ use std::{ /// A general-purpose property editor definition that creates /// a nested inspector within an [Expander](crate::expander::Expander) widget to allow the user /// to edited properties of type T. -/// The expander is labeled with [FieldInfo::display_name]. +/// The expander is labeled with [FieldInfoRef::display_name]. /// The layer_index for the inner inspector is increased by 1. pub struct InspectablePropertyEditorDefinition where diff --git a/fyrox-ui/src/inspector/editors/mod.rs b/fyrox-ui/src/inspector/editors/mod.rs index be009534f..bb6c390cf 100644 --- a/fyrox-ui/src/inspector/editors/mod.rs +++ b/fyrox-ui/src/inspector/editors/mod.rs @@ -152,7 +152,7 @@ pub struct PropertyEditorBuildContext<'a, 'b, 'c, 'd> { /// General context for widget building to be used for creating the editor. pub build_context: &'a mut BuildContext<'c>, /// The FieldInfo of the property to edit, extracted from the object we are inspecting by reflection. - pub property_info: &'b FieldInfo<'b, 'd>, + pub property_info: &'b FieldInfoRef<'b, 'd>, /// Untyped reference to the environment that the Inspector is being used in. /// This will often be /// [fyroxed_base::inspector::EditorEnvironment](https://docs.rs/fyroxed_base/latest/fyroxed_base/inspector/struct.EditorEnvironment.html) @@ -197,7 +197,7 @@ pub struct PropertyEditorMessageContext<'a, 'b, 'c> { /// [UiMessage::flags] set to `sync_flag`. pub ui: &'b mut UserInterface, /// The FieldInfo of the property to edit, extracted from the object we are inspecting by reflection. - pub property_info: &'a FieldInfo<'a, 'c>, + pub property_info: &'a FieldInfoRef<'a, 'c>, /// The list of the Inspectors property editors. /// This allows one property editor to make use of other property editors. pub definition_container: Arc, diff --git a/fyrox-ui/src/inspector/editors/refcell.rs b/fyrox-ui/src/inspector/editors/refcell.rs index 6ffa9331b..ff09627a4 100644 --- a/fyrox-ui/src/inspector/editors/refcell.rs +++ b/fyrox-ui/src/inspector/editors/refcell.rs @@ -85,7 +85,7 @@ where let value = property_info.cast_value::>()?.borrow(); - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -100,7 +100,6 @@ where doc: property_info.doc, }, value: &*value, - reflect_value: &*value, }; definition @@ -134,7 +133,7 @@ where let value = ctx.property_info.cast_value::>()?.borrow(); - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -149,7 +148,6 @@ where doc: property_info.doc, }, value: &*value, - reflect_value: &*value, }; return definition diff --git a/fyrox-ui/src/inspector/editors/style.rs b/fyrox-ui/src/inspector/editors/style.rs index 6b7de5b32..7899dd66a 100644 --- a/fyrox-ui/src/inspector/editors/style.rs +++ b/fyrox-ui/src/inspector/editors/style.rs @@ -225,7 +225,7 @@ where { let property_info = ctx.property_info; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -240,7 +240,6 @@ where doc: property_info.doc, }, value: &**value, - reflect_value: &**value, }; let instance = @@ -303,7 +302,7 @@ where let value = property_info.cast_value::>()?; - let proxy_property_info = FieldInfo { + let proxy_property_info = FieldInfoRef { metadata: &FieldMetadata { name: property_info.name, display_name: property_info.display_name, @@ -318,7 +317,6 @@ where doc: property_info.doc, }, value: &**value, - reflect_value: &**value, }; return definition diff --git a/fyrox-ui/src/inspector/mod.rs b/fyrox-ui/src/inspector/mod.rs index 0dc22ed78..2dbaaefb0 100644 --- a/fyrox-ui/src/inspector/mod.rs +++ b/fyrox-ui/src/inspector/mod.rs @@ -534,11 +534,11 @@ impl From for InspectorError { /// Stores the association between a field in an object and an editor widget in an [Inspector]. #[derive(Clone, Debug)] pub struct ContextEntry { - /// The name of the field being edited, as found in [FieldInfo::name]. + /// The name of the field being edited, as found in [FieldInfoRef::name]. pub property_name: String, - /// The name of the field being edited, as found in [FieldInfo::display_name]. + /// The name of the field being edited, as found in [FieldInfoRef::display_name]. pub property_display_name: String, - /// The name of the field being edited, as found in [FieldInfo::tag]. + /// The name of the field being edited, as found in [FieldInfoRef::tag]. pub property_tag: String, /// The type of the property being edited, as found in [PropertyEditorDefinition::value_type_id](editors::PropertyEditorDefinition::value_type_id). pub property_value_type_id: TypeId, @@ -856,7 +856,7 @@ impl InspectorContext { let mut editors = Vec::new(); object.fields_info(&mut |fields_info| { for (i, (field_text, info)) in fields_text.iter().zip(fields_info.iter()).enumerate() { - if !filter.pass(info.reflect_value) { + if !filter.pass(info.value.field_value_as_reflect()) { continue; } @@ -1022,7 +1022,7 @@ impl InspectorContext { object.fields_info(&mut |fields_info| { for info in fields_info { - if !filter.pass(info.reflect_value) { + if !filter.pass(info.value.field_value_as_reflect()) { continue; } diff --git a/fyrox-ui/src/node/mod.rs b/fyrox-ui/src/node/mod.rs index b3f855719..8e6156b20 100644 --- a/fyrox-ui/src/node/mod.rs +++ b/fyrox-ui/src/node/mod.rs @@ -307,10 +307,14 @@ impl Reflect for UiNode { env!("CARGO_PKG_NAME") } - fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfo])) { + fn fields_info(&self, func: &mut dyn FnMut(&[FieldInfoRef])) { self.0.deref().fields_info(func) } + fn fields_info_mut(&mut self, func: &mut dyn FnMut(&mut [FieldInfoMut])) { + self.0.deref_mut().fields_info_mut(func) + } + fn into_any(self: Box) -> Box { Reflect::into_any(self.0) }