1use core::fmt::{Debug, Formatter};
2
3use bevy_platform::collections::HashTable;
4use bevy_reflect_derive::impl_type_path;
5
6use crate::{
7 generics::impl_generic_info_methods, type_info::impl_type_methods, ApplyError, Generics,
8 MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
9 TypeInfo, TypePath,
10};
11use alloc::{boxed::Box, format, vec::Vec};
12
13pub trait Map: PartialReflect {
49 fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
53
54 fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect>;
58
59 fn len(&self) -> usize;
61
62 fn is_empty(&self) -> bool {
64 self.len() == 0
65 }
66
67 fn iter(&self) -> Box<dyn Iterator<Item = (&dyn PartialReflect, &dyn PartialReflect)> + '_>;
69
70 fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>;
74
75 fn retain(&mut self, f: &mut dyn FnMut(&dyn PartialReflect, &mut dyn PartialReflect) -> bool);
79
80 fn to_dynamic_map(&self) -> DynamicMap {
82 let mut map = DynamicMap::default();
83 map.set_represented_type(self.get_represented_type_info());
84 for (key, value) in self.iter() {
85 map.insert_boxed(key.to_dynamic(), value.to_dynamic());
86 }
87 map
88 }
89
90 fn insert_boxed(
95 &mut self,
96 key: Box<dyn PartialReflect>,
97 value: Box<dyn PartialReflect>,
98 ) -> Option<Box<dyn PartialReflect>>;
99
100 fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>>;
105
106 fn get_represented_map_info(&self) -> Option<&'static MapInfo> {
108 self.get_represented_type_info()?.as_map().ok()
109 }
110}
111
112#[derive(Clone, Debug)]
114pub struct MapInfo {
115 ty: Type,
116 generics: Generics,
117 key_info: fn() -> Option<&'static TypeInfo>,
118 key_ty: Type,
119 value_info: fn() -> Option<&'static TypeInfo>,
120 value_ty: Type,
121 #[cfg(feature = "documentation")]
122 docs: Option<&'static str>,
123}
124
125impl MapInfo {
126 pub fn new<
128 TMap: Map + TypePath,
129 TKey: Reflect + MaybeTyped + TypePath,
130 TValue: Reflect + MaybeTyped + TypePath,
131 >() -> Self {
132 Self {
133 ty: Type::of::<TMap>(),
134 generics: Generics::new(),
135 key_info: TKey::maybe_type_info,
136 key_ty: Type::of::<TKey>(),
137 value_info: TValue::maybe_type_info,
138 value_ty: Type::of::<TValue>(),
139 #[cfg(feature = "documentation")]
140 docs: None,
141 }
142 }
143
144 #[cfg(feature = "documentation")]
146 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
147 Self { docs, ..self }
148 }
149
150 impl_type_methods!(ty);
151
152 pub fn key_info(&self) -> Option<&'static TypeInfo> {
157 (self.key_info)()
158 }
159
160 pub fn key_ty(&self) -> Type {
164 self.key_ty
165 }
166
167 pub fn value_info(&self) -> Option<&'static TypeInfo> {
172 (self.value_info)()
173 }
174
175 pub fn value_ty(&self) -> Type {
179 self.value_ty
180 }
181
182 #[cfg(feature = "documentation")]
184 pub fn docs(&self) -> Option<&'static str> {
185 self.docs
186 }
187
188 impl_generic_info_methods!(generics);
189}
190
191#[macro_export]
194macro_rules! hash_error {
195 ( $key:expr ) => {{
196 let type_path = (*$key).reflect_type_path();
197 if !$key.is_dynamic() {
198 format!(
199 "the given key of type `{}` does not support hashing",
200 type_path
201 )
202 } else {
203 match (*$key).get_represented_type_info() {
204 None => format!("the dynamic type `{}` does not support hashing", type_path),
206 Some(s) => format!(
208 "the dynamic type `{}` (representing `{}`) does not support hashing",
209 type_path,
210 s.type_path()
211 ),
212 }
213 }
214 }}
215}
216
217#[derive(Default)]
219pub struct DynamicMap {
220 represented_type: Option<&'static TypeInfo>,
221 hash_table: HashTable<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>,
222}
223
224impl DynamicMap {
225 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
233 if let Some(represented_type) = represented_type {
234 assert!(
235 matches!(represented_type, TypeInfo::Map(_)),
236 "expected TypeInfo::Map but received: {represented_type:?}"
237 );
238 }
239
240 self.represented_type = represented_type;
241 }
242
243 pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
245 self.insert_boxed(Box::new(key), Box::new(value));
246 }
247
248 fn internal_hash(value: &dyn PartialReflect) -> u64 {
249 value.reflect_hash().expect(&hash_error!(value))
250 }
251
252 fn internal_eq(
253 key: &dyn PartialReflect,
254 ) -> impl FnMut(&(Box<dyn PartialReflect>, Box<dyn PartialReflect>)) -> bool + '_ {
255 |(other, _)| {
256 key
257 .reflect_partial_eq(&**other)
258 .expect("underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
259 }
260 }
261}
262
263impl Map for DynamicMap {
264 fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
265 self.hash_table
266 .find(Self::internal_hash(key), Self::internal_eq(key))
267 .map(|(_, value)| &**value)
268 }
269
270 fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
271 self.hash_table
272 .find_mut(Self::internal_hash(key), Self::internal_eq(key))
273 .map(|(_, value)| &mut **value)
274 }
275
276 fn len(&self) -> usize {
277 self.hash_table.len()
278 }
279
280 fn iter(&self) -> Box<dyn Iterator<Item = (&dyn PartialReflect, &dyn PartialReflect)> + '_> {
281 let iter = self.hash_table.iter().map(|(k, v)| (&**k, &**v));
282 Box::new(iter)
283 }
284
285 fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> {
286 self.hash_table.drain().collect()
287 }
288
289 fn retain(&mut self, f: &mut dyn FnMut(&dyn PartialReflect, &mut dyn PartialReflect) -> bool) {
290 self.hash_table
291 .retain(move |(key, value)| f(&**key, &mut **value));
292 }
293
294 fn insert_boxed(
295 &mut self,
296 key: Box<dyn PartialReflect>,
297 value: Box<dyn PartialReflect>,
298 ) -> Option<Box<dyn PartialReflect>> {
299 assert_eq!(
300 key.reflect_partial_eq(&*key),
301 Some(true),
302 "keys inserted in `Map`-like types are expected to reflect `PartialEq`"
303 );
304
305 let hash = Self::internal_hash(&*key);
306 let eq = Self::internal_eq(&*key);
307 match self.hash_table.find_mut(hash, eq) {
308 Some((_, old)) => Some(core::mem::replace(old, value)),
309 None => {
310 self.hash_table.insert_unique(
311 Self::internal_hash(key.as_ref()),
312 (key, value),
313 |(key, _)| Self::internal_hash(&**key),
314 );
315 None
316 }
317 }
318 }
319
320 fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>> {
321 let hash = Self::internal_hash(key);
322 let eq = Self::internal_eq(key);
323 match self.hash_table.find_entry(hash, eq) {
324 Ok(entry) => {
325 let ((_, old_value), _) = entry.remove();
326 Some(old_value)
327 }
328 Err(_) => None,
329 }
330 }
331}
332
333impl PartialReflect for DynamicMap {
334 #[inline]
335 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
336 self.represented_type
337 }
338
339 #[inline]
340 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
341 self
342 }
343
344 #[inline]
345 fn as_partial_reflect(&self) -> &dyn PartialReflect {
346 self
347 }
348
349 #[inline]
350 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
351 self
352 }
353
354 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
355 Err(self)
356 }
357
358 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
359 None
360 }
361
362 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
363 None
364 }
365
366 fn apply(&mut self, value: &dyn PartialReflect) {
367 map_apply(self, value);
368 }
369
370 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
371 map_try_apply(self, value)
372 }
373
374 fn reflect_kind(&self) -> ReflectKind {
375 ReflectKind::Map
376 }
377
378 fn reflect_ref(&self) -> ReflectRef<'_> {
379 ReflectRef::Map(self)
380 }
381
382 fn reflect_mut(&mut self) -> ReflectMut<'_> {
383 ReflectMut::Map(self)
384 }
385
386 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
387 ReflectOwned::Map(self)
388 }
389
390 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
391 map_partial_eq(self, value)
392 }
393
394 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
395 write!(f, "DynamicMap(")?;
396 map_debug(self, f)?;
397 write!(f, ")")
398 }
399
400 #[inline]
401 fn is_dynamic(&self) -> bool {
402 true
403 }
404}
405
406impl_type_path!((in bevy_reflect) DynamicMap);
407
408impl Debug for DynamicMap {
409 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
410 self.debug(f)
411 }
412}
413
414impl FromIterator<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> for DynamicMap {
415 fn from_iter<I: IntoIterator<Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>)>>(
416 items: I,
417 ) -> Self {
418 let mut map = Self::default();
419 for (key, value) in items.into_iter() {
420 map.insert_boxed(key, value);
421 }
422 map
423 }
424}
425
426impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
427 fn from_iter<I: IntoIterator<Item = (K, V)>>(items: I) -> Self {
428 let mut map = Self::default();
429 for (key, value) in items.into_iter() {
430 map.insert(key, value);
431 }
432 map
433 }
434}
435
436impl IntoIterator for DynamicMap {
437 type Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>);
438 type IntoIter = bevy_platform::collections::hash_table::IntoIter<Self::Item>;
439
440 fn into_iter(self) -> Self::IntoIter {
441 self.hash_table.into_iter()
442 }
443}
444
445impl<'a> IntoIterator for &'a DynamicMap {
446 type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
447 type IntoIter = core::iter::Map<
448 bevy_platform::collections::hash_table::Iter<
449 'a,
450 (Box<dyn PartialReflect>, Box<dyn PartialReflect>),
451 >,
452 fn(&'a (Box<dyn PartialReflect>, Box<dyn PartialReflect>)) -> Self::Item,
453 >;
454
455 fn into_iter(self) -> Self::IntoIter {
456 self.hash_table
457 .iter()
458 .map(|(k, v)| (k.as_ref(), v.as_ref()))
459 }
460}
461
462#[inline]
472pub fn map_partial_eq<M: Map + ?Sized>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
473 let ReflectRef::Map(map) = b.reflect_ref() else {
474 return Some(false);
475 };
476
477 if a.len() != map.len() {
478 return Some(false);
479 }
480
481 for (key, value) in a.iter() {
482 if let Some(map_value) = map.get(key) {
483 let eq_result = value.reflect_partial_eq(map_value);
484 if let failed @ (Some(false) | None) = eq_result {
485 return failed;
486 }
487 } else {
488 return Some(false);
489 }
490 }
491
492 Some(true)
493}
494
495#[inline]
513pub fn map_debug(dyn_map: &dyn Map, f: &mut Formatter<'_>) -> core::fmt::Result {
514 let mut debug = f.debug_map();
515 for (key, value) in dyn_map.iter() {
516 debug.entry(&key as &dyn Debug, &value as &dyn Debug);
517 }
518 debug.finish()
519}
520
521#[inline]
530pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
531 if let Err(err) = map_try_apply(a, b) {
532 panic!("{err}");
533 }
534}
535
536#[inline]
547pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
548 let map_value = b.reflect_ref().as_map()?;
549
550 for (key, b_value) in map_value.iter() {
551 if let Some(a_value) = a.get_mut(key) {
552 a_value.try_apply(b_value)?;
553 } else {
554 a.insert_boxed(key.to_dynamic(), b_value.to_dynamic());
555 }
556 }
557 a.retain(&mut |key, _| map_value.get(key).is_some());
558
559 Ok(())
560}
561
562#[cfg(test)]
563mod tests {
564
565 use crate::PartialReflect;
566
567 use super::{DynamicMap, Map};
568
569 #[test]
570 fn remove() {
571 let mut map = DynamicMap::default();
572 map.insert(0, 0);
573 map.insert(1, 1);
574
575 assert_eq!(map.remove(&0).unwrap().try_downcast_ref(), Some(&0));
576 assert!(map.get(&0).is_none());
577 assert_eq!(map.get(&1).unwrap().try_downcast_ref(), Some(&1));
578
579 assert_eq!(map.remove(&1).unwrap().try_downcast_ref(), Some(&1));
580 assert!(map.get(&1).is_none());
581
582 assert!(map.remove(&1).is_none());
583 assert!(map.get(&1).is_none());
584 }
585
586 #[test]
587 fn apply() {
588 let mut map_a = DynamicMap::default();
589 map_a.insert(0, 0);
590 map_a.insert(1, 1);
591
592 let mut map_b = DynamicMap::default();
593 map_b.insert(10, 10);
594 map_b.insert(1, 5);
595
596 map_a.apply(&map_b);
597
598 assert!(map_a.get(&0).is_none());
599 assert_eq!(map_a.get(&1).unwrap().try_downcast_ref(), Some(&5));
600 assert_eq!(map_a.get(&10).unwrap().try_downcast_ref(), Some(&10));
601 }
602}