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#[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#[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 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 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 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 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 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 pub fn from<TEnum: Enum>(value: TEnum) -> Self {
146 Self::from_ref(&value)
147 }
148
149 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 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 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);