1use bevy_reflect_derive::impl_type_path;
2
3use crate::{
4 enum_debug, enum_hash, enum_partial_eq, ApplyError, DynamicStruct, DynamicTuple, Enum,
5 PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Struct, Tuple,
6 TypeInfo, VariantFieldIter, VariantType,
7};
8
9use alloc::{boxed::Box, string::String};
10use core::fmt::Formatter;
11use derive_more::derive::From;
12
13#[derive(Debug, Default, From)]
15pub enum DynamicVariant {
16 #[default]
18 Unit,
19 Tuple(DynamicTuple),
21 Struct(DynamicStruct),
23}
24
25impl Clone for DynamicVariant {
26 fn clone(&self) -> Self {
27 match self {
28 DynamicVariant::Unit => DynamicVariant::Unit,
29 DynamicVariant::Tuple(data) => DynamicVariant::Tuple(data.to_dynamic_tuple()),
30 DynamicVariant::Struct(data) => DynamicVariant::Struct(data.to_dynamic_struct()),
31 }
32 }
33}
34
35impl From<()> for DynamicVariant {
36 fn from(_: ()) -> Self {
37 Self::Unit
38 }
39}
40
41#[derive(Default, Debug)]
66pub struct DynamicEnum {
67 represented_type: Option<&'static TypeInfo>,
68 variant_name: String,
69 variant_index: usize,
70 variant: DynamicVariant,
71}
72
73impl DynamicEnum {
74 pub fn new<I: Into<String>, V: Into<DynamicVariant>>(variant_name: I, variant: V) -> Self {
81 Self {
82 represented_type: None,
83 variant_index: 0,
84 variant_name: variant_name.into(),
85 variant: variant.into(),
86 }
87 }
88
89 pub fn new_with_index<I: Into<String>, V: Into<DynamicVariant>>(
97 variant_index: usize,
98 variant_name: I,
99 variant: V,
100 ) -> Self {
101 Self {
102 represented_type: None,
103 variant_index,
104 variant_name: variant_name.into(),
105 variant: variant.into(),
106 }
107 }
108
109 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
117 if let Some(represented_type) = represented_type {
118 assert!(
119 matches!(represented_type, TypeInfo::Enum(_)),
120 "expected TypeInfo::Enum but received: {represented_type:?}",
121 );
122 }
123
124 self.represented_type = represented_type;
125 }
126
127 pub fn set_variant<I: Into<String>, V: Into<DynamicVariant>>(&mut self, name: I, variant: V) {
129 self.variant_name = name.into();
130 self.variant = variant.into();
131 }
132
133 pub fn set_variant_with_index<I: Into<String>, V: Into<DynamicVariant>>(
135 &mut self,
136 variant_index: usize,
137 variant_name: I,
138 variant: V,
139 ) {
140 self.variant_index = variant_index;
141 self.variant_name = variant_name.into();
142 self.variant = variant.into();
143 }
144
145 pub fn variant(&self) -> &DynamicVariant {
147 &self.variant
148 }
149
150 pub fn variant_mut(&mut self) -> &mut DynamicVariant {
158 &mut self.variant
159 }
160
161 pub fn from<TEnum: Enum>(value: TEnum) -> Self {
165 Self::from_ref(&value)
166 }
167
168 pub fn from_ref<TEnum: Enum + ?Sized>(value: &TEnum) -> Self {
172 let type_info = value.get_represented_type_info();
173 let mut dyn_enum = match value.variant_type() {
174 VariantType::Unit => DynamicEnum::new_with_index(
175 value.variant_index(),
176 value.variant_name(),
177 DynamicVariant::Unit,
178 ),
179 VariantType::Tuple => {
180 let mut data = DynamicTuple::default();
181 for field in value.iter_fields() {
182 data.insert_boxed(field.value().to_dynamic());
183 }
184 DynamicEnum::new_with_index(
185 value.variant_index(),
186 value.variant_name(),
187 DynamicVariant::Tuple(data),
188 )
189 }
190 VariantType::Struct => {
191 let mut data = DynamicStruct::default();
192 for field in value.iter_fields() {
193 let name = field.name().unwrap();
194 data.insert_boxed(name, field.value().to_dynamic());
195 }
196 DynamicEnum::new_with_index(
197 value.variant_index(),
198 value.variant_name(),
199 DynamicVariant::Struct(data),
200 )
201 }
202 };
203
204 dyn_enum.set_represented_type(type_info);
205 dyn_enum
206 }
207}
208
209impl Enum for DynamicEnum {
210 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
211 if let DynamicVariant::Struct(data) = &self.variant {
212 data.field(name)
213 } else {
214 None
215 }
216 }
217
218 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
219 match &self.variant {
220 DynamicVariant::Tuple(data) => data.field(index),
221 DynamicVariant::Struct(data) => data.field_at(index),
222 DynamicVariant::Unit => None,
223 }
224 }
225
226 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
227 if let DynamicVariant::Struct(data) = &mut self.variant {
228 data.field_mut(name)
229 } else {
230 None
231 }
232 }
233
234 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
235 match &mut self.variant {
236 DynamicVariant::Tuple(data) => data.field_mut(index),
237 DynamicVariant::Struct(data) => data.field_at_mut(index),
238 DynamicVariant::Unit => None,
239 }
240 }
241
242 fn index_of(&self, name: &str) -> Option<usize> {
243 if let DynamicVariant::Struct(data) = &self.variant {
244 data.index_of(name)
245 } else {
246 None
247 }
248 }
249
250 fn name_at(&self, index: usize) -> Option<&str> {
251 if let DynamicVariant::Struct(data) = &self.variant {
252 data.name_at(index)
253 } else {
254 None
255 }
256 }
257
258 fn iter_fields(&self) -> VariantFieldIter<'_> {
259 VariantFieldIter::new(self)
260 }
261
262 fn field_len(&self) -> usize {
263 match &self.variant {
264 DynamicVariant::Unit => 0,
265 DynamicVariant::Tuple(data) => data.field_len(),
266 DynamicVariant::Struct(data) => data.field_len(),
267 }
268 }
269
270 fn variant_name(&self) -> &str {
271 &self.variant_name
272 }
273
274 fn variant_index(&self) -> usize {
275 self.variant_index
276 }
277
278 fn variant_type(&self) -> VariantType {
279 match &self.variant {
280 DynamicVariant::Unit => VariantType::Unit,
281 DynamicVariant::Tuple(..) => VariantType::Tuple,
282 DynamicVariant::Struct(..) => VariantType::Struct,
283 }
284 }
285}
286
287impl PartialReflect for DynamicEnum {
288 #[inline]
289 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
290 self.represented_type
291 }
292
293 #[inline]
294 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
295 self
296 }
297
298 #[inline]
299 fn as_partial_reflect(&self) -> &dyn PartialReflect {
300 self
301 }
302
303 #[inline]
304 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
305 self
306 }
307
308 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
309 Err(self)
310 }
311
312 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
313 None
314 }
315
316 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
317 None
318 }
319
320 #[inline]
321 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
322 let value = value.reflect_ref().as_enum()?;
323
324 if Enum::variant_name(self) == value.variant_name() {
325 match value.variant_type() {
327 VariantType::Struct => {
328 for field in value.iter_fields() {
329 let name = field.name().unwrap();
330 if let Some(v) = Enum::field_mut(self, name) {
331 v.try_apply(field.value())?;
332 }
333 }
334 }
335 VariantType::Tuple => {
336 for (index, field) in value.iter_fields().enumerate() {
337 if let Some(v) = Enum::field_at_mut(self, index) {
338 v.try_apply(field.value())?;
339 }
340 }
341 }
342 _ => {}
343 }
344 } else {
345 let dyn_variant = match value.variant_type() {
347 VariantType::Unit => DynamicVariant::Unit,
348 VariantType::Tuple => {
349 let mut dyn_tuple = DynamicTuple::default();
350 for field in value.iter_fields() {
351 dyn_tuple.insert_boxed(field.value().to_dynamic());
352 }
353 DynamicVariant::Tuple(dyn_tuple)
354 }
355 VariantType::Struct => {
356 let mut dyn_struct = DynamicStruct::default();
357 for field in value.iter_fields() {
358 dyn_struct.insert_boxed(field.name().unwrap(), field.value().to_dynamic());
359 }
360 DynamicVariant::Struct(dyn_struct)
361 }
362 };
363 self.set_variant(value.variant_name(), dyn_variant);
364 }
365
366 Ok(())
367 }
368
369 #[inline]
370 fn reflect_kind(&self) -> ReflectKind {
371 ReflectKind::Enum
372 }
373
374 #[inline]
375 fn reflect_ref(&self) -> ReflectRef<'_> {
376 ReflectRef::Enum(self)
377 }
378
379 #[inline]
380 fn reflect_mut(&mut self) -> ReflectMut<'_> {
381 ReflectMut::Enum(self)
382 }
383
384 #[inline]
385 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
386 ReflectOwned::Enum(self)
387 }
388
389 #[inline]
390 fn reflect_hash(&self) -> Option<u64> {
391 enum_hash(self)
392 }
393
394 #[inline]
395 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
396 enum_partial_eq(self, value)
397 }
398
399 #[inline]
400 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
401 write!(f, "DynamicEnum(")?;
402 enum_debug(self, f)?;
403 write!(f, ")")
404 }
405
406 #[inline]
407 fn is_dynamic(&self) -> bool {
408 true
409 }
410}
411
412impl_type_path!((in bevy_reflect) DynamicEnum);