bevy_reflect/
set.rs

1use core::fmt::{Debug, Formatter};
2
3use bevy_reflect_derive::impl_type_path;
4use bevy_utils::hashbrown::{hash_table::OccupiedEntry as HashTableOccupiedEntry, HashTable};
5
6use crate::generics::impl_generic_info_methods;
7use crate::{
8    self as bevy_reflect, hash_error, type_info::impl_type_methods, ApplyError, Generics,
9    PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
10    TypePath,
11};
12
13/// A trait used to power [set-like] operations via [reflection].
14///
15/// Sets contain zero or more entries of a fixed type, and correspond to types
16/// like [`HashSet`] and [`BTreeSet`].
17/// The order of these entries is not guaranteed by this trait.
18///
19/// # Hashing and equality
20///
21/// All values are expected to return a valid hash value from [`PartialReflect::reflect_hash`] and be
22/// comparable using [`PartialReflect::reflect_partial_eq`].
23/// If using the [`#[derive(Reflect)]`](derive@crate::Reflect) macro, this can be done by adding
24/// `#[reflect(Hash, PartialEq)]` to the entire struct or enum.
25/// The ordering is expected to be total, that is as if the reflected type implements the [`Eq`] trait.
26/// This is true even for manual implementors who do not hash or compare values,
27/// as it is still relied on by [`DynamicSet`].
28///
29/// # Example
30///
31/// ```
32/// use bevy_reflect::{PartialReflect, Set};
33/// use bevy_utils::HashSet;
34///
35///
36/// let foo: &mut dyn Set = &mut HashSet::<u32>::new();
37/// foo.insert_boxed(Box::new(123_u32));
38/// assert_eq!(foo.len(), 1);
39///
40/// let field: &dyn PartialReflect = foo.get(&123_u32).unwrap();
41/// assert_eq!(field.try_downcast_ref::<u32>(), Some(&123_u32));
42/// ```
43///
44/// [`HashSet`]: std::collections::HashSet
45/// [`BTreeSet`]: std::collections::BTreeSet
46/// [set-like]: https://doc.rust-lang.org/stable/std/collections/struct.HashSet.html
47/// [reflection]: crate
48pub trait Set: PartialReflect {
49    /// Returns a reference to the value.
50    ///
51    /// If no value is contained, returns `None`.
52    fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
53
54    /// Returns the number of elements in the set.
55    fn len(&self) -> usize;
56
57    /// Returns `true` if the list contains no elements.
58    fn is_empty(&self) -> bool {
59        self.len() == 0
60    }
61
62    /// Returns an iterator over the values of the set.
63    fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_>;
64
65    /// Drain the values of this set to get a vector of owned values.
66    ///
67    /// After calling this function, `self` will be empty.
68    fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
69
70    /// Clones the set, producing a [`DynamicSet`].
71    fn clone_dynamic(&self) -> DynamicSet;
72
73    /// Inserts a value into the set.
74    ///
75    /// If the set did not have this value present, `true` is returned.
76    /// If the set did have this value present, `false` is returned.
77    fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool;
78
79    /// Removes a value from the set.
80    ///
81    /// If the set did not have this value present, `true` is returned.
82    /// If the set did have this value present, `false` is returned.
83    fn remove(&mut self, value: &dyn PartialReflect) -> bool;
84
85    /// Checks if the given value is contained in the set
86    fn contains(&self, value: &dyn PartialReflect) -> bool;
87}
88
89/// A container for compile-time set info.
90#[derive(Clone, Debug)]
91pub struct SetInfo {
92    ty: Type,
93    generics: Generics,
94    value_ty: Type,
95    #[cfg(feature = "documentation")]
96    docs: Option<&'static str>,
97}
98
99impl SetInfo {
100    /// Create a new [`SetInfo`].
101    pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self {
102        Self {
103            ty: Type::of::<TSet>(),
104            generics: Generics::new(),
105            value_ty: Type::of::<TValue>(),
106            #[cfg(feature = "documentation")]
107            docs: None,
108        }
109    }
110
111    /// Sets the docstring for this set.
112    #[cfg(feature = "documentation")]
113    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
114        Self { docs, ..self }
115    }
116
117    impl_type_methods!(ty);
118
119    /// The [type] of the value.
120    ///
121    /// [type]: Type
122    pub fn value_ty(&self) -> Type {
123        self.value_ty
124    }
125
126    /// The docstring of this set, if any.
127    #[cfg(feature = "documentation")]
128    pub fn docs(&self) -> Option<&'static str> {
129        self.docs
130    }
131
132    impl_generic_info_methods!(generics);
133}
134
135/// An ordered set of reflected values.
136#[derive(Default)]
137pub struct DynamicSet {
138    represented_type: Option<&'static TypeInfo>,
139    hash_table: HashTable<Box<dyn PartialReflect>>,
140}
141
142impl DynamicSet {
143    /// Sets the [type] to be represented by this `DynamicSet`.
144    ///
145    /// # Panics
146    ///
147    /// Panics if the given [type] is not a [`TypeInfo::Set`].
148    ///
149    /// [type]: TypeInfo
150    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
151        if let Some(represented_type) = represented_type {
152            assert!(
153                matches!(represented_type, TypeInfo::Set(_)),
154                "expected TypeInfo::Set but received: {:?}",
155                represented_type
156            );
157        }
158
159        self.represented_type = represented_type;
160    }
161
162    /// Inserts a typed value into the set.
163    pub fn insert<V: Reflect>(&mut self, value: V) {
164        self.insert_boxed(Box::new(value));
165    }
166
167    fn internal_hash(value: &dyn PartialReflect) -> u64 {
168        value.reflect_hash().expect(hash_error!(value))
169    }
170
171    fn internal_eq(
172        value: &dyn PartialReflect,
173    ) -> impl FnMut(&Box<dyn PartialReflect>) -> bool + '_ {
174        |other| {
175            value
176                .reflect_partial_eq(&**other)
177                .expect("Underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
178        }
179    }
180}
181
182impl Set for DynamicSet {
183    fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
184        self.hash_table
185            .find(Self::internal_hash(value), Self::internal_eq(value))
186            .map(|value| &**value)
187    }
188
189    fn len(&self) -> usize {
190        self.hash_table.len()
191    }
192
193    fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_> {
194        let iter = self.hash_table.iter().map(|v| &**v);
195        Box::new(iter)
196    }
197
198    fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
199        self.hash_table.drain().collect::<Vec<_>>()
200    }
201
202    fn clone_dynamic(&self) -> DynamicSet {
203        let mut hash_table = HashTable::new();
204        self.hash_table
205            .iter()
206            .map(|value| value.clone_value())
207            .for_each(|value| {
208                hash_table.insert_unique(Self::internal_hash(value.as_ref()), value, |boxed| {
209                    Self::internal_hash(boxed.as_ref())
210                });
211            });
212
213        DynamicSet {
214            represented_type: self.represented_type,
215            hash_table,
216        }
217    }
218
219    fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool {
220        assert_eq!(
221            value.reflect_partial_eq(&*value),
222            Some(true),
223            "Values inserted in `Set` like types are expected to reflect `PartialEq`"
224        );
225        match self
226            .hash_table
227            .find_mut(Self::internal_hash(&*value), Self::internal_eq(&*value))
228        {
229            Some(old) => {
230                *old = value;
231                false
232            }
233            None => {
234                self.hash_table.insert_unique(
235                    Self::internal_hash(value.as_ref()),
236                    value,
237                    |boxed| Self::internal_hash(boxed.as_ref()),
238                );
239                true
240            }
241        }
242    }
243
244    fn remove(&mut self, value: &dyn PartialReflect) -> bool {
245        self.hash_table
246            .find_entry(Self::internal_hash(value), Self::internal_eq(value))
247            .map(HashTableOccupiedEntry::remove)
248            .is_ok()
249    }
250
251    fn contains(&self, value: &dyn PartialReflect) -> bool {
252        self.hash_table
253            .find(Self::internal_hash(value), Self::internal_eq(value))
254            .is_some()
255    }
256}
257
258impl PartialReflect for DynamicSet {
259    #[inline]
260    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
261        self.represented_type
262    }
263
264    #[inline]
265    fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
266        self
267    }
268
269    #[inline]
270    fn as_partial_reflect(&self) -> &dyn PartialReflect {
271        self
272    }
273
274    #[inline]
275    fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
276        self
277    }
278
279    #[inline]
280    fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
281        Err(self)
282    }
283
284    #[inline]
285    fn try_as_reflect(&self) -> Option<&dyn Reflect> {
286        None
287    }
288
289    #[inline]
290    fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
291        None
292    }
293
294    fn apply(&mut self, value: &dyn PartialReflect) {
295        set_apply(self, value);
296    }
297
298    fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
299        set_try_apply(self, value)
300    }
301
302    fn reflect_kind(&self) -> ReflectKind {
303        ReflectKind::Set
304    }
305
306    fn reflect_ref(&self) -> ReflectRef {
307        ReflectRef::Set(self)
308    }
309
310    fn reflect_mut(&mut self) -> ReflectMut {
311        ReflectMut::Set(self)
312    }
313
314    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
315        ReflectOwned::Set(self)
316    }
317
318    fn clone_value(&self) -> Box<dyn PartialReflect> {
319        Box::new(self.clone_dynamic())
320    }
321
322    fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
323        set_partial_eq(self, value)
324    }
325
326    fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
327        write!(f, "DynamicSet(")?;
328        set_debug(self, f)?;
329        write!(f, ")")
330    }
331
332    #[inline]
333    fn is_dynamic(&self) -> bool {
334        true
335    }
336}
337
338impl_type_path!((in bevy_reflect) DynamicSet);
339
340impl Debug for DynamicSet {
341    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
342        self.debug(f)
343    }
344}
345
346impl FromIterator<Box<dyn PartialReflect>> for DynamicSet {
347    fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
348        let mut this = Self {
349            represented_type: None,
350            hash_table: HashTable::new(),
351        };
352
353        for value in values {
354            this.insert_boxed(value);
355        }
356
357        this
358    }
359}
360
361impl<T: Reflect> FromIterator<T> for DynamicSet {
362    fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
363        let mut this = Self {
364            represented_type: None,
365            hash_table: HashTable::new(),
366        };
367
368        for value in values {
369            this.insert(value);
370        }
371
372        this
373    }
374}
375
376impl IntoIterator for DynamicSet {
377    type Item = Box<dyn PartialReflect>;
378    type IntoIter = bevy_utils::hashbrown::hash_table::IntoIter<Self::Item>;
379
380    fn into_iter(self) -> Self::IntoIter {
381        self.hash_table.into_iter()
382    }
383}
384
385impl<'a> IntoIterator for &'a DynamicSet {
386    type Item = &'a dyn PartialReflect;
387    type IntoIter = core::iter::Map<
388        bevy_utils::hashbrown::hash_table::Iter<'a, Box<dyn PartialReflect>>,
389        fn(&'a Box<dyn PartialReflect>) -> Self::Item,
390    >;
391
392    fn into_iter(self) -> Self::IntoIter {
393        self.hash_table.iter().map(|v| v.as_ref())
394    }
395}
396
397/// Compares a [`Set`] with a [`PartialReflect`] value.
398///
399/// Returns true if and only if all of the following are true:
400/// - `b` is a set;
401/// - `b` is the same length as `a`;
402/// - For each value pair in `a`, `b` contains the value too,
403///   and [`PartialReflect::reflect_partial_eq`] returns `Some(true)` for the two values.
404///
405/// Returns [`None`] if the comparison couldn't even be performed.
406#[inline]
407pub fn set_partial_eq<M: Set>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
408    let ReflectRef::Set(set) = b.reflect_ref() else {
409        return Some(false);
410    };
411
412    if a.len() != set.len() {
413        return Some(false);
414    }
415
416    for value in a.iter() {
417        if let Some(set_value) = set.get(value) {
418            let eq_result = value.reflect_partial_eq(set_value);
419            if let failed @ (Some(false) | None) = eq_result {
420                return failed;
421            }
422        } else {
423            return Some(false);
424        }
425    }
426
427    Some(true)
428}
429
430/// The default debug formatter for [`Set`] types.
431///
432/// # Example
433/// ```
434/// # use bevy_utils::HashSet;
435/// use bevy_reflect::Reflect;
436///
437/// let mut my_set = HashSet::new();
438/// my_set.insert(String::from("Hello"));
439/// println!("{:#?}", &my_set as &dyn Reflect);
440///
441/// // Output:
442///
443/// // {
444/// //   "Hello",
445/// // }
446/// ```
447#[inline]
448pub fn set_debug(dyn_set: &dyn Set, f: &mut Formatter<'_>) -> core::fmt::Result {
449    let mut debug = f.debug_set();
450    for value in dyn_set.iter() {
451        debug.entry(&value as &dyn Debug);
452    }
453    debug.finish()
454}
455
456/// Applies the elements of reflected set `b` to the corresponding elements of set `a`.
457///
458/// If a value from `b` does not exist in `a`, the value is cloned and inserted.
459///
460/// # Panics
461///
462/// This function panics if `b` is not a reflected set.
463#[inline]
464pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
465    if let ReflectRef::Set(set_value) = b.reflect_ref() {
466        for b_value in set_value.iter() {
467            if a.get(b_value).is_none() {
468                a.insert_boxed(b_value.clone_value());
469            }
470        }
471    } else {
472        panic!("Attempted to apply a non-set type to a set type.");
473    }
474}
475
476/// Tries to apply the elements of reflected set `b` to the corresponding elements of set `a`
477/// and returns a Result.
478///
479/// If a key from `b` does not exist in `a`, the value is cloned and inserted.
480///
481/// # Errors
482///
483/// This function returns an [`ApplyError::MismatchedKinds`] if `b` is not a reflected set or if
484/// applying elements to each other fails.
485#[inline]
486pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
487    let set_value = b.reflect_ref().as_set()?;
488
489    for b_value in set_value.iter() {
490        if a.get(b_value).is_none() {
491            a.insert_boxed(b_value.clone_value());
492        }
493    }
494
495    Ok(())
496}
497
498#[cfg(test)]
499mod tests {
500    use super::DynamicSet;
501
502    #[test]
503    fn test_into_iter() {
504        let expected = ["foo", "bar", "baz"];
505
506        let mut set = DynamicSet::default();
507        set.insert(expected[0].to_string());
508        set.insert(expected[1].to_string());
509        set.insert(expected[2].to_string());
510
511        for item in set.into_iter() {
512            let value = item
513                .try_take::<String>()
514                .expect("couldn't downcast to String");
515            let index = expected
516                .iter()
517                .position(|i| *i == value.as_str())
518                .expect("Element found in expected array");
519            assert_eq!(expected[index], value);
520        }
521    }
522}