bevy_reflect/enums/
helpers.rs

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