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