Skip to main content

bevy_reflect/
map.rs

1//! Traits and types used to power [map-like] operations via reflection.
2//!
3//! [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
4use core::fmt::{Debug, Formatter};
5
6use bevy_platform::collections::HashTable;
7use bevy_reflect_derive::impl_type_path;
8
9use crate::{
10    generics::impl_generic_info_methods, type_info::impl_type_methods, ApplyError, Generics,
11    MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type,
12    TypeInfo, TypePath,
13};
14use alloc::{boxed::Box, format, vec::Vec};
15
16/// A trait used to power [map-like] operations via [reflection].
17///
18/// Maps contain zero or more entries of a key and its associated value,
19/// and correspond to types like [`HashMap`] and [`BTreeMap`].
20/// The order of these entries is not guaranteed by this trait.
21///
22/// # Hashing and equality
23///
24/// All keys are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
25/// comparable using [`PartialReflect::reflect_partial_eq`].
26/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
27/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
28/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
29/// This is true even for manual implementors who do not hash or compare values,
30/// as it is still relied on by [`DynamicMap`].
31///
32/// # Example
33///
34/// ```
35/// use bevy_reflect::{PartialReflect, Reflect, map::Map};
36/// use std::collections::HashMap;
37///
38///
39/// let foo: &mut dyn Map = &mut HashMap::<u32, bool>::new();
40/// foo.insert_boxed(Box::new(123_u32), Box::new(true));
41/// assert_eq!(foo.len(), 1);
42///
43/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
44/// assert_eq!(field.try_downcast_ref::<bool>(), Some(&true));
45/// ```
46///
47/// [`HashMap`]: std::collections::HashMap
48/// [`BTreeMap`]: alloc::collections::BTreeMap
49/// [map-like]: https://doc.rust-lang.org/book/ch08-03-hash-maps.html
50/// [reflection]: crate
51pub trait Map: PartialReflect {
52    /// Returns a reference to the value associated with the given key.
53    ///
54    /// If no value is associated with `key`, returns `None`.
55    fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
56
57    /// Returns a mutable reference to the value associated with the given key.
58    ///
59    /// If no value is associated with `key`, returns `None`.
60    fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect>;
61
62    /// Returns the number of elements in the map.
63    fn len(&self) -> usize;
64
65    /// Returns `true` if the list contains no elements.
66    fn is_empty(&self) -> bool {
67        self.len() == 0
68    }
69
70    /// Returns an iterator over the key-value pairs of the map.
71    fn iter(&self) -> Box<dyn Iterator<Item = (&dyn PartialReflect, &dyn PartialReflect)> + '_>;
72
73    /// Drain the key-value pairs of this map to get a vector of owned values.
74    ///
75    /// After calling this function, `self` will be empty.
76    fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>;
77
78    /// Retain only the elements specified by the predicate.
79    ///
80    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
81    fn retain(&mut self, f: &mut dyn FnMut(&dyn PartialReflect, &mut dyn PartialReflect) -> bool);
82
83    /// Creates a new [`DynamicMap`] from this map.
84    fn to_dynamic_map(&self) -> DynamicMap {
85        let mut map = DynamicMap::default();
86        map.set_represented_type(self.get_represented_type_info());
87        for (key, value) in self.iter() {
88            map.insert_boxed(key.to_dynamic(), value.to_dynamic());
89        }
90        map
91    }
92
93    /// Inserts a key-value pair into the map.
94    ///
95    /// If the map did not have this key present, `None` is returned.
96    /// If the map did have this key present, the value is updated, and the old value is returned.
97    fn insert_boxed(
98        &mut self,
99        key: Box<dyn PartialReflect>,
100        value: Box<dyn PartialReflect>,
101    ) -> Option<Box<dyn PartialReflect>>;
102
103    /// Removes an entry from the map.
104    ///
105    /// If the map did not have this key present, `None` is returned.
106    /// If the map did have this key present, the removed value is returned.
107    fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>>;
108
109    /// Will return `None` if [`TypeInfo`] is not available.
110    fn get_represented_map_info(&self) -> Option<&'static MapInfo> {
111        self.get_represented_type_info()?.as_map().ok()
112    }
113}
114
115/// A container for compile-time map info.
116#[derive(#[automatically_derived]
impl ::core::clone::Clone for MapInfo {
    #[inline]
    fn clone(&self) -> MapInfo {
        MapInfo {
            ty: ::core::clone::Clone::clone(&self.ty),
            generics: ::core::clone::Clone::clone(&self.generics),
            key_info: ::core::clone::Clone::clone(&self.key_info),
            key_ty: ::core::clone::Clone::clone(&self.key_ty),
            value_info: ::core::clone::Clone::clone(&self.value_info),
            value_ty: ::core::clone::Clone::clone(&self.value_ty),
            docs: ::core::clone::Clone::clone(&self.docs),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for MapInfo {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["ty", "generics", "key_info", "key_ty", "value_info",
                        "value_ty", "docs"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.ty, &self.generics, &self.key_info, &self.key_ty,
                        &self.value_info, &self.value_ty, &&self.docs];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "MapInfo",
            names, values)
    }
}Debug)]
117pub struct MapInfo {
118    ty: Type,
119    generics: Generics,
120    key_info: fn() -> Option<&'static TypeInfo>,
121    key_ty: Type,
122    value_info: fn() -> Option<&'static TypeInfo>,
123    value_ty: Type,
124    #[cfg(feature = "reflect_documentation")]
125    docs: Option<&'static str>,
126}
127
128impl MapInfo {
129    /// Create a new [`MapInfo`].
130    pub fn new<
131        TMap: Map + TypePath,
132        TKey: Reflect + MaybeTyped + TypePath,
133        TValue: Reflect + MaybeTyped + TypePath,
134    >() -> Self {
135        Self {
136            ty: Type::of::<TMap>(),
137            generics: Generics::new(),
138            key_info: TKey::maybe_type_info,
139            key_ty: Type::of::<TKey>(),
140            value_info: TValue::maybe_type_info,
141            value_ty: Type::of::<TValue>(),
142            #[cfg(feature = "reflect_documentation")]
143            docs: None,
144        }
145    }
146
147    /// Sets the docstring for this map.
148    #[cfg(feature = "reflect_documentation")]
149    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
150        Self { docs, ..self }
151    }
152
153    /// The underlying Rust [type].
///
/// [type]: crate::type_info::Type
pub fn ty(&self) -> &crate::type_info::Type { { &self.ty } }
/// The [`TypeId`] of this type.
///
/// [`TypeId`]: core::any::TypeId
pub fn type_id(&self) -> ::core::any::TypeId { self.ty().id() }
/// The [stable, full type path] of this type.
///
/// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
///
/// [stable, full type path]: TypePath
/// [`type_path_table`]: Self::type_path_table
pub fn type_path(&self) -> &'static str { self.ty().path() }
/// A representation of the type path of this type.
///
/// Provides dynamic access to all methods on [`TypePath`].
///
/// [`TypePath`]: crate::type_path::TypePath
pub fn type_path_table(&self) -> &crate::type_path::TypePathTable {
    &self.ty().type_path_table()
}
/// Check if the given type matches this one.
///
/// This only compares the [`TypeId`] of the types
/// and does not verify they share the same [`TypePath`]
/// (though it implies they do).
///
/// [`TypeId`]: core::any::TypeId
/// [`TypePath`]: crate::type_path::TypePath
pub fn is<T: ::core::any::Any>(&self) -> bool { self.ty().is::<T>() }impl_type_methods!(ty);
154
155    /// The [`TypeInfo`] of the key type.
156    ///
157    /// Returns `None` if the key type does not contain static type information,
158    /// such as for dynamic types.
159    pub fn key_info(&self) -> Option<&'static TypeInfo> {
160        (self.key_info)()
161    }
162
163    /// The [type] of the key type.
164    ///
165    /// [type]: Type
166    pub fn key_ty(&self) -> Type {
167        self.key_ty
168    }
169
170    /// The [`TypeInfo`] of the value type.
171    ///
172    /// Returns `None` if the value type does not contain static type information,
173    /// such as for dynamic types.
174    pub fn value_info(&self) -> Option<&'static TypeInfo> {
175        (self.value_info)()
176    }
177
178    /// The [type] of the value type.
179    ///
180    /// [type]: Type
181    pub fn value_ty(&self) -> Type {
182        self.value_ty
183    }
184
185    /// The docstring of this map, if any.
186    #[cfg(feature = "reflect_documentation")]
187    pub fn docs(&self) -> Option<&'static str> {
188        self.docs
189    }
190
191    /// Gets the generic parameters for this type.
pub fn generics(&self) -> &crate::generics::Generics { &self.generics }
/// Sets the generic parameters for this type.
pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
    self.generics = generics;
    self
}impl_generic_info_methods!(generics);
192}
193
194/// Used to produce an error message when an attempt is made to hash
195/// a [`PartialReflect`] value that does not support hashing.
196#[macro_export]
197macro_rules! hash_error {
198    ( $key:expr ) => {{
199        let type_path = (*$key).reflect_type_path();
200        if !$key.is_dynamic() {
201            format!(
202                "the given key of type `{}` does not support hashing",
203                type_path
204            )
205        } else {
206            match (*$key).get_represented_type_info() {
207                // Handle dynamic types that do not represent a type (i.e a plain `DynamicStruct`):
208                None => format!("the dynamic type `{}` does not support hashing", type_path),
209                // Handle dynamic types that do represent a type (i.e. a `DynamicStruct` proxying `Foo`):
210                Some(s) => format!(
211                    "the dynamic type `{}` (representing `{}`) does not support hashing",
212                    type_path,
213                    s.type_path()
214                ),
215            }
216        }
217    }}
218}
219
220/// An unordered mapping between reflected values.
221#[derive(#[automatically_derived]
impl ::core::default::Default for DynamicMap {
    #[inline]
    fn default() -> DynamicMap {
        DynamicMap {
            represented_type: ::core::default::Default::default(),
            hash_table: ::core::default::Default::default(),
        }
    }
}Default)]
222pub struct DynamicMap {
223    represented_type: Option<&'static TypeInfo>,
224    hash_table: HashTable<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)>,
225}
226
227impl DynamicMap {
228    /// Sets the [type] to be represented by this `DynamicMap`.
229    ///
230    /// # Panics
231    ///
232    /// Panics if the given [type] is not a [`TypeInfo::Map`].
233    ///
234    /// [type]: TypeInfo
235    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
236        if let Some(represented_type) = represented_type {
237            if !#[allow(non_exhaustive_omitted_patterns)] match represented_type {
            TypeInfo::Map(_) => true,
            _ => false,
        } {
    {
        ::core::panicking::panic_fmt(format_args!("expected TypeInfo::Map but received: {0:?}",
                represented_type));
    }
};assert!(
238                matches!(represented_type, TypeInfo::Map(_)),
239                "expected TypeInfo::Map but received: {represented_type:?}"
240            );
241        }
242
243        self.represented_type = represented_type;
244    }
245
246    /// Inserts a typed key-value pair into the map.
247    pub fn insert<K: PartialReflect, V: PartialReflect>(&mut self, key: K, value: V) {
248        self.insert_boxed(Box::new(key), Box::new(value));
249    }
250
251    fn internal_hash(value: &dyn PartialReflect) -> u64 {
252        value.reflect_hash().expect(&{
    let type_path = (*value).reflect_type_path();
    if !value.is_dynamic() {
        ::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("the given key of type `{0}` does not support hashing",
                        type_path))
            })
    } else {
        match (*value).get_represented_type_info() {
            None =>
                ::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("the dynamic type `{0}` does not support hashing",
                                type_path))
                    }),
            Some(s) =>
                ::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("the dynamic type `{0}` (representing `{1}`) does not support hashing",
                                type_path, s.type_path()))
                    }),
        }
    }
}hash_error!(value))
253    }
254
255    fn internal_eq(
256        key: &dyn PartialReflect,
257    ) -> impl FnMut(&(Box<dyn PartialReflect>, Box<dyn PartialReflect>)) -> bool + '_ {
258        |(other, _)| {
259            key
260            .reflect_partial_eq(&**other)
261            .expect("underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
262        }
263    }
264}
265
266impl Map for DynamicMap {
267    fn get(&self, key: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
268        self.hash_table
269            .find(Self::internal_hash(key), Self::internal_eq(key))
270            .map(|(_, value)| &**value)
271    }
272
273    fn get_mut(&mut self, key: &dyn PartialReflect) -> Option<&mut dyn PartialReflect> {
274        self.hash_table
275            .find_mut(Self::internal_hash(key), Self::internal_eq(key))
276            .map(|(_, value)| &mut **value)
277    }
278
279    fn len(&self) -> usize {
280        self.hash_table.len()
281    }
282
283    fn iter(&self) -> Box<dyn Iterator<Item = (&dyn PartialReflect, &dyn PartialReflect)> + '_> {
284        let iter = self.hash_table.iter().map(|(k, v)| (&**k, &**v));
285        Box::new(iter)
286    }
287
288    fn drain(&mut self) -> Vec<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> {
289        self.hash_table.drain().collect()
290    }
291
292    fn retain(&mut self, f: &mut dyn FnMut(&dyn PartialReflect, &mut dyn PartialReflect) -> bool) {
293        self.hash_table
294            .retain(move |(key, value)| f(&**key, &mut **value));
295    }
296
297    fn insert_boxed(
298        &mut self,
299        key: Box<dyn PartialReflect>,
300        value: Box<dyn PartialReflect>,
301    ) -> Option<Box<dyn PartialReflect>> {
302        match (&key.reflect_partial_eq(&*key), &Some(true)) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::Some(format_args!("keys inserted in `Map`-like types are expected to reflect `PartialEq`")));
        }
    }
};assert_eq!(
303            key.reflect_partial_eq(&*key),
304            Some(true),
305            "keys inserted in `Map`-like types are expected to reflect `PartialEq`"
306        );
307
308        let hash = Self::internal_hash(&*key);
309        let eq = Self::internal_eq(&*key);
310        match self.hash_table.find_mut(hash, eq) {
311            Some((_, old)) => Some(core::mem::replace(old, value)),
312            None => {
313                self.hash_table.insert_unique(
314                    Self::internal_hash(key.as_ref()),
315                    (key, value),
316                    |(key, _)| Self::internal_hash(&**key),
317                );
318                None
319            }
320        }
321    }
322
323    fn remove(&mut self, key: &dyn PartialReflect) -> Option<Box<dyn PartialReflect>> {
324        let hash = Self::internal_hash(key);
325        let eq = Self::internal_eq(key);
326        match self.hash_table.find_entry(hash, eq) {
327            Ok(entry) => {
328                let ((_, old_value), _) = entry.remove();
329                Some(old_value)
330            }
331            Err(_) => None,
332        }
333    }
334}
335
336impl PartialReflect for DynamicMap {
337    #[inline]
338    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
339        self.represented_type
340    }
341
342    #[inline]
343    fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
344        self
345    }
346
347    #[inline]
348    fn as_partial_reflect(&self) -> &dyn PartialReflect {
349        self
350    }
351
352    #[inline]
353    fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
354        self
355    }
356
357    fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
358        Err(self)
359    }
360
361    fn try_as_reflect(&self) -> Option<&dyn Reflect> {
362        None
363    }
364
365    fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
366        None
367    }
368
369    fn apply(&mut self, value: &dyn PartialReflect) {
370        map_apply(self, value);
371    }
372
373    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
374        map_try_apply(self, value)
375    }
376
377    fn reflect_kind(&self) -> ReflectKind {
378        ReflectKind::Map
379    }
380
381    fn reflect_ref(&self) -> ReflectRef<'_> {
382        ReflectRef::Map(self)
383    }
384
385    fn reflect_mut(&mut self) -> ReflectMut<'_> {
386        ReflectMut::Map(self)
387    }
388
389    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
390        ReflectOwned::Map(self)
391    }
392
393    fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
394        map_partial_eq(self, value)
395    }
396
397    fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
398        f.write_fmt(format_args!("DynamicMap("))write!(f, "DynamicMap(")?;
399        map_debug(self, f)?;
400        f.write_fmt(format_args!(")"))write!(f, ")")
401    }
402
403    #[inline]
404    fn is_dynamic(&self) -> bool {
405        true
406    }
407}
408
409const _: () =
    {
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for DynamicMap where  {
            fn type_path() -> &'static str { "bevy_reflect::DynamicMap" }
            fn short_type_path() -> &'static str { "DynamicMap" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("DynamicMap")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_reflect")
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_reflect")
            }
        }
    };impl_type_path!((in bevy_reflect) DynamicMap);
410
411impl Debug for DynamicMap {
412    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
413        self.debug(f)
414    }
415}
416
417impl FromIterator<(Box<dyn PartialReflect>, Box<dyn PartialReflect>)> for DynamicMap {
418    fn from_iter<I: IntoIterator<Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>)>>(
419        items: I,
420    ) -> Self {
421        let mut map = Self::default();
422        for (key, value) in items.into_iter() {
423            map.insert_boxed(key, value);
424        }
425        map
426    }
427}
428
429impl<K: Reflect, V: Reflect> FromIterator<(K, V)> for DynamicMap {
430    fn from_iter<I: IntoIterator<Item = (K, V)>>(items: I) -> Self {
431        let mut map = Self::default();
432        for (key, value) in items.into_iter() {
433            map.insert(key, value);
434        }
435        map
436    }
437}
438
439impl IntoIterator for DynamicMap {
440    type Item = (Box<dyn PartialReflect>, Box<dyn PartialReflect>);
441    type IntoIter = bevy_platform::collections::hash_table::IntoIter<Self::Item>;
442
443    fn into_iter(self) -> Self::IntoIter {
444        self.hash_table.into_iter()
445    }
446}
447
448impl<'a> IntoIterator for &'a DynamicMap {
449    type Item = (&'a dyn PartialReflect, &'a dyn PartialReflect);
450    type IntoIter = core::iter::Map<
451        bevy_platform::collections::hash_table::Iter<
452            'a,
453            (Box<dyn PartialReflect>, Box<dyn PartialReflect>),
454        >,
455        fn(&'a (Box<dyn PartialReflect>, Box<dyn PartialReflect>)) -> Self::Item,
456    >;
457
458    fn into_iter(self) -> Self::IntoIter {
459        self.hash_table
460            .iter()
461            .map(|(k, v)| (k.as_ref(), v.as_ref()))
462    }
463}
464
465/// Compares a [`Map`] with a [`PartialReflect`] value.
466///
467/// Returns true if and only if all of the following are true:
468/// - `b` is a map;
469/// - `b` is the same length as `a`;
470/// - For each key-value pair in `a`, `b` contains a value for the given key,
471///   and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
472///
473/// Returns [`None`] if the comparison couldn't even be performed.
474#[inline]
475pub fn map_partial_eq<M: Map + ?Sized>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
476    let ReflectRef::Map(map) = b.reflect_ref() else {
477        return Some(false);
478    };
479
480    if a.len() != map.len() {
481        return Some(false);
482    }
483
484    for (key, value) in a.iter() {
485        if let Some(map_value) = map.get(key) {
486            let eq_result = value.reflect_partial_eq(map_value);
487            if let failed @ (Some(false) | None) = eq_result {
488                return failed;
489            }
490        } else {
491            return Some(false);
492        }
493    }
494
495    Some(true)
496}
497
498/// Lexicographically compares two [`Map`] values according to their iteration order
499/// (suitable for ordered maps like `BTreeMap`).
500///
501/// For each entry pair `(a_k, a_v)` and `(b_k, b_v)` in the iteration order,
502/// compare `a_k` to `b_k` using `reflect_partial_cmp`, returning the first
503/// non-equal ordering. If keys are equal, compare values `a_v` and `b_v `similarly. If all
504/// compared entries are equal, the shorter map is `Less` and longer is `Greater`.
505///
506/// Returns [`None`] if the comparison couldn't be performed (kinds mismatch or
507/// an element comparison returns `None`).
508#[inline]
509pub fn map_partial_cmp<M: Map + ?Sized>(
510    a: &M,
511    b: &dyn PartialReflect,
512) -> Option<::core::cmp::Ordering> {
513    let ReflectRef::Map(map) = b.reflect_ref() else {
514        return None;
515    };
516
517    let mut a_iter = a.iter();
518    let mut b_iter = map.iter();
519
520    loop {
521        match (a_iter.next(), b_iter.next()) {
522            (Some((a_k, a_v)), Some((b_k, b_v))) => {
523                match a_k.reflect_partial_cmp(b_k) {
524                    None => return None,
525                    Some(core::cmp::Ordering::Equal) => {}
526                    Some(ord) => return Some(ord),
527                }
528
529                match a_v.reflect_partial_cmp(b_v) {
530                    None => return None,
531                    Some(core::cmp::Ordering::Equal) => {}
532                    Some(ord) => return Some(ord),
533                }
534            }
535            (None, None) => return Some(::core::cmp::Ordering::Equal),
536            (None, Some(_)) => return Some(::core::cmp::Ordering::Less),
537            (Some(_), None) => return Some(::core::cmp::Ordering::Greater),
538        }
539    }
540}
541
542/// The default debug formatter for [`Map`] types.
543///
544/// # Example
545/// ```
546/// # use std::collections::HashMap;
547/// use bevy_reflect::Reflect;
548///
549/// let mut my_map = HashMap::new();
550/// my_map.insert(123, String::from("Hello"));
551/// println!("{:#?}", &my_map as &dyn Reflect);
552///
553/// // Output:
554///
555/// // {
556/// //   123: "Hello",
557/// // }
558/// ```
559#[inline]
560pub fn map_debug(dyn_map: &dyn Map, f: &mut Formatter<'_>) -> core::fmt::Result {
561    let mut debug = f.debug_map();
562    for (key, value) in dyn_map.iter() {
563        debug.entry(&key as &dyn Debug, &value as &dyn Debug);
564    }
565    debug.finish()
566}
567
568/// Applies the elements of reflected map `b` to the corresponding elements of map `a`.
569///
570/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
571/// If a key from `a` does not exist in `b`, the value is removed.
572///
573/// # Panics
574///
575/// This function panics if `b` is not a reflected map.
576#[inline]
577pub fn map_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) {
578    if let Err(err) = map_try_apply(a, b) {
579        { ::core::panicking::panic_fmt(format_args!("{0}", err)); };panic!("{err}");
580    }
581}
582
583/// Tries to apply the elements of reflected map `b` to the corresponding elements of map `a`
584/// and returns a Result.
585///
586/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
587/// If a key from `a` does not exist in `b`, the value is removed.
588///
589/// # Errors
590///
591/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected map or if
592/// applying elements to each other fails.
593#[inline]
594pub fn map_try_apply<M: Map>(a: &mut M, b: &dyn PartialReflect) -> Result<(), ApplyError> {
595    let map_value = b.reflect_ref().as_map()?;
596
597    for (key, b_value) in map_value.iter() {
598        if let Some(a_value) = a.get_mut(key) {
599            a_value.try_apply(b_value)?;
600        } else {
601            a.insert_boxed(key.to_dynamic(), b_value.to_dynamic());
602        }
603    }
604    a.retain(&mut |key, _| map_value.get(key).is_some());
605
606    Ok(())
607}
608
609#[cfg(test)]
610mod tests {
611
612    use crate::PartialReflect;
613
614    use super::{DynamicMap, Map};
615
616    #[test]
617    fn remove() {
618        let mut map = DynamicMap::default();
619        map.insert(0, 0);
620        map.insert(1, 1);
621
622        assert_eq!(map.remove(&0).unwrap().try_downcast_ref(), Some(&0));
623        assert!(map.get(&0).is_none());
624        assert_eq!(map.get(&1).unwrap().try_downcast_ref(), Some(&1));
625
626        assert_eq!(map.remove(&1).unwrap().try_downcast_ref(), Some(&1));
627        assert!(map.get(&1).is_none());
628
629        assert!(map.remove(&1).is_none());
630        assert!(map.get(&1).is_none());
631    }
632
633    #[test]
634    fn apply() {
635        let mut map_a = DynamicMap::default();
636        map_a.insert(0, 0);
637        map_a.insert(1, 1);
638
639        let mut map_b = DynamicMap::default();
640        map_b.insert(10, 10);
641        map_b.insert(1, 5);
642
643        map_a.apply(&map_b);
644
645        assert!(map_a.get(&0).is_none());
646        assert_eq!(map_a.get(&1).unwrap().try_downcast_ref(), Some(&5));
647        assert_eq!(map_a.get(&10).unwrap().try_downcast_ref(), Some(&10));
648    }
649}