Skip to content

Commit 189cd9d

Browse files
committed
Add string-based path support for reflected enums
1 parent 7ced533 commit 189cd9d

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)