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, ReflectKind, ReflectMut, ReflectOwned, ReflectRef,
11 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 {
31 fn clone(&self) -> Self {
32 match self {
33 DynamicVariant::Unit => DynamicVariant::Unit,
34 DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.to_dynamic_tuple()),
35 DynamicVariant::Struct(data) => DynamicVariant::Struct(data.to_dynamic_struct()),
36 }
37 }
38}
39
40impl From<()> for DynamicVariant {
41 fn from(_: ()) -> Self {
42 Self::Unit
43 }
44}
45
46#[derive(Default, Debug)]
71pub struct DynamicEnum {
72 represented_type: Option<&'static TypeInfo>,
73 variant_name: String,
74 variant_index: usize,
75 variant: DynamicVariant,
76}
77
78impl DynamicEnum {
79 pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
86 Self {
87 represented_type: None,
88 variant_index: 0,
89 variant_name: variant_name.into(),
90 variant: variant.into(),
91 }
92 }
93
94 pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
102 variant_index: usize,
103 variant_name: I,
104 variant: V,
105 ) -> Self {
106 Self {
107 represented_type: None,
108 variant_index,
109 variant_name: variant_name.into(),
110 variant: variant.into(),
111 }
112 }
113
114 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
122 if let Some(represented_type) = represented_type {
123 assert!(
124 matches!(represented_type, TypeInfo::Enum(_)),
125 "expected TypeInfo::Enum but received: {represented_type:?}",
126 );
127 }
128
129 self.represented_type = represented_type;
130 }
131
132 pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
134 self.variant_name = name.into();
135 self.variant = variant.into();
136 }
137
138 pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
140 &mut self,
141 variant_index: usize,
142 variant_name: I,
143 variant: V,
144 ) {
145 self.variant_index = variant_index;
146 self.variant_name = variant_name.into();
147 self.variant = variant.into();
148 }
149
150 pub fn variant(&self) -> &DynamicVariant {
152 &self.variant
153 }
154
155 pub fn variant_mut(&mut self) -> &mut DynamicVariant {
163 &mut self.variant
164 }
165
166 pub fn from<TEnum: Enum>(value: TEnum) -> Self {
170 Self::from_ref(&value)
171 }
172
173 pub fn from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Self {
177 let type_info = value.get_represented_type_info();
178 let mut dyn_enum = match value.variant_type() {
179 VariantType::Unit => DynamicEnum::new_with_index(
180 value.variant_index(),
181 value.variant_name(),
182 DynamicVariant::Unit,
183 ),
184 VariantType::Tuple => {
185 let mut data = DynamicTuple::default();
186 for field in value.iter_fields() {
187 data.insert_boxed(field.value().to_dynamic());
188 }
189 DynamicEnum::new_with_index(
190 value.variant_index(),
191 value.variant_name(),
192 DynamicVariant::Tuple(data),
193 )
194 }
195 VariantType::Struct => {
196 let mut data = DynamicStruct::default();
197 for field in value.iter_fields() {
198 let name = field.name().unwrap();
199 data.insert_boxed(name, field.value().to_dynamic());
200 }
201 DynamicEnum::new_with_index(
202 value.variant_index(),
203 value.variant_name(),
204 DynamicVariant::Struct(data),
205 )
206 }
207 };
208
209 dyn_enum.set_represented_type(type_info);
210 dyn_enum
211 }
212}
213
214impl Enum for DynamicEnum {
215 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
216 if let DynamicVariant::Struct(data) = &self.variant {
217 data.field(name)
218 } else {
219 None
220 }
221 }
222
223 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
224 match &self.variant {
225 DynamicVariant::Tuple(data) => data.field(index),
226 DynamicVariant::Struct(data) => data.field_at(index),
227 DynamicVariant::Unit => None,
228 }
229 }
230
231 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
232 if let DynamicVariant::Struct(data) = &mut self.variant {
233 data.field_mut(name)
234 } else {
235 None
236 }
237 }
238
239 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
240 match &mut self.variant {
241 DynamicVariant::Tuple(data) => data.field_mut(index),
242 DynamicVariant::Struct(data) => data.field_at_mut(index),
243 DynamicVariant::Unit => None,
244 }
245 }
246
247 fn index_of(&self, name: &str) -> Option<usize> {
248 if let DynamicVariant::Struct(data) = &self.variant {
249 data.index_of_name(name)
250 } else {
251 None
252 }
253 }
254
255 fn name_at(&self, index: usize) -> Option<&str> {
256 if let DynamicVariant::Struct(data) = &self.variant {
257 data.name_at(index)
258 } else {
259 None
260 }
261 }
262
263 fn iter_fields(&self) -> VariantFieldIter<'_> {
264 VariantFieldIter::new(self)
265 }
266
267 fn field_len(&self) -> usize {
268 match &self.variant {
269 DynamicVariant::Unit => 0,
270 DynamicVariant::Tuple(data) => data.field_len(),
271 DynamicVariant::Struct(data) => data.field_len(),
272 }
273 }
274
275 fn variant_name(&self) -> &str {
276 &self.variant_name
277 }
278
279 fn variant_index(&self) -> usize {
280 self.variant_index
281 }
282
283 fn variant_type(&self) -> VariantType {
284 match &self.variant {
285 DynamicVariant::Unit => VariantType::Unit,
286 DynamicVariant::Tuple(..) => VariantType::Tuple,
287 DynamicVariant::Struct(..) => VariantType::Struct,
288 }
289 }
290}
291
292impl PartialReflect for DynamicEnum {
293 #[inline]
294 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
295 self.represented_type
296 }
297
298 #[inline]
299 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
300 self
301 }
302
303 #[inline]
304 fn as_partial_reflect(&self) -> &dyn PartialReflect {
305 self
306 }
307
308 #[inline]
309 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
310 self
311 }
312
313 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
314 Err(self)
315 }
316
317 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
318 None
319 }
320
321 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
322 None
323 }
324
325 #[inline]
326 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
327 let value = value.reflect_ref().as_enum()?;
328
329 if Enum::variant_name(self) == value.variant_name() {
330 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 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().to_dynamic());
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.insert_boxed(field.name().unwrap(), field.value().to_dynamic());
364 }
365 DynamicVariant::Struct(dyn_struct)
366 }
367 };
368 self.set_variant(value.variant_name(), dyn_variant);
369 }
370
371 Ok(())
372 }
373
374 #[inline]
375 fn reflect_kind(&self) -> ReflectKind {
376 ReflectKind::Enum
377 }
378
379 #[inline]
380 fn reflect_ref(&self) -> ReflectRef<'_> {
381 ReflectRef::Enum(self)
382 }
383
384 #[inline]
385 fn reflect_mut(&mut self) -> ReflectMut<'_> {
386 ReflectMut::Enum(self)
387 }
388
389 #[inline]
390 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
391 ReflectOwned::Enum(self)
392 }
393
394 #[inline]
395 fn reflect_hash(&self) -> Option<u64> {
396 enum_hash(self)
397 }
398
399 #[inline]
400 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
401 enum_partial_eq(self, value)
402 }
403
404 #[inline]
405 fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
406 enum_partial_cmp(self, value)
407 }
408
409 #[inline]
410 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
411 write!(f, "DynamicEnum(")?;
412 enum_debug(self, f)?;
413 write!(f, ")")
414 }
415
416 #[inline]
417 fn is_dynamic(&self) -> bool {
418 true
419 }
420}
421
422impl_type_path!((in bevy_reflect) DynamicEnum);