bevy_reflect/enums/
enum_trait.rs

1use crate::attributes::{impl_custom_attribute_methods, CustomAttributes};
2use crate::{DynamicEnum, Reflect, TypePath, TypePathTable, VariantInfo, VariantType};
3use bevy_utils::HashMap;
4use std::any::{Any, TypeId};
5use std::slice::Iter;
6use std::sync::Arc;
7
8/// A trait used to power [enum-like] operations via [reflection].
9///
10/// This allows enums to be processed and modified dynamically at runtime without
11/// necessarily knowing the actual type.
12/// Enums are much more complex than their struct counterparts.
13/// As a result, users will need to be mindful of conventions, considerations,
14/// and complications when working with this trait.
15///
16/// # Variants
17///
18/// An enum is a set of choices called _variants_.
19/// An instance of an enum can only exist as one of these choices at any given time.
20/// Consider Rust's [`Option<T>`]. It's an enum with two variants: [`None`] and [`Some`].
21/// If you're `None`, you can't be `Some` and vice versa.
22///
23/// > ⚠️ __This is very important:__
24/// > The [`Enum`] trait represents an enum _as one of its variants_.
25/// > It does not represent the entire enum since that's not true to how enums work.
26///
27/// Variants come in a few [flavors](VariantType):
28///
29/// | Variant Type | Syntax                         |
30/// | ------------ | ------------------------------ |
31/// | Unit         | `MyEnum::Foo`                  |
32/// | Tuple        | `MyEnum::Foo( i32, i32 )`      |
33/// | Struct       | `MyEnum::Foo{ value: String }` |
34///
35/// As you can see, a unit variant contains no fields, while tuple and struct variants
36/// can contain one or more fields.
37/// The fields in a tuple variant is defined by their _order_ within the variant.
38/// Index `0` represents the first field in the variant and so on.
39/// Fields in struct variants (excluding tuple structs), on the other hand, are
40/// represented by a _name_.
41///
42/// # Implementation
43///
44/// > 💡 This trait can be automatically implemented using [`#[derive(Reflect)]`](derive@crate::Reflect)
45/// > on an enum definition.
46///
47/// Despite the fact that enums can represent multiple states, traits only exist in one state
48/// and must be applied to the entire enum rather than a particular variant.
49/// Because of this limitation, the [`Enum`] trait must not only _represent_ any of the
50/// three variant types, but also define the _methods_ for all three as well.
51///
52/// What does this mean? It means that even though a unit variant contains no fields, a
53/// representation of that variant using the [`Enum`] trait will still contain methods for
54/// accessing fields!
55/// Again, this is to account for _all three_ variant types.
56///
57/// We recommend using the built-in [`#[derive(Reflect)]`](derive@crate::Reflect) macro to automatically handle all the
58/// implementation details for you.
59/// However, if you _must_ implement this trait manually, there are a few things to keep in mind...
60///
61/// ## Field Order
62///
63/// While tuple variants identify their fields by the order in which they are defined, struct
64/// variants identify fields by their name.
65/// However, both should allow access to fields by their defined order.
66///
67/// The reason all fields, regardless of variant type, need to be accessible by their order is
68/// due to field iteration.
69/// We need a way to iterate through each field in a variant, and the easiest way of achieving
70/// that is through the use of field order.
71///
72/// The derive macro adds proper struct variant handling for [`Enum::index_of`], [`Enum::name_at`]
73/// and [`Enum::field_at[_mut]`](Enum::field_at) methods.
74/// The first two methods are __required__ for all struct variant types.
75/// By convention, implementors should also handle the last method as well, but this is not
76/// a strict requirement.
77///
78/// ## Field Names
79///
80/// Implementors may choose to handle [`Enum::index_of`], [`Enum::name_at`], and
81/// [`Enum::field[_mut]`](Enum::field) for tuple variants by considering stringified `usize`s to be
82/// valid names (such as `"3"`).
83/// This isn't wrong to do, but the convention set by the derive macro is that it isn't supported.
84/// It's preferred that these strings be converted to their proper `usize` representations and
85/// the [`Enum::field_at[_mut]`](Enum::field_at) methods be used instead.
86///
87/// [enum-like]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html
88/// [reflection]: crate
89/// [`None`]: Option<T>::None
90/// [`Some`]: Option<T>::Some
91/// [`Reflect`]: bevy_reflect_derive::Reflect
92pub trait Enum: Reflect {
93    /// Returns a reference to the value of the field (in the current variant) with the given name.
94    ///
95    /// For non-[`VariantType::Struct`] variants, this should return `None`.
96    fn field(&self, name: &str) -> Option<&dyn Reflect>;
97    /// Returns a reference to the value of the field (in the current variant) at the given index.
98    fn field_at(&self, index: usize) -> Option<&dyn Reflect>;
99    /// Returns a mutable reference to the value of the field (in the current variant) with the given name.
100    ///
101    /// For non-[`VariantType::Struct`] variants, this should return `None`.
102    fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect>;
103    /// Returns a mutable reference to the value of the field (in the current variant) at the given index.
104    fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect>;
105    /// Returns the index of the field (in the current variant) with the given name.
106    ///
107    /// For non-[`VariantType::Struct`] variants, this should return `None`.
108    fn index_of(&self, name: &str) -> Option<usize>;
109    /// Returns the name of the field (in the current variant) with the given index.
110    ///
111    /// For non-[`VariantType::Struct`] variants, this should return `None`.
112    fn name_at(&self, index: usize) -> Option<&str>;
113    /// Returns an iterator over the values of the current variant's fields.
114    fn iter_fields(&self) -> VariantFieldIter;
115    /// Returns the number of fields in the current variant.
116    fn field_len(&self) -> usize;
117    /// The name of the current variant.
118    fn variant_name(&self) -> &str;
119    /// The index of the current variant.
120    fn variant_index(&self) -> usize;
121    /// The type of the current variant.
122    fn variant_type(&self) -> VariantType;
123    // Clones the enum into a [`DynamicEnum`].
124    fn clone_dynamic(&self) -> DynamicEnum;
125    /// Returns true if the current variant's type matches the given one.
126    fn is_variant(&self, variant_type: VariantType) -> bool {
127        self.variant_type() == variant_type
128    }
129    /// Returns the full path to the current variant.
130    fn variant_path(&self) -> String {
131        format!("{}::{}", self.reflect_type_path(), self.variant_name())
132    }
133}
134
135/// A container for compile-time enum info, used by [`TypeInfo`](crate::TypeInfo).
136#[derive(Clone, Debug)]
137pub struct EnumInfo {
138    type_path: TypePathTable,
139    type_id: TypeId,
140    variants: Box<[VariantInfo]>,
141    variant_names: Box<[&'static str]>,
142    variant_indices: HashMap<&'static str, usize>,
143    custom_attributes: Arc<CustomAttributes>,
144    #[cfg(feature = "documentation")]
145    docs: Option<&'static str>,
146}
147
148impl EnumInfo {
149    /// Create a new [`EnumInfo`].
150    ///
151    /// # Arguments
152    ///
153    /// * `variants`: The variants of this enum in the order they are defined
154    ///
155    pub fn new<TEnum: Enum + TypePath>(variants: &[VariantInfo]) -> Self {
156        let variant_indices = variants
157            .iter()
158            .enumerate()
159            .map(|(index, variant)| (variant.name(), index))
160            .collect::<HashMap<_, _>>();
161
162        let variant_names = variants.iter().map(|variant| variant.name()).collect();
163
164        Self {
165            type_path: TypePathTable::of::<TEnum>(),
166            type_id: TypeId::of::<TEnum>(),
167            variants: variants.to_vec().into_boxed_slice(),
168            variant_names,
169            variant_indices,
170            custom_attributes: Arc::new(CustomAttributes::default()),
171            #[cfg(feature = "documentation")]
172            docs: None,
173        }
174    }
175
176    /// Sets the docstring for this enum.
177    #[cfg(feature = "documentation")]
178    pub fn with_docs(self, docs: Option<&'static str>) -> Self {
179        Self { docs, ..self }
180    }
181
182    /// Sets the custom attributes for this enum.
183    pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
184        Self {
185            custom_attributes: Arc::new(custom_attributes),
186            ..self
187        }
188    }
189
190    /// A slice containing the names of all variants in order.
191    pub fn variant_names(&self) -> &[&'static str] {
192        &self.variant_names
193    }
194
195    /// Get a variant with the given name.
196    pub fn variant(&self, name: &str) -> Option<&VariantInfo> {
197        self.variant_indices
198            .get(name)
199            .map(|index| &self.variants[*index])
200    }
201
202    /// Get a variant at the given index.
203    pub fn variant_at(&self, index: usize) -> Option<&VariantInfo> {
204        self.variants.get(index)
205    }
206
207    /// Get the index of the variant with the given name.
208    pub fn index_of(&self, name: &str) -> Option<usize> {
209        self.variant_indices.get(name).copied()
210    }
211
212    /// Returns the full path to the given variant.
213    ///
214    /// This does _not_ check if the given variant exists.
215    pub fn variant_path(&self, name: &str) -> String {
216        format!("{}::{name}", self.type_path())
217    }
218
219    /// Checks if a variant with the given name exists within this enum.
220    pub fn contains_variant(&self, name: &str) -> bool {
221        self.variant_indices.contains_key(name)
222    }
223
224    /// Iterate over the variants of this enum.
225    pub fn iter(&self) -> Iter<'_, VariantInfo> {
226        self.variants.iter()
227    }
228
229    /// The number of variants in this enum.
230    pub fn variant_len(&self) -> usize {
231        self.variants.len()
232    }
233
234    /// A representation of the type path of the value.
235    ///
236    /// Provides dynamic access to all methods on [`TypePath`].
237    pub fn type_path_table(&self) -> &TypePathTable {
238        &self.type_path
239    }
240
241    /// The [stable, full type path] of the value.
242    ///
243    /// Use [`type_path_table`] if you need access to the other methods on [`TypePath`].
244    ///
245    /// [stable, full type path]: TypePath
246    /// [`type_path_table`]: Self::type_path_table
247    pub fn type_path(&self) -> &'static str {
248        self.type_path_table().path()
249    }
250
251    /// The [`TypeId`] of the enum.
252    pub fn type_id(&self) -> TypeId {
253        self.type_id
254    }
255
256    /// Check if the given type matches the enum type.
257    pub fn is<T: Any>(&self) -> bool {
258        TypeId::of::<T>() == self.type_id
259    }
260
261    /// The docstring of this enum, if any.
262    #[cfg(feature = "documentation")]
263    pub fn docs(&self) -> Option<&'static str> {
264        self.docs
265    }
266
267    impl_custom_attribute_methods!(self.custom_attributes, "enum");
268}
269
270/// An iterator over the fields in the current enum variant.
271pub struct VariantFieldIter<'a> {
272    container: &'a dyn Enum,
273    index: usize,
274}
275
276impl<'a> VariantFieldIter<'a> {
277    pub fn new(container: &'a dyn Enum) -> Self {
278        Self {
279            container,
280            index: 0,
281        }
282    }
283}
284
285impl<'a> Iterator for VariantFieldIter<'a> {
286    type Item = VariantField<'a>;
287
288    fn next(&mut self) -> Option<Self::Item> {
289        let value = match self.container.variant_type() {
290            VariantType::Unit => None,
291            VariantType::Tuple => Some(VariantField::Tuple(self.container.field_at(self.index)?)),
292            VariantType::Struct => {
293                let name = self.container.name_at(self.index)?;
294                Some(VariantField::Struct(name, self.container.field(name)?))
295            }
296        };
297        self.index += value.is_some() as usize;
298        value
299    }
300
301    fn size_hint(&self) -> (usize, Option<usize>) {
302        let size = self.container.field_len();
303        (size, Some(size))
304    }
305}
306
307impl<'a> ExactSizeIterator for VariantFieldIter<'a> {}
308
309pub enum VariantField<'a> {
310    Struct(&'a str, &'a dyn Reflect),
311    Tuple(&'a dyn Reflect),
312}
313
314impl<'a> VariantField<'a> {
315    pub fn name(&self) -> Option<&'a str> {
316        if let Self::Struct(name, ..) = self {
317            Some(*name)
318        } else {
319            None
320        }
321    }
322
323    pub fn value(&self) -> &'a dyn Reflect {
324        match *self {
325            Self::Struct(_, value) | Self::Tuple(value) => value,
326        }
327    }
328}
329
330// Tests that need access to internal fields have to go here rather than in mod.rs
331#[cfg(test)]
332mod tests {
333    use crate as bevy_reflect;
334    use crate::*;
335
336    #[derive(Reflect, Debug, PartialEq)]
337    enum MyEnum {
338        A,
339        B(usize, i32),
340        C { foo: f32, bar: bool },
341    }
342    #[test]
343    fn next_index_increment() {
344        // unit enums always return none, so index should stay at 0
345        let unit_enum = MyEnum::A;
346        let mut iter = unit_enum.iter_fields();
347        let size = iter.len();
348        for _ in 0..2 {
349            assert!(iter.next().is_none());
350            assert_eq!(size, iter.index);
351        }
352        // tuple enums we iter over each value (unnamed fields), stop after that
353        let tuple_enum = MyEnum::B(0, 1);
354        let mut iter = tuple_enum.iter_fields();
355        let size = iter.len();
356        for _ in 0..2 {
357            let prev_index = iter.index;
358            assert!(iter.next().is_some());
359            assert_eq!(prev_index, iter.index - 1);
360        }
361        for _ in 0..2 {
362            assert!(iter.next().is_none());
363            assert_eq!(size, iter.index);
364        }
365
366        // struct enums, we iterate over each field in the struct
367        let struct_enum = MyEnum::C {
368            foo: 0.,
369            bar: false,
370        };
371        let mut iter = struct_enum.iter_fields();
372        let size = iter.len();
373        for _ in 0..2 {
374            let prev_index = iter.index;
375            assert!(iter.next().is_some());
376            assert_eq!(prev_index, iter.index - 1);
377        }
378        for _ in 0..2 {
379            assert!(iter.next().is_none());
380            assert_eq!(size, iter.index);
381        }
382    }
383}