bevy_reflect/enums/
helpers.rs

1use crate::{utility::reflect_hasher, Enum, Reflect, ReflectRef, VariantType};
2use std::fmt::Debug;
3use std::hash::{Hash, Hasher};
4
5/// Returns the `u64` hash of the given [enum](Enum).
6#[inline]
7pub fn enum_hash<TEnum: Enum>(value: &TEnum) -> Option<u64> {
8    let mut hasher = reflect_hasher();
9    std::any::Any::type_id(value).hash(&mut hasher);
10    value.variant_name().hash(&mut hasher);
11    value.variant_type().hash(&mut hasher);
12    for field in value.iter_fields() {
13        hasher.write_u64(field.value().reflect_hash()?);
14    }
15    Some(hasher.finish())
16}
17
18/// Compares an [`Enum`] with a [`Reflect`] value.
19///
20/// Returns true if and only if all of the following are true:
21/// - `b` is an enum;
22/// - `b` is the same variant as `a`;
23/// - For each field in `a`, `b` contains a field with the same name and
24///   [`Reflect::reflect_partial_eq`] returns `Some(true)` for the two field
25///   values.
26#[inline]
27pub fn enum_partial_eq<TEnum: Enum>(a: &TEnum, b: &dyn Reflect) -> Option<bool> {
28    // Both enums?
29    let ReflectRef::Enum(b) = b.reflect_ref() else {
30        return Some(false);
31    };
32
33    // Same variant name?
34    if a.variant_name() != b.variant_name() {
35        return Some(false);
36    }
37
38    // Same variant type?
39    if !a.is_variant(b.variant_type()) {
40        return Some(false);
41    }
42
43    match a.variant_type() {
44        VariantType::Struct => {
45            // Same struct fields?
46            for field in a.iter_fields() {
47                let field_name = field.name().unwrap();
48                if let Some(field_value) = b.field(field_name) {
49                    if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
50                        // Fields failed comparison
51                        return Some(false);
52                    }
53                } else {
54                    // Field does not exist
55                    return Some(false);
56                }
57            }
58            Some(true)
59        }
60        VariantType::Tuple => {
61            // Same tuple fields?
62            for (i, field) in a.iter_fields().enumerate() {
63                if let Some(field_value) = b.field_at(i) {
64                    if let Some(false) | None = field_value.reflect_partial_eq(field.value()) {
65                        // Fields failed comparison
66                        return Some(false);
67                    }
68                } else {
69                    // Field does not exist
70                    return Some(false);
71                }
72            }
73            Some(true)
74        }
75        _ => Some(true),
76    }
77}
78
79/// The default debug formatter for [`Enum`] types.
80///
81/// # Example
82/// ```
83/// use bevy_reflect::Reflect;
84/// #[derive(Reflect)]
85/// enum MyEnum {
86///   A,
87///   B (usize),
88///   C {value: i32}
89/// }
90///
91/// let my_enum: &dyn Reflect = &MyEnum::B(123);
92/// println!("{:#?}", my_enum);
93///
94/// // Output:
95///
96/// // B (
97/// //   123,
98/// // )
99/// ```
100#[inline]
101pub fn enum_debug(dyn_enum: &dyn Enum, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102    match dyn_enum.variant_type() {
103        VariantType::Unit => f.write_str(dyn_enum.variant_name()),
104        VariantType::Tuple => {
105            let mut debug = f.debug_tuple(dyn_enum.variant_name());
106            for field in dyn_enum.iter_fields() {
107                debug.field(&field.value() as &dyn Debug);
108            }
109            debug.finish()
110        }
111        VariantType::Struct => {
112            let mut debug = f.debug_struct(dyn_enum.variant_name());
113            for field in dyn_enum.iter_fields() {
114                debug.field(field.name().unwrap(), &field.value() as &dyn Debug);
115            }
116            debug.finish()
117        }
118    }
119}