diff --git a/fyrox-core-derive/src/reflect.rs b/fyrox-core-derive/src/reflect.rs index e9a617f6f..9b2018899 100644 --- a/fyrox-core-derive/src/reflect.rs +++ b/fyrox-core-derive/src/reflect.rs @@ -482,11 +482,11 @@ fn gen_impl( Ok(Box::new(this)) } - fn get_field_direct_ref(&self, reflect_argument_index: usize) -> Option { + fn field_direct_ref(&self, reflect_argument_index: usize) -> Option { #getter_ref } - fn get_field_direct_mut(&mut self, reflect_argument_index: usize) -> Option { + fn field_direct_mut(&mut self, reflect_argument_index: usize) -> Option { #getter_mut } diff --git a/fyrox-core/src/dyntype.rs b/fyrox-core/src/dyntype.rs index 0e6c31eb2..48feffa33 100644 --- a/fyrox-core/src/dyntype.rs +++ b/fyrox-core/src/dyntype.rs @@ -243,7 +243,7 @@ impl Reflect for DynTypeWrapper { Some(Box::new(self.clone())) } - fn get_field_direct_ref(&self, index: usize) -> Option { + fn field_direct_ref(&self, index: usize) -> Option { if index == 0 { Some(FieldRef { metadata: &CONTENT_METADATA, @@ -254,7 +254,7 @@ impl Reflect for DynTypeWrapper { } } - fn get_field_direct_mut(&mut self, index: usize) -> Option { + fn field_direct_mut(&mut self, index: usize) -> Option { if index == 0 { Some(FieldMut { metadata: &CONTENT_METADATA, diff --git a/fyrox-core/src/pool/handle.rs b/fyrox-core/src/pool/handle.rs index d33e9d14c..a91644a3b 100644 --- a/fyrox-core/src/pool/handle.rs +++ b/fyrox-core/src/pool/handle.rs @@ -213,7 +213,7 @@ impl Reflect for Handle { func(Some(self)) } - fn get_field_direct_ref(&self, index: usize) -> Option { + fn field_direct_ref(&self, index: usize) -> Option { if index == 0 { Some(FieldRef { metadata: &INDEX_METADATA, @@ -229,7 +229,7 @@ impl Reflect for Handle { } } - fn get_field_direct_mut(&mut self, index: usize) -> Option { + fn field_direct_mut(&mut self, index: usize) -> Option { if index == 0 { Some(FieldMut { metadata: &INDEX_METADATA, diff --git a/fyrox-core/src/pool/mod.rs b/fyrox-core/src/pool/mod.rs index 39fd8c40b..0b9d2fc98 100644 --- a/fyrox-core/src/pool/mod.rs +++ b/fyrox-core/src/pool/mod.rs @@ -226,11 +226,11 @@ where env!("CARGO_PKG_NAME") } - fn get_field_direct_ref(&self, _index: usize) -> Option { + fn field_direct_ref(&self, _index: usize) -> Option { None } - fn get_field_direct_mut(&mut self, _index: usize) -> Option { + fn field_direct_mut(&mut self, _index: usize) -> Option { None } diff --git a/fyrox-core/src/reflect/impls.rs b/fyrox-core/src/reflect/impls.rs index dc2fb2059..c1d285952 100644 --- a/fyrox-core/src/reflect/impls.rs +++ b/fyrox-core/src/reflect/impls.rs @@ -210,13 +210,13 @@ macro_rules! impl_reflect_inner_mutability { guard.set(value) } - fn get_field_direct_ref(&self, index: usize) -> Option { + fn field_direct_ref(&self, index: usize) -> Option { warn!("Cannot get a direct field ref {index}, because it is \ not supported for types with interior mutability."); None } - fn get_field_direct_mut(&mut self, index: usize) -> Option { + fn field_direct_mut(&mut self, index: usize) -> Option { warn!("Cannot get a direct field ref {index}, because it is \ not supported for types with interior mutability."); None diff --git a/fyrox-core/src/reflect/macros.rs b/fyrox-core/src/reflect/macros.rs index 63b9f7a4c..93830efc5 100644 --- a/fyrox-core/src/reflect/macros.rs +++ b/fyrox-core/src/reflect/macros.rs @@ -200,12 +200,12 @@ macro_rules! delegate_reflect { self.deref_mut().as_reflect_mut(func) } - fn get_field_direct_ref(&self, index: usize) -> Option { - self.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option { + self.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option { - self.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option { + self.deref_mut().field_direct_mut(index) } fn set( @@ -374,11 +374,11 @@ macro_rules! blank_reflect { func(if name == "self" { Some(self) } else { None }) } - fn get_field_direct_ref(&self, _index: usize) -> Option<$crate::reflect::FieldRef> { + fn field_direct_ref(&self, _index: usize) -> Option<$crate::reflect::FieldRef> { None } - fn get_field_direct_mut(&mut self, _index: usize) -> Option<$crate::reflect::FieldMut> { + fn field_direct_mut(&mut self, _index: usize) -> Option<$crate::reflect::FieldMut> { None } diff --git a/fyrox-core/src/reflect/mod.rs b/fyrox-core/src/reflect/mod.rs index ccc965f22..03bbf7033 100644 --- a/fyrox-core/src/reflect/mod.rs +++ b/fyrox-core/src/reflect/mod.rs @@ -165,7 +165,7 @@ pub trait Reflect: Any + Debug { /// but returning a lock guard would require boxing which in most cases would ruin performance. /// If you need to get a field reference for types with interior mutability, then use /// [`Reflect::fields_ref`] instead. - fn get_field_direct_ref(&self, index: usize) -> Option; + fn field_direct_ref(&self, index: usize) -> Option; /// Tries to get a mutable reference to a field at the specified index. Returns [`None`] in two cases: /// 1) The type does not have such field @@ -175,7 +175,7 @@ pub trait Reflect: Any + Debug { /// but returning a lock guard would require boxing which in most cases would ruin performance. /// If you need to get a field reference for types with interior mutability, then use /// [`Reflect::fields_ref`] instead. - fn get_field_direct_mut(&mut self, index: usize) -> Option; + fn field_direct_mut(&mut self, index: usize) -> Option; /// Returns the total number of fields. fn fields_count(&self) -> usize { @@ -307,6 +307,46 @@ impl dyn Reflect { self.as_any_mut(&mut |any| func(any.downcast_mut::())) } + /// Tries to find the first field of the given type. This method internally uses + /// [`Reflect::field_direct_ref`] with all of its limitations. + #[inline] + pub fn first_field_ref_of_type(&self) -> Option<&T> { + let count = self.fields_count(); + + for i in 0..count { + if let Some(field) = self.field_direct_ref(i) { + if let Some(typed_field) = (field.value as &dyn Any).downcast_ref::() { + return Some(typed_field); + } + } + } + + None + } + + /// Tries to find the first field of the given type. This method internally uses + /// [`Reflect::field_direct_ref`] with all of its limitations. + #[inline] + pub fn first_field_mut_of_type(&mut self) -> Option<&mut T> { + let count = self.fields_count(); + + for i in 0..count { + // SAFETY: Current implementation of borrow checker is just dumb. When a reborrow of self + // happens in every iteration of the loop, it assigns a new lifetime to the new reference. + // This way the returned reference has a different lifetime than in the method definition. + // The following unsafe block reborrows self with the correct lifetime, while the initial + // reference is not used so this is absolutely safe. + let this = unsafe { &mut *(self as *mut Self) }; + if let Some(field) = this.field_direct_mut(i) { + if let Some(typed_field) = (field.value as &mut dyn Any).downcast_mut::() { + return Some(typed_field); + } + } + } + + None + } + /// Sets a field by its path in the given entity. This method always uses [`Reflect::set_field`] which means, /// that it will always call custom property setters. #[inline] @@ -983,10 +1023,12 @@ mod test { #[test] fn enumerate_fields_recursively() { + let baz = 123.321; + let foo = Foo { enum_field: Enum::Stuff { field: 123 }.into(), bar: Default::default(), - baz: 0.0, + baz, collection: vec![Item::default()], hash_map: [("Foobar".to_string(), Item::default())].into(), }; @@ -1020,6 +1062,13 @@ mod test { assert_eq!(names[11], "hash_map[Foobar].payload"); assert_eq!(foo.fields_count(), 5); + + assert_eq!( + (&foo as &dyn Reflect) + .first_field_ref_of_type::() + .unwrap(), + &baz + ); } #[derive(Reflect, Clone, Debug)] diff --git a/fyrox-core/src/variable.rs b/fyrox-core/src/variable.rs index 5f57425b6..325467c5f 100644 --- a/fyrox-core/src/variable.rs +++ b/fyrox-core/src/variable.rs @@ -543,12 +543,12 @@ where func(Some(self)) } - fn get_field_direct_ref(&self, index: usize) -> Option { - self.value.get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option { + self.value.field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option { - self.value.get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option { + self.value.field_direct_mut(index) } } diff --git a/fyrox-graph/src/lib.rs b/fyrox-graph/src/lib.rs index 99037c56d..f331a523b 100644 --- a/fyrox-graph/src/lib.rs +++ b/fyrox-graph/src/lib.rs @@ -1815,12 +1815,12 @@ mod test { Some(Box::new(self.clone())) } - fn get_field_direct_ref(&self, index: usize) -> Option> { - self.0.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option> { + self.0.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option> { - self.0.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option> { + self.0.deref_mut().field_direct_mut(index) } } diff --git a/fyrox-impl/src/scene/node/mod.rs b/fyrox-impl/src/scene/node/mod.rs index 115e4eb48..9f0a93631 100644 --- a/fyrox-impl/src/scene/node/mod.rs +++ b/fyrox-impl/src/scene/node/mod.rs @@ -662,12 +662,12 @@ impl Reflect for Node { Some(Box::new(self.clone())) } - fn get_field_direct_ref(&self, index: usize) -> Option { - self.0.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option { + self.0.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option { - self.0.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option { + self.0.deref_mut().field_direct_mut(index) } } diff --git a/fyrox-impl/src/script/mod.rs b/fyrox-impl/src/script/mod.rs index e66a2d854..e1bb91a20 100644 --- a/fyrox-impl/src/script/mod.rs +++ b/fyrox-impl/src/script/mod.rs @@ -812,12 +812,12 @@ impl Reflect for Script { Some(Box::new(self.clone())) } - fn get_field_direct_ref(&self, index: usize) -> Option { - self.instance.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option { + self.instance.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option { - self.instance.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option { + self.instance.deref_mut().field_direct_mut(index) } } diff --git a/fyrox-resource/src/state.rs b/fyrox-resource/src/state.rs index 6957f549c..5f1567926 100644 --- a/fyrox-resource/src/state.rs +++ b/fyrox-resource/src/state.rs @@ -161,12 +161,12 @@ impl Reflect for ResourceDataWrapper { env!("CARGO_PKG_NAME") } - fn get_field_direct_ref(&self, index: usize) -> Option> { - self.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option> { + self.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option> { - self.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option> { + self.deref_mut().field_direct_mut(index) } fn set_field( diff --git a/fyrox-ui/src/node/mod.rs b/fyrox-ui/src/node/mod.rs index dbe52f320..cfdb1c75d 100644 --- a/fyrox-ui/src/node/mod.rs +++ b/fyrox-ui/src/node/mod.rs @@ -345,12 +345,12 @@ impl Reflect for UiNode { env!("CARGO_PKG_NAME") } - fn get_field_direct_ref(&self, index: usize) -> Option { - self.0.deref().get_field_direct_ref(index) + fn field_direct_ref(&self, index: usize) -> Option { + self.0.deref().field_direct_ref(index) } - fn get_field_direct_mut(&mut self, index: usize) -> Option { - self.0.deref_mut().get_field_direct_mut(index) + fn field_direct_mut(&mut self, index: usize) -> Option { + self.0.deref_mut().field_direct_mut(index) } fn set_field(