Reflect::first_field_ref/mut_of_type

This commit is contained in:
Dmitry Stepanov
2026-05-08 15:18:08 +03:00
parent 1904f95519
commit 5cf90dff53
13 changed files with 92 additions and 43 deletions
+2 -2
View File
@@ -243,7 +243,7 @@ impl Reflect for DynTypeWrapper {
Some(Box::new(self.clone()))
}
fn get_field_direct_ref(&self, index: usize) -> Option<FieldRef> {
fn field_direct_ref(&self, index: usize) -> Option<FieldRef> {
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<FieldMut> {
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
if index == 0 {
Some(FieldMut {
metadata: &CONTENT_METADATA,
+2 -2
View File
@@ -213,7 +213,7 @@ impl<T: Reflect> Reflect for Handle<T> {
func(Some(self))
}
fn get_field_direct_ref(&self, index: usize) -> Option<FieldRef> {
fn field_direct_ref(&self, index: usize) -> Option<FieldRef> {
if index == 0 {
Some(FieldRef {
metadata: &INDEX_METADATA,
@@ -229,7 +229,7 @@ impl<T: Reflect> Reflect for Handle<T> {
}
}
fn get_field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
if index == 0 {
Some(FieldMut {
metadata: &INDEX_METADATA,
+2 -2
View File
@@ -226,11 +226,11 @@ where
env!("CARGO_PKG_NAME")
}
fn get_field_direct_ref(&self, _index: usize) -> Option<FieldRef> {
fn field_direct_ref(&self, _index: usize) -> Option<FieldRef> {
None
}
fn get_field_direct_mut(&mut self, _index: usize) -> Option<FieldMut> {
fn field_direct_mut(&mut self, _index: usize) -> Option<FieldMut> {
None
}
+2 -2
View File
@@ -210,13 +210,13 @@ macro_rules! impl_reflect_inner_mutability {
guard.set(value)
}
fn get_field_direct_ref(&self, index: usize) -> Option<FieldRef> {
fn field_direct_ref(&self, index: usize) -> Option<FieldRef> {
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<FieldMut> {
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
warn!("Cannot get a direct field ref {index}, because it is \
not supported for types with interior mutability.");
None
+6 -6
View File
@@ -200,12 +200,12 @@ macro_rules! delegate_reflect {
self.deref_mut().as_reflect_mut(func)
}
fn get_field_direct_ref(&self, index: usize) -> Option<FieldRef> {
self.deref().get_field_direct_ref(index)
fn field_direct_ref(&self, index: usize) -> Option<FieldRef> {
self.deref().field_direct_ref(index)
}
fn get_field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
self.deref_mut().get_field_direct_mut(index)
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
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
}
+52 -3
View File
@@ -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<FieldRef>;
fn field_direct_ref(&self, index: usize) -> Option<FieldRef>;
/// 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<FieldMut>;
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut>;
/// 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::<T>()))
}
/// 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<T: Reflect>(&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::<T>() {
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<T: Reflect>(&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::<T>() {
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::<f32>()
.unwrap(),
&baz
);
}
#[derive(Reflect, Clone, Debug)]
+4 -4
View File
@@ -543,12 +543,12 @@ where
func(Some(self))
}
fn get_field_direct_ref(&self, index: usize) -> Option<FieldRef> {
self.value.get_field_direct_ref(index)
fn field_direct_ref(&self, index: usize) -> Option<FieldRef> {
self.value.field_direct_ref(index)
}
fn get_field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
self.value.get_field_direct_mut(index)
fn field_direct_mut(&mut self, index: usize) -> Option<FieldMut> {
self.value.field_direct_mut(index)
}
}