Skip to content

Commit 5819c59

Browse files
MrGVSValradish
authored andcommitted
bevy_reflect: Add simple enum support to reflection paths (bevyengine#6560)
# Objective Enums are now reflectable, but are not accessible via reflection paths. This would allow us to do things like: ```rust #[derive(Reflect)] struct MyStruct { data: MyEnum } #[derive(Reflect)] struct MyEnum { Foo(u32, u32), Bar(bool) } let x = MyStruct { data: MyEnum::Foo(123), }; assert_eq!(*x.get_path::<u32>("data.1").unwrap(), 123); ``` ## Solution Added support for enums in reflection paths. ##### Note This uses a simple approach of just getting the field with the given accessor. It does not do matching or anything else to ensure the enum is the intended variant. This means that the variant must be known ahead of time or matched outside the reflection path (i.e. path to variant, perform manual match, and continue pathing). --- ## Changelog - Added support for enums in reflection paths
1 parent a72ee9a commit 5819c59

File tree

1 file changed

+77
-1
lines changed

1 file changed

+77
-1
lines changed

crates/bevy_reflect/src/path.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::num::ParseIntError;
22

3-
use crate::{Array, Reflect, ReflectMut, ReflectRef};
3+
use crate::{Array, Reflect, ReflectMut, ReflectRef, VariantType};
44
use thiserror::Error;
55

66
/// An error returned from a failed path string query.
@@ -29,6 +29,8 @@ pub enum ReflectPathError<'a> {
2929
IndexParseError(#[from] ParseIntError),
3030
#[error("failed to downcast to the path result to the given type")]
3131
InvalidDowncast,
32+
#[error("expected either a struct variant or tuple variant, but found a unit variant")]
33+
InvalidVariantAccess { index: usize, accessor: &'a str },
3234
}
3335

3436
/// A trait which allows nested values to be retrieved with path strings.
@@ -280,6 +282,29 @@ fn read_field<'r, 'p>(
280282
},
281283
)?)
282284
}
285+
ReflectRef::Enum(reflect_enum) => match reflect_enum.variant_type() {
286+
VariantType::Struct => {
287+
Ok(reflect_enum
288+
.field(field)
289+
.ok_or(ReflectPathError::InvalidField {
290+
index: current_index,
291+
field,
292+
})?)
293+
}
294+
VariantType::Tuple => {
295+
let tuple_index = field.parse::<usize>()?;
296+
Ok(reflect_enum
297+
.field_at(tuple_index)
298+
.ok_or(ReflectPathError::InvalidField {
299+
index: current_index,
300+
field,
301+
})?)
302+
}
303+
_ => Err(ReflectPathError::InvalidVariantAccess {
304+
index: current_index,
305+
accessor: field,
306+
}),
307+
},
283308
_ => Err(ReflectPathError::ExpectedStruct {
284309
index: current_index,
285310
}),
@@ -309,6 +334,29 @@ fn read_field_mut<'r, 'p>(
309334
},
310335
)?)
311336
}
337+
ReflectMut::Enum(reflect_enum) => match reflect_enum.variant_type() {
338+
VariantType::Struct => {
339+
Ok(reflect_enum
340+
.field_mut(field)
341+
.ok_or(ReflectPathError::InvalidField {
342+
index: current_index,
343+
field,
344+
})?)
345+
}
346+
VariantType::Tuple => {
347+
let tuple_index = field.parse::<usize>()?;
348+
Ok(reflect_enum.field_at_mut(tuple_index).ok_or(
349+
ReflectPathError::InvalidField {
350+
index: current_index,
351+
field,
352+
},
353+
)?)
354+
}
355+
_ => Err(ReflectPathError::InvalidVariantAccess {
356+
index: current_index,
357+
accessor: field,
358+
}),
359+
},
312360
_ => Err(ReflectPathError::ExpectedStruct {
313361
index: current_index,
314362
}),
@@ -416,6 +464,9 @@ mod tests {
416464
x: B,
417465
y: Vec<C>,
418466
z: D,
467+
unit_variant: F,
468+
tuple_variant: F,
469+
struct_variant: F,
419470
}
420471

421472
#[derive(Reflect)]
@@ -435,6 +486,13 @@ mod tests {
435486
#[derive(Reflect)]
436487
struct E(f32, usize);
437488

489+
#[derive(Reflect, FromReflect, PartialEq, Debug)]
490+
enum F {
491+
Unit,
492+
Tuple(u32, u32),
493+
Struct { value: char },
494+
}
495+
438496
let mut a = A {
439497
w: 1,
440498
x: B {
@@ -443,6 +501,9 @@ mod tests {
443501
},
444502
y: vec![C { baz: 1.0 }, C { baz: 2.0 }],
445503
z: D(E(10.0, 42)),
504+
unit_variant: F::Unit,
505+
tuple_variant: F::Tuple(123, 321),
506+
struct_variant: F::Struct { value: 'm' },
446507
};
447508

448509
assert_eq!(*a.get_path::<usize>("w").unwrap(), 1);
@@ -451,9 +512,16 @@ mod tests {
451512
assert_eq!(*a.get_path::<f32>("y[1].baz").unwrap(), 2.0);
452513
assert_eq!(*a.get_path::<usize>("z.0.1").unwrap(), 42);
453514

515+
assert_eq!(*a.get_path::<F>("unit_variant").unwrap(), F::Unit);
516+
assert_eq!(*a.get_path::<u32>("tuple_variant.1").unwrap(), 321);
517+
assert_eq!(*a.get_path::<char>("struct_variant.value").unwrap(), 'm');
518+
454519
*a.get_path_mut::<f32>("y[1].baz").unwrap() = 3.0;
455520
assert_eq!(a.y[1].baz, 3.0);
456521

522+
*a.get_path_mut::<u32>("tuple_variant.0").unwrap() = 1337;
523+
assert_eq!(a.tuple_variant, F::Tuple(1337, 321));
524+
457525
assert_eq!(
458526
a.path("x.notreal").err().unwrap(),
459527
ReflectPathError::InvalidField {
@@ -462,6 +530,14 @@ mod tests {
462530
}
463531
);
464532

533+
assert_eq!(
534+
a.path("unit_variant.0").err().unwrap(),
535+
ReflectPathError::InvalidVariantAccess {
536+
index: 13,
537+
accessor: "0"
538+
}
539+
);
540+
465541
assert_eq!(
466542
a.path("x..").err().unwrap(),
467543
ReflectPathError::ExpectedIdent { index: 2 }

0 commit comments

Comments
 (0)