diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index b6a95f8665..4800160786 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -100,6 +100,8 @@ impl_reflect_value!( ::core::result::Result < T: Clone + Reflect + TypePath, E: Clone + Reflect + TypePath > () ); +impl_reflect_value!(::std::collections::BTreeSet()); +impl_reflect_value!(::std::collections::HashSet()); impl_reflect_value!(::bevy_utils::HashSet()); impl_reflect_value!(::core::ops::Range()); impl_reflect_value!(::core::ops::RangeInclusive()); @@ -620,6 +622,220 @@ impl_type_path!(::bevy_utils::hashbrown::hash_map::DefaultHashBuilder); impl_type_path!(::bevy_utils::NoOpHash); impl_type_path!(::bevy_utils::hashbrown::HashMap); +macro_rules! impl_reflect_for_btree_map { + ($ty:path) => { + impl Map for $ty + where + K: FromReflect + TypePath + Eq + Ord, + V: FromReflect + TypePath, + { + fn get(&self, key: &dyn Reflect) -> Option<&dyn Reflect> { + key.downcast_ref::() + .and_then(|key| Self::get(self, key)) + .map(|value| value as &dyn Reflect) + } + + fn get_mut(&mut self, key: &dyn Reflect) -> Option<&mut dyn Reflect> { + key.downcast_ref::() + .and_then(move |key| Self::get_mut(self, key)) + .map(|value| value as &mut dyn Reflect) + } + + fn get_at(&self, index: usize) -> Option<(&dyn Reflect, &dyn Reflect)> { + self.iter() + .nth(index) + .map(|(key, value)| (key as &dyn Reflect, value as &dyn Reflect)) + } + + fn get_at_mut(&mut self, index: usize) -> Option<(&dyn Reflect, &mut dyn Reflect)> { + self.iter_mut() + .nth(index) + .map(|(key, value)| (key as &dyn Reflect, value as &mut dyn Reflect)) + } + + fn len(&self) -> usize { + Self::len(self) + } + + fn iter(&self) -> MapIter { + MapIter::new(self) + } + + fn drain(self: Box) -> Vec<(Box, Box)> { + self.into_iter() + .map(|(key, value)| { + ( + Box::new(key) as Box, + Box::new(value) as Box, + ) + }) + .collect() + } + + fn clone_dynamic(&self) -> DynamicMap { + let mut dynamic_map = DynamicMap::default(); + dynamic_map.set_represented_type(self.get_represented_type_info()); + for (k, v) in self { + let key = K::from_reflect(k).unwrap_or_else(|| { + panic!( + "Attempted to clone invalid key of type {}.", + k.reflect_type_path() + ) + }); + dynamic_map.insert_boxed(Box::new(key), v.clone_value()); + } + dynamic_map + } + + fn insert_boxed( + &mut self, + key: Box, + value: Box, + ) -> Option> { + let key = K::take_from_reflect(key).unwrap_or_else(|key| { + panic!( + "Attempted to insert invalid key of type {}.", + key.reflect_type_path() + ) + }); + let value = V::take_from_reflect(value).unwrap_or_else(|value| { + panic!( + "Attempted to insert invalid value of type {}.", + value.reflect_type_path() + ) + }); + self.insert(key, value) + .map(|old_value| Box::new(old_value) as Box) + } + + fn remove(&mut self, key: &dyn Reflect) -> Option> { + let mut from_reflect = None; + key.downcast_ref::() + .or_else(|| { + from_reflect = K::from_reflect(key); + from_reflect.as_ref() + }) + .and_then(|key| self.remove(key)) + .map(|value| Box::new(value) as Box) + } + } + + impl Reflect for $ty + where + K: FromReflect + TypePath + Eq + Ord, + V: FromReflect + TypePath, + { + fn get_represented_type_info(&self) -> Option<&'static TypeInfo> { + Some(::type_info()) + } + + fn into_any(self: Box) -> Box { + self + } + + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + #[inline] + fn into_reflect(self: Box) -> Box { + self + } + + fn as_reflect(&self) -> &dyn Reflect { + self + } + + fn as_reflect_mut(&mut self) -> &mut dyn Reflect { + self + } + + fn apply(&mut self, value: &dyn Reflect) { + map_apply(self, value); + } + + fn set(&mut self, value: Box) -> Result<(), Box> { + *self = value.take()?; + Ok(()) + } + + fn reflect_kind(&self) -> ReflectKind { + ReflectKind::Map + } + + fn reflect_ref(&self) -> ReflectRef { + ReflectRef::Map(self) + } + + fn reflect_mut(&mut self) -> ReflectMut { + ReflectMut::Map(self) + } + + fn reflect_owned(self: Box) -> ReflectOwned { + ReflectOwned::Map(self) + } + + fn clone_value(&self) -> Box { + Box::new(self.clone_dynamic()) + } + + fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option { + map_partial_eq(self, value) + } + } + + impl Typed for $ty + where + K: FromReflect + TypePath + Eq + Ord, + V: FromReflect + TypePath, + { + fn type_info() -> &'static TypeInfo { + static CELL: GenericTypeInfoCell = GenericTypeInfoCell::new(); + CELL.get_or_insert::(|| TypeInfo::Map(MapInfo::new::())) + } + } + + impl GetTypeRegistration for $ty + where + K: FromReflect + TypePath + Eq + Ord, + V: FromReflect + TypePath, + { + fn get_type_registration() -> TypeRegistration { + let mut registration = TypeRegistration::of::(); + registration.insert::(FromType::::from_type()); + registration + } + } + + impl FromReflect for $ty + where + K: FromReflect + TypePath + Eq + Ord, + V: FromReflect + TypePath, + { + fn from_reflect(reflect: &dyn Reflect) -> Option { + if let ReflectRef::Map(ref_map) = reflect.reflect_ref() { + let mut new_map = Self::new(); + for (key, value) in ref_map.iter() { + let new_key = K::from_reflect(key)?; + let new_value = V::from_reflect(value)?; + new_map.insert(new_key, new_value); + } + Some(new_map) + } else { + None + } + } + } + }; +} + +impl_reflect_for_btree_map!(::std::collections::BTreeMap); +impl_type_path!(::std::collections::BTreeMap); + impl Array for [T; N] { #[inline] fn get(&self, index: usize) -> Option<&dyn Reflect> { @@ -1658,6 +1874,7 @@ mod tests { use bevy_utils::HashMap; use bevy_utils::{Duration, Instant}; use static_assertions::assert_impl_all; + use std::collections::BTreeMap; use std::f32::consts::{PI, TAU}; use std::path::Path; @@ -1732,6 +1949,21 @@ mod tests { assert!(!a.reflect_partial_eq(c).unwrap_or_default()); } + #[test] + fn should_partial_eq_btree_map() { + let mut a = BTreeMap::new(); + a.insert(0usize, 1.23_f64); + let b = a.clone(); + let mut c = BTreeMap::new(); + c.insert(0usize, 3.21_f64); + + let a: &dyn Reflect = &a; + let b: &dyn Reflect = &b; + let c: &dyn Reflect = &c; + assert!(a.reflect_partial_eq(b).unwrap_or_default()); + assert!(!a.reflect_partial_eq(c).unwrap_or_default()); + } + #[test] fn should_partial_eq_option() { let a: &dyn Reflect = &Some(123); diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index 5bfb687837..a965440746 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -1,6 +1,5 @@ use std::any::{Any, TypeId}; use std::fmt::{Debug, Formatter}; -use std::hash::Hash; use bevy_reflect_derive::impl_type_path; use bevy_utils::{Entry, HashMap}; @@ -107,11 +106,8 @@ pub struct MapInfo { impl MapInfo { /// Create a new [`MapInfo`]. - pub fn new< - TMap: Map + TypePath, - TKey: Hash + Reflect + TypePath, - TValue: Reflect + TypePath, - >() -> Self { + pub fn new() -> Self + { Self { type_path: TypePathTable::of::(), type_id: TypeId::of::(),