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