bevy_reflect/enums/
dynamic_enum.rs

1use bevy_reflect_derive::impl_type_path;
2
3use crate::{
4    self as bevy_reflect, enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct,
5    DynamicTuple, Enum, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
6    TypeInfo, VariantFieldIter, VariantType,
7};
8use std::any::Any;
9use std::fmt::Formatter;
10
11/// A dynamic representation of an enum variant.
12#[derive(Debug, Default)]
13pub enum DynamicVariant {
14    #[default]
15    Unit,
16    Tuple(DynamicTuple),
17    Struct(DynamicStruct),
18}
19
20impl Clone for DynamicVariant {
21    fn clone(&self) -> Self {
22        match self {
23            DynamicVariant::Unit => DynamicVariant::Unit,
24            DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.clone_dynamic()),
25            DynamicVariant::Struct(data) => DynamicVariant::Struct(data.clone_dynamic()),
26        }
27    }
28}
29
30impl From<DynamicTuple> for DynamicVariant {
31    fn from(dyn_tuple: DynamicTuple) -> Self {
32        Self::Tuple(dyn_tuple)
33    }
34}
35
36impl From<DynamicStruct> for DynamicVariant {
37    fn from(dyn_struct: DynamicStruct) -> Self {
38        Self::Struct(dyn_struct)
39    }
40}
41
42impl From<()> for DynamicVariant {
43    fn from(_: ()) -> Self {
44        Self::Unit
45    }
46}
47
48/// A dynamic representation of an enum.
49///
50/// This allows for enums to be configured at runtime.
51///
52/// # Example
53///
54/// ```
55/// # use bevy_reflect::{DynamicEnum, DynamicVariant, Reflect};
56///
57/// // The original enum value
58/// let mut value: Option<usize> = Some(123);
59///
60/// // Create a DynamicEnum to represent the new value
61/// let mut dyn_enum = DynamicEnum::new(
62///   "None",
63///   DynamicVariant::Unit
64/// );
65///
66/// // Apply the DynamicEnum as a patch to the original value
67/// value.apply(&dyn_enum);
68///
69/// // Tada!
70/// assert_eq!(None, value);
71/// ```
72#[derive(Default, Debug)]
73pub struct DynamicEnum {
74    represented_type: Option<&'static TypeInfo>,
75    variant_name: String,
76    variant_index: usize,
77    variant: DynamicVariant,
78}
79
80impl DynamicEnum {
81    /// Create a new [`DynamicEnum`] to represent an enum at runtime.
82    ///
83    /// # Arguments
84    ///
85    /// * `variant_name`: The name of the variant to set
86    /// * `variant`: The variant data
87    ///
88    pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
89        Self {
90            represented_type: None,
91            variant_index: 0,
92            variant_name: variant_name.into(),
93            variant: variant.into(),
94        }
95    }
96
97    /// Create a new [`DynamicEnum`] with a variant index to represent an enum at runtime.
98    ///
99    /// # Arguments
100    ///
101    /// * `variant_index`: The index of the variant to set
102    /// * `variant_name`: The name of the variant to set
103    /// * `variant`: The variant data
104    ///
105    pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
106        variant_index: usize,
107        variant_name: I,
108        variant: V,
109    ) -> Self {
110        Self {
111            represented_type: None,
112            variant_index,
113            variant_name: variant_name.into(),
114            variant: variant.into(),
115        }
116    }
117
118    /// Sets the [type] to be represented by this `DynamicEnum`.
119    ///
120    /// # Panics
121    ///
122    /// Panics if the given [type] is not a [`TypeInfo::Enum`].
123    ///
124    /// [type]: TypeInfo
125    pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
126        if let Some(represented_type) = represented_type {
127            assert!(
128                matches!(represented_type, TypeInfo::Enum(_)),
129                "expected TypeInfo::Enum but received: {:?}",
130                represented_type
131            );
132        }
133
134        self.represented_type = represented_type;
135    }
136
137    /// Set the current enum variant represented by this struct.
138    pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
139        self.variant_name = name.into();
140        self.variant = variant.into();
141    }
142
143    /// Set the current enum variant represented by this struct along with its variant index.
144    pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
145        &mut self,
146        variant_index: usize,
147        variant_name: I,
148        variant: V,
149    ) {
150        self.variant_index = variant_index;
151        self.variant_name = variant_name.into();
152        self.variant = variant.into();
153    }
154
155    /// Create a [`DynamicEnum`] from an existing one.
156    ///
157    /// This is functionally the same as [`DynamicEnum::from_ref`] except it takes an owned value.
158    pub fn from<TEnum: Enum>(value: TEnum) -> Self {
159        Self::from_ref(&value)
160    }
161
162    /// Create a [`DynamicEnum`] from an existing one.
163    ///
164    /// This is functionally the same as [`DynamicEnum::from`] except it takes a reference.
165    pub fn from_ref<TEnum: Enum>(value: &TEnum) -> Self {
166        let type_info = value.get_represented_type_info();
167        let mut dyn_enum = match value.variant_type() {
168            VariantType::Unit => DynamicEnum::new_with_index(
169                value.variant_index(),
170                value.variant_name(),
171                DynamicVariant::Unit,
172            ),
173            VariantType::Tuple => {
174                let mut data = DynamicTuple::default();
175                for field in value.iter_fields() {
176                    data.insert_boxed(field.value().clone_value());
177                }
178                DynamicEnum::new_with_index(
179                    value.variant_index(),
180                    value.variant_name(),
181                    DynamicVariant::Tuple(data),
182                )
183            }
184            VariantType::Struct => {
185                let mut data = DynamicStruct::default();
186                for field in value.iter_fields() {
187                    let name = field.name().unwrap();
188                    data.insert_boxed(name, field.value().clone_value());
189                }
190                DynamicEnum::new_with_index(
191                    value.variant_index(),
192                    value.variant_name(),
193                    DynamicVariant::Struct(data),
194                )
195            }
196        };
197
198        dyn_enum.set_represented_type(type_info);
199        dyn_enum
200    }
201}
202
203impl Enum for DynamicEnum {
204    fn field(&self, name: &str) -> Option<&dyn Reflect> {
205        if let DynamicVariant::Struct(data) = &self.variant {
206            data.field(name)
207        } else {
208            None
209        }
210    }
211
212    fn field_at(&self, index: usize) -> Option<&dyn Reflect> {
213        if let DynamicVariant::Tuple(data) = &self.variant {
214            data.field(index)
215        } else {
216            None
217        }
218    }
219
220    fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
221        if let DynamicVariant::Struct(data) = &mut self.variant {
222            data.field_mut(name)
223        } else {
224            None
225        }
226    }
227
228    fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn Reflect> {
229        if let DynamicVariant::Tuple(data) = &mut self.variant {
230            data.field_mut(index)
231        } else {
232            None
233        }
234    }
235
236    fn index_of(&self, name: &str) -> Option<usize> {
237        if let DynamicVariant::Struct(data) = &self.variant {
238            data.index_of(name)
239        } else {
240            None
241        }
242    }
243
244    fn name_at(&self, index: usize) -> Option<&str> {
245        if let DynamicVariant::Struct(data) = &self.variant {
246            data.name_at(index)
247        } else {
248            None
249        }
250    }
251
252    fn iter_fields(&self) -> VariantFieldIter {
253        VariantFieldIter::new(self)
254    }
255
256    fn field_len(&self) -> usize {
257        match &self.variant {
258            DynamicVariant::Unit => 0,
259            DynamicVariant::Tuple(data) => data.field_len(),
260            DynamicVariant::Struct(data) => data.field_len(),
261        }
262    }
263
264    fn variant_name(&self) -> &str {
265        &self.variant_name
266    }
267
268    fn variant_index(&self) -> usize {
269        self.variant_index
270    }
271
272    fn variant_type(&self) -> VariantType {
273        match &self.variant {
274            DynamicVariant::Unit => VariantType::Unit,
275            DynamicVariant::Tuple(..) => VariantType::Tuple,
276            DynamicVariant::Struct(..) => VariantType::Struct,
277        }
278    }
279
280    fn clone_dynamic(&self) -> DynamicEnum {
281        Self {
282            represented_type: self.represented_type,
283            variant_index: self.variant_index,
284            variant_name: self.variant_name.clone(),
285            variant: self.variant.clone(),
286        }
287    }
288}
289
290impl Reflect for DynamicEnum {
291    #[inline]
292    fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
293        self.represented_type
294    }
295
296    #[inline]
297    fn into_any(self: Box<Self>) -> Box<dyn Any> {
298        self
299    }
300
301    #[inline]
302    fn as_any(&self) -> &dyn Any {
303        self
304    }
305
306    #[inline]
307    fn as_any_mut(&mut self) -> &mut dyn Any {
308        self
309    }
310
311    #[inline]
312    fn into_reflect(self: Box<Self>) -> Box<dyn Reflect> {
313        self
314    }
315
316    #[inline]
317    fn as_reflect(&self) -> &dyn Reflect {
318        self
319    }
320
321    #[inline]
322    fn as_reflect_mut(&mut self) -> &mut dyn Reflect {
323        self
324    }
325
326    #[inline]
327    fn try_apply(&mut self, value: &dyn Reflect) -> Result<(), ApplyError> {
328        if let ReflectRef::Enum(value) = value.reflect_ref() {
329            if Enum::variant_name(self) == value.variant_name() {
330                // Same variant -> just update fields
331                match value.variant_type() {
332                    VariantType::Struct => {
333                        for field in value.iter_fields() {
334                            let name = field.name().unwrap();
335                            if let Some(v) = Enum::field_mut(self, name) {
336                                v.try_apply(field.value())?;
337                            }
338                        }
339                    }
340                    VariantType::Tuple => {
341                        for (index, field) in value.iter_fields().enumerate() {
342                            if let Some(v) = Enum::field_at_mut(self, index) {
343                                v.try_apply(field.value())?;
344                            }
345                        }
346                    }
347                    _ => {}
348                }
349            } else {
350                // New variant -> perform a switch
351                let dyn_variant = match value.variant_type() {
352                    VariantType::Unit => DynamicVariant::Unit,
353                    VariantType::Tuple => {
354                        let mut dyn_tuple = DynamicTuple::default();
355                        for field in value.iter_fields() {
356                            dyn_tuple.insert_boxed(field.value().clone_value());
357                        }
358                        DynamicVariant::Tuple(dyn_tuple)
359                    }
360                    VariantType::Struct => {
361                        let mut dyn_struct = DynamicStruct::default();
362                        for field in value.iter_fields() {
363                            dyn_struct
364                                .insert_boxed(field.name().unwrap(), field.value().clone_value());
365                        }
366                        DynamicVariant::Struct(dyn_struct)
367                    }
368                };
369                self.set_variant(value.variant_name(), dyn_variant);
370            }
371        } else {
372            return Err(ApplyError::MismatchedKinds {
373                from_kind: value.reflect_kind(),
374                to_kind: ReflectKind::Enum,
375            });
376        }
377        Ok(())
378    }
379
380    #[inline]
381    fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>> {
382        *self = value.take()?;
383        Ok(())
384    }
385
386    #[inline]
387    fn reflect_kind(&self) -> ReflectKind {
388        ReflectKind::Enum
389    }
390
391    #[inline]
392    fn reflect_ref(&self) -> ReflectRef {
393        ReflectRef::Enum(self)
394    }
395
396    #[inline]
397    fn reflect_mut(&mut self) -> ReflectMut {
398        ReflectMut::Enum(self)
399    }
400
401    #[inline]
402    fn reflect_owned(self: Box<Self>) -> ReflectOwned {
403        ReflectOwned::Enum(self)
404    }
405
406    #[inline]
407    fn clone_value(&self) -> Box<dyn Reflect> {
408        Box::new(self.clone_dynamic())
409    }
410
411    #[inline]
412    fn reflect_hash(&self) -> Option<u64> {
413        enum_hash(self)
414    }
415
416    #[inline]
417    fn reflect_partial_eq(&self, value: &dyn Reflect) -> Option<bool> {
418        enum_partial_eq(self, value)
419    }
420
421    #[inline]
422    fn debug(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
423        write!(f, "DynamicEnum(")?;
424        enum_debug(self, f)?;
425        write!(f, ")")
426    }
427
428    #[inline]
429    fn is_dynamic(&self) -> bool {
430        true
431    }
432}
433
434impl_type_path!((in bevy_reflect) DynamicEnum);