bevy_reflect/
map.rs

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