diff --git a/fyrox-core-derive/tests/it/reflect.rs b/fyrox-core-derive/tests/it/reflect.rs index be396f9ff..a3bcc87d5 100644 --- a/fyrox-core-derive/tests/it/reflect.rs +++ b/fyrox-core-derive/tests/it/reflect.rs @@ -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::().unwrap().field, 123) - }); + assert_eq!( + hash_map + .reflect_get(&foo_key) + .unwrap() + .downcast_ref::() + .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::().unwrap().field = 555 - }); + hash_map + .reflect_get_mut(&bar_key) + .unwrap() + .downcast_mut::() + .unwrap() + .field = 555; } // Check path resolution. @@ -696,6 +705,7 @@ fn test_hash_map() { hash_map: HashMap, } + let mut hash_map2 = hash_map.clone(); let something = Something { hash_map }; something.get_resolve_path::("hash_map[foo].field", &mut |result| { @@ -704,4 +714,24 @@ fn test_hash_map() { something.get_resolve_path::("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::() + .unwrap() + .field, + 555 + ); + } } diff --git a/fyrox-core/src/reflect/map.rs b/fyrox-core/src/reflect/map.rs index 25e7f661f..7314d5fb7 100644 --- a/fyrox-core/src/reflect/map.rs +++ b/fyrox-core/src/reflect/map.rs @@ -30,17 +30,18 @@ pub trait ReflectHashMap: Reflect { value: Box, ) -> Option>; 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>)); + fn reflect_remove(&mut self, key: &dyn Reflect) -> Option>; + fn reflect_replace_key( + &mut self, + old_key: &dyn Reflect, + new_key: Box, + ) -> Result<(), Box>; } impl Reflect for HashMap @@ -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::() { 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::() { 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>), - ) { + fn reflect_remove(&mut self, key: &dyn Reflect) -> Option> { match key.downcast_ref::() { - Some(key) => func( - self.remove(key) - .map(|value| Box::new(value) as Box), - ), - None => func(None), + Some(key) => self + .remove(key) + .map(|value| Box::new(value) as Box), + None => None, + } + } + + fn reflect_replace_key( + &mut self, + old_key: &dyn Reflect, + new_key: Box, + ) -> Result<(), Box> { + 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) } } } diff --git a/fyrox-core/src/reflect/mod.rs b/fyrox-core/src/reflect/mod.rs index c15385ed0..d28725649 100644 --- a/fyrox-core/src/reflect/mod.rs +++ b/fyrox-core/src/reflect/mod.rs @@ -828,39 +828,33 @@ unsafe fn make_fake_string_from_slice(string: &str) -> ManuallyDrop { ))) } -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)), } }