1use bevy_reflect_derive::impl_type_path;
2
3use crate::{
4 enums::{
5 enum_debug, enum_hash, enum_partial_cmp, enum_partial_eq, Enum, VariantFieldIter,
6 VariantType,
7 },
8 structs::{DynamicStruct, Struct},
9 tuple::{DynamicTuple, Tuple},
10 ApplyError, PartialReflect, Reflect, ReflectCloneError, ReflectKind, ReflectMut, ReflectOwned,
11 ReflectRef, TypeInfo,
12};
13
14use alloc::{boxed::Box, string::String};
15use core::fmt::Formatter;
16use derive_more::derive::From;
17
18#[derive(Debug, Default, From)]
20pub enum DynamicVariant {
21 #[default]
23 Unit,
24 Tuple(DynamicTuple),
26 Struct(DynamicStruct),
28}
29
30impl Clone for DynamicVariant {
36 fn clone(&self) -> Self {
37 match self {
38 DynamicVariant::Unit => DynamicVariant::Unit,
39 DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.to_dynamic_tuple().unwrap()),
40 DynamicVariant::Struct(data) => {
41 DynamicVariant::Struct(data.to_dynamic_struct().unwrap())
42 }
43 }
44 }
45}
46
47impl From<()> for DynamicVariant {
48 fn from(_: ()) -> Self {
49 Self::Unit
50 }
51}
52
53#[derive(Default, Debug)]
78pub struct DynamicEnum {
79 represented_type: Option<&'static TypeInfo>,
80 variant_name: String,
81 variant_index: usize,
82 variant: DynamicVariant,
83}
84
85impl DynamicEnum {
86 pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
93 Self {
94 represented_type: None,
95 variant_index: 0,
96 variant_name: variant_name.into(),
97 variant: variant.into(),
98 }
99 }
100
101 pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
109 variant_index: usize,
110 variant_name: I,
111 variant: V,
112 ) -> Self {
113 Self {
114 represented_type: None,
115 variant_index,
116 variant_name: variant_name.into(),
117 variant: variant.into(),
118 }
119 }
120
121 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
129 if let Some(represented_type) = represented_type {
130 assert!(
131 matches!(represented_type, TypeInfo::Enum(_)),
132 "expected TypeInfo::Enum but received: {represented_type:?}",
133 );
134 }
135
136 self.represented_type = represented_type;
137 }
138
139 pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
141 self.variant_name = name.into();
142 self.variant = variant.into();
143 }
144
145 pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
147 &mut self,
148 variant_index: usize,
149 variant_name: I,
150 variant: V,
151 ) {
152 self.variant_index = variant_index;
153 self.variant_name = variant_name.into();
154 self.variant = variant.into();
155 }
156
157 pub fn variant(&self) -> &DynamicVariant {
159 &self.variant
160 }
161
162 pub fn variant_mut(&mut self) -> &mut DynamicVariant {
170 &mut self.variant
171 }
172
173 #[deprecated(
177 since = "0.20.0",
178 note = "Use `DynamicEnum::try_from` instead, which returns a Result."
179 )]
180 pub fn from<TEnum: Enum>(value: TEnum) -> Self {
181 Self::try_from(value).unwrap()
182 }
183
184 pub fn try_from<TEnum: Enum>(value: TEnum) -> Result<Self, ReflectCloneError> {
191 Self::try_from_ref(&value)
192 }
193
194 #[deprecated(
198 since = "0.20.0",
199 note = "Use `DynamicEnum::try_from_ref` instead, which returns a Result."
200 )]
201 pub fn from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Self {
202 Self::try_from_ref(value).unwrap()
203 }
204
205 pub fn try_from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Result<Self, ReflectCloneError> {
212 let type_info = value.get_represented_type_info();
213 let mut dyn_enum = match value.variant_type() {
214 VariantType::Unit => DynamicEnum::new_with_index(
215 value.variant_index(),
216 value.variant_name(),
217 DynamicVariant::Unit,
218 ),
219 VariantType::Tuple => {
220 let mut data = DynamicTuple::default();
221 for field in value.iter_fields() {
222 data.insert_boxed(field.value().to_dynamic()?);
223 }
224 DynamicEnum::new_with_index(
225 value.variant_index(),
226 value.variant_name(),
227 DynamicVariant::Tuple(data),
228 )
229 }
230 VariantType::Struct => {
231 let mut data = DynamicStruct::default();
232 for field in value.iter_fields() {
233 let name = field.name().unwrap();
234 data.insert_boxed(name, field.value().to_dynamic()?);
235 }
236 DynamicEnum::new_with_index(
237 value.variant_index(),
238 value.variant_name(),
239 DynamicVariant::Struct(data),
240 )
241 }
242 };
243
244 dyn_enum.set_represented_type(type_info);
245 Ok(dyn_enum)
246 }
247}
248
249impl Enum for DynamicEnum {
250 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
251 if let DynamicVariant::Struct(data) = &self.variant {
252 data.field(name)
253 } else {
254 None
255 }
256 }
257
258 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
259 match &self.variant {
260 DynamicVariant::Tuple(data) => data.field(index),
261 DynamicVariant::Struct(data) => data.field_at(index),
262 DynamicVariant::Unit => None,
263 }
264 }
265
266 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
267 if let DynamicVariant::Struct(data) = &mut self.variant {
268 data.field_mut(name)
269 } else {
270 None
271 }
272 }
273
274 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
275 match &mut self.variant {
276 DynamicVariant::Tuple(data) => data.field_mut(index),
277 DynamicVariant::Struct(data) => data.field_at_mut(index),
278 DynamicVariant::Unit => None,
279 }
280 }
281
282 fn index_of(&self, name: &str) -> Option<usize> {
283 if let DynamicVariant::Struct(data) = &self.variant {
284 data.index_of_name(name)
285 } else {
286 None
287 }
288 }
289
290 fn name_at(&self, index: usize) -> Option<&str> {
291 if let DynamicVariant::Struct(data) = &self.variant {
292 data.name_at(index)
293 } else {
294 None
295 }
296 }
297
298 fn iter_fields(&self) -> VariantFieldIter<'_> {
299 VariantFieldIter::new(self)
300 }
301
302 fn field_len(&self) -> usize {
303 match &self.variant {
304 DynamicVariant::Unit => 0,
305 DynamicVariant::Tuple(data) => data.field_len(),
306 DynamicVariant::Struct(data) => data.field_len(),
307 }
308 }
309
310 fn variant_name(&self) -> &str {
311 &self.variant_name
312 }
313
314 fn variant_index(&self) -> usize {
315 self.variant_index
316 }
317
318 fn variant_type(&self) -> VariantType {
319 match &self.variant {
320 DynamicVariant::Unit => VariantType::Unit,
321 DynamicVariant::Tuple(..) => VariantType::Tuple,
322 DynamicVariant::Struct(..) => VariantType::Struct,
323 }
324 }
325}
326
327impl PartialReflect for DynamicEnum {
328 #[inline]
329 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
330 self.represented_type
331 }
332
333 #[inline]
334 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
335 self
336 }
337
338 #[inline]
339 fn as_partial_reflect(&self) -> &dyn PartialReflect {
340 self
341 }
342
343 #[inline]
344 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
345 self
346 }
347
348 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
349 Err(self)
350 }
351
352 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
353 None
354 }
355
356 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
357 None
358 }
359
360 #[inline]
361 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
362 let value = value.reflect_ref().as_enum()?;
363
364 if Enum::variant_name(self) == value.variant_name() {
365 match value.variant_type() {
367 VariantType::Struct => {
368 for field in value.iter_fields() {
369 let name = field.name().unwrap();
370 if let Some(v) = Enum::field_mut(self, name) {
371 v.try_apply(field.value())?;
372 }
373 }
374 }
375 VariantType::Tuple => {
376 for (index, field) in value.iter_fields().enumerate() {
377 if let Some(v) = Enum::field_at_mut(self, index) {
378 v.try_apply(field.value())?;
379 }
380 }
381 }
382 _ => {}
383 }
384 } else {
385 let dyn_variant = match value.variant_type() {
387 VariantType::Unit => DynamicVariant::Unit,
388 VariantType::Tuple => {
389 let mut dyn_tuple = DynamicTuple::default();
390 for field in value.iter_fields() {
391 dyn_tuple.insert_boxed(field.value().to_dynamic()?);
392 }
393 DynamicVariant::Tuple(dyn_tuple)
394 }
395 VariantType::Struct => {
396 let mut dyn_struct = DynamicStruct::default();
397 for field in value.iter_fields() {
398 dyn_struct.insert_boxed(field.name().unwrap(), field.value().to_dynamic()?);
399 }
400 DynamicVariant::Struct(dyn_struct)
401 }
402 };
403 self.set_variant(value.variant_name(), dyn_variant);
404 }
405
406 Ok(())
407 }
408
409 #[inline]
410 fn reflect_kind(&self) -> ReflectKind {
411 ReflectKind::Enum
412 }
413
414 #[inline]
415 fn reflect_ref(&self) -> ReflectRef<'_> {
416 ReflectRef::Enum(self)
417 }
418
419 #[inline]
420 fn reflect_mut(&mut self) -> ReflectMut<'_> {
421 ReflectMut::Enum(self)
422 }
423
424 #[inline]
425 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
426 ReflectOwned::Enum(self)
427 }
428
429 #[inline]
430 fn reflect_hash(&self) -> Option<u64> {
431 enum_hash(self)
432 }
433
434 #[inline]
435 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
436 enum_partial_eq(self, value)
437 }
438
439 #[inline]
440 fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
441 enum_partial_cmp(self, value)
442 }
443
444 #[inline]
445 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
446 write!(f, "DynamicEnum(")?;
447 enum_debug(self, f)?;
448 write!(f, ")")
449 }
450
451 #[inline]
452 fn is_dynamic(&self) -> bool {
453 true
454 }
455}
456
457impl_type_path!((in bevy_reflect) DynamicEnum);