mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
ability to replace hash map key via reflection + refactoring
This commit is contained in:
@@ -677,16 +677,25 @@ fn test_hash_map() {
|
||||
{
|
||||
let hash_map = hash_map.as_hash_map().unwrap();
|
||||
assert_eq!(hash_map.reflect_len(), 2);
|
||||
hash_map.reflect_get(&foo_key, &mut |result| {
|
||||
assert_eq!(result.unwrap().downcast_ref::<Struct>().unwrap().field, 123)
|
||||
});
|
||||
assert_eq!(
|
||||
hash_map
|
||||
.reflect_get(&foo_key)
|
||||
.unwrap()
|
||||
.downcast_ref::<Struct>()
|
||||
.unwrap()
|
||||
.field,
|
||||
123
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let hash_map = hash_map.as_hash_map_mut().unwrap();
|
||||
hash_map.reflect_get_mut(&bar_key, &mut |result| {
|
||||
result.unwrap().downcast_mut::<Struct>().unwrap().field = 555
|
||||
});
|
||||
hash_map
|
||||
.reflect_get_mut(&bar_key)
|
||||
.unwrap()
|
||||
.downcast_mut::<Struct>()
|
||||
.unwrap()
|
||||
.field = 555;
|
||||
}
|
||||
|
||||
// Check path resolution.
|
||||
@@ -696,6 +705,7 @@ fn test_hash_map() {
|
||||
hash_map: HashMap<String, Struct>,
|
||||
}
|
||||
|
||||
let mut hash_map2 = hash_map.clone();
|
||||
let something = Something { hash_map };
|
||||
|
||||
something.get_resolve_path::<usize>("hash_map[foo].field", &mut |result| {
|
||||
@@ -704,4 +714,24 @@ fn test_hash_map() {
|
||||
something.get_resolve_path::<usize>("hash_map[bar].field", &mut |result| {
|
||||
assert_eq!(*result.unwrap(), 555)
|
||||
});
|
||||
|
||||
// Check key replacement.
|
||||
let baz_key = "baz".to_string();
|
||||
hash_map2
|
||||
.reflect_replace_key(&bar_key, Box::new(baz_key.clone()))
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
assert_eq!(hash_map2.reflect_len(), 2);
|
||||
assert!(hash_map2.reflect_get(&bar_key).is_none());
|
||||
assert_eq!(
|
||||
hash_map2
|
||||
.reflect_get(&baz_key)
|
||||
.unwrap()
|
||||
.downcast_ref::<Struct>()
|
||||
.unwrap()
|
||||
.field,
|
||||
555
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,17 +30,18 @@ pub trait ReflectHashMap: Reflect {
|
||||
value: Box<dyn Reflect>,
|
||||
) -> Option<Box<dyn Reflect>>;
|
||||
fn reflect_len(&self) -> usize;
|
||||
fn reflect_get(&self, key: &dyn Reflect, func: &mut dyn FnMut(Option<&dyn Reflect>));
|
||||
fn reflect_get_mut(
|
||||
&mut self,
|
||||
key: &dyn Reflect,
|
||||
func: &mut dyn FnMut(Option<&mut dyn Reflect>),
|
||||
);
|
||||
fn reflect_get(&self, key: &dyn Reflect) -> Option<&dyn Reflect>;
|
||||
fn reflect_get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect>;
|
||||
fn reflect_get_nth_value_ref(&self, index: usize) -> Option<&dyn Reflect>;
|
||||
fn reflect_get_nth_value_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
|
||||
fn reflect_get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)>;
|
||||
fn reflect_get_at_mut(&mut self, index: usize) -> Option<(&dyn Reflect, &mut dyn Reflect)>;
|
||||
fn reflect_remove(&mut self, key: &dyn Reflect, func: &mut dyn FnMut(Option<Box<dyn Reflect>>));
|
||||
fn reflect_remove(&mut self, key: &dyn Reflect) -> Option<Box<dyn Reflect>>;
|
||||
fn reflect_replace_key(
|
||||
&mut self,
|
||||
old_key: &dyn Reflect,
|
||||
new_key: Box<dyn Reflect>,
|
||||
) -> Result<(), Box<dyn Reflect>>;
|
||||
}
|
||||
|
||||
impl<K, V, S> Reflect for HashMap<K, V, S>
|
||||
@@ -87,27 +88,23 @@ where
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn reflect_get(&self, key: &dyn Reflect, func: &mut dyn FnMut(Option<&dyn Reflect>)) {
|
||||
fn reflect_get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> {
|
||||
match key.downcast_ref::<K>() {
|
||||
Some(key) => match self.get(key) {
|
||||
Some(value) => func(Some(value)),
|
||||
None => func(None),
|
||||
Some(value) => Some(value),
|
||||
None => None,
|
||||
},
|
||||
None => func(None),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn reflect_get_mut(
|
||||
&mut self,
|
||||
key: &dyn Reflect,
|
||||
func: &mut dyn FnMut(Option<&mut dyn Reflect>),
|
||||
) {
|
||||
fn reflect_get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect> {
|
||||
match key.downcast_ref::<K>() {
|
||||
Some(key) => match self.get_mut(key) {
|
||||
Some(value) => func(Some(value)),
|
||||
None => func(None),
|
||||
Some(value) => Some(value),
|
||||
None => None,
|
||||
},
|
||||
None => func(None),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,17 +128,28 @@ where
|
||||
.map(|(k, v)| (k as &dyn Reflect, v as &mut dyn Reflect))
|
||||
}
|
||||
|
||||
fn reflect_remove(
|
||||
&mut self,
|
||||
key: &dyn Reflect,
|
||||
func: &mut dyn FnMut(Option<Box<dyn Reflect>>),
|
||||
) {
|
||||
fn reflect_remove(&mut self, key: &dyn Reflect) -> Option<Box<dyn Reflect>> {
|
||||
match key.downcast_ref::<K>() {
|
||||
Some(key) => func(
|
||||
self.remove(key)
|
||||
.map(|value| Box::new(value) as Box<dyn Reflect>),
|
||||
),
|
||||
None => func(None),
|
||||
Some(key) => self
|
||||
.remove(key)
|
||||
.map(|value| Box::new(value) as Box<dyn Reflect>),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn reflect_replace_key(
|
||||
&mut self,
|
||||
old_key: &dyn Reflect,
|
||||
new_key: Box<dyn Reflect>,
|
||||
) -> Result<(), Box<dyn Reflect>> {
|
||||
if self.reflect_get(&*new_key).is_some() {
|
||||
return Err(new_key);
|
||||
}
|
||||
if let Some(value) = self.reflect_remove(old_key) {
|
||||
self.reflect_insert(new_key, value);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(new_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,39 +828,33 @@ unsafe fn make_fake_string_from_slice(string: &str) -> ManuallyDrop<String> {
|
||||
)))
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_ref(
|
||||
hash_map: &dyn ReflectHashMap,
|
||||
fn try_fetch_by_str_path_ref<'a>(
|
||||
hash_map: &'a dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&dyn Reflect>),
|
||||
) {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
) -> Option<&'a dyn Reflect> {
|
||||
// Create fake string here first, this is needed to avoid memory allocations.
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
hash_map.reflect_get(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => hash_map.reflect_get(&ImmutableString::new(path) as &dyn Reflect, func),
|
||||
});
|
||||
match hash_map.reflect_get(&*fake_string_key) {
|
||||
Some(value) => Some(value),
|
||||
None => hash_map.reflect_get(&ImmutableString::new(path) as &dyn Reflect),
|
||||
}
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_mut(
|
||||
hash_map: &mut dyn ReflectHashMap,
|
||||
fn try_fetch_by_str_path_mut<'a>(
|
||||
hash_map: &'a mut dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&mut dyn Reflect>),
|
||||
) {
|
||||
) -> Option<&'a mut dyn Reflect> {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
let mut succeeded = true;
|
||||
let hash_map2 = unsafe { &mut *(hash_map as *mut dyn ReflectHashMap) };
|
||||
|
||||
hash_map.reflect_get_mut(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => succeeded = false,
|
||||
});
|
||||
|
||||
if !succeeded {
|
||||
hash_map.reflect_get_mut(&ImmutableString::new(path) as &dyn Reflect, func)
|
||||
match hash_map.reflect_get_mut(&*fake_string_key) {
|
||||
Some(value) => Some(value),
|
||||
None => hash_map2.reflect_get_mut(&ImmutableString::new(path) as &dyn Reflect),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,9 +918,10 @@ impl<'p> Component<'p> {
|
||||
Err(_) => func(Err(ReflectPathError::InvalidIndexSyntax { s: path })),
|
||||
},
|
||||
None => match reflect.as_hash_map() {
|
||||
Some(hash_map) => try_fetch_by_str_path_ref(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
}),
|
||||
Some(hash_map) => func(
|
||||
try_fetch_by_str_path_ref(hash_map, path)
|
||||
.ok_or(ReflectPathError::NoItemForIndex { s: path }),
|
||||
),
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
},
|
||||
},
|
||||
@@ -957,11 +952,10 @@ impl<'p> Component<'p> {
|
||||
|
||||
if !succeeded {
|
||||
match reflect.as_hash_map_mut() {
|
||||
Some(hash_map) => {
|
||||
try_fetch_by_str_path_mut(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
})
|
||||
}
|
||||
Some(hash_map) => func(
|
||||
try_fetch_by_str_path_mut(hash_map, path)
|
||||
.ok_or(ReflectPathError::NoItemForIndex { s: path }),
|
||||
),
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user