Skip to content

Commit 4d0961c

Browse files
MrGVSValice-i-cecilepablo-lua
authored
bevy_reflect: Add ReflectRef/ReflectMut/ReflectOwned convenience casting methods (#15235)
# Objective #13320 added convenience methods for casting a `TypeInfo` into its respective variant: ```rust let info: &TypeInfo = <Vec<i32> as Typed>::type_info(); // We know `info` contains a `ListInfo`, so we can simply cast it: let list_info: &ListInfo = info.as_list().unwrap(); ``` This is especially helpful when you have already verified a type is a certain kind via `ReflectRef`, `ReflectMut`, `ReflectOwned`, or `ReflectKind`. As mentioned in that PR, though, it would be useful to add similar convenience methods to those types as well. ## Solution Added convenience casting methods to `ReflectRef`, `ReflectMut`, and `ReflectOwned`. With these methods, I was able to reduce our nesting in certain places throughout the crate. Additionally, I took this opportunity to move these types (and `ReflectKind`) to their own module to help clean up the `reflect` module. ## Testing You can test locally by running: ``` cargo test --package bevy_reflect --all-features ``` --- ## Showcase Convenience methods for casting `ReflectRef`, `ReflectMut`, and `ReflectOwned` into their respective variants has been added! This allows you to write cleaner code if you already know the kind of your reflected data: ```rust // BEFORE let ReflectRef::List(list) = list.reflect_ref() else { panic!("expected list"); }; // AFTER let list = list.reflect_ref().as_list().unwrap(); ``` --------- Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: Pablo Reinhardt <[email protected]>
1 parent f78856b commit 4d0961c

File tree

15 files changed

+530
-355
lines changed

15 files changed

+530
-355
lines changed

crates/bevy_asset/src/reflect.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ mod tests {
249249
use crate::{Asset, AssetApp, AssetPlugin, ReflectAsset, UntypedHandle};
250250
use bevy_app::App;
251251
use bevy_ecs::reflect::AppTypeRegistry;
252-
use bevy_reflect::{Reflect, ReflectMut};
252+
use bevy_reflect::Reflect;
253253

254254
#[derive(Asset, Reflect)]
255255
struct AssetType {
@@ -278,13 +278,13 @@ mod tests {
278278
};
279279

280280
let handle = reflect_asset.add(app.world_mut(), &value);
281-
let ReflectMut::Struct(strukt) = reflect_asset
281+
// struct is a reserved keyword, so we can't use it here
282+
let strukt = reflect_asset
282283
.get_mut(app.world_mut(), handle)
283284
.unwrap()
284285
.reflect_mut()
285-
else {
286-
unreachable!();
287-
};
286+
.as_struct()
287+
.unwrap();
288288
strukt
289289
.field_mut("field")
290290
.unwrap()

crates/bevy_reflect/src/array.rs

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -436,23 +436,20 @@ pub fn array_try_apply<A: Array>(
436436
array: &mut A,
437437
reflect: &dyn PartialReflect,
438438
) -> Result<(), ApplyError> {
439-
if let ReflectRef::Array(reflect_array) = reflect.reflect_ref() {
440-
if array.len() != reflect_array.len() {
441-
return Err(ApplyError::DifferentSize {
442-
from_size: reflect_array.len(),
443-
to_size: array.len(),
444-
});
445-
}
446-
for (i, value) in reflect_array.iter().enumerate() {
447-
let v = array.get_mut(i).unwrap();
448-
v.try_apply(value)?;
449-
}
450-
} else {
451-
return Err(ApplyError::MismatchedKinds {
452-
from_kind: reflect.reflect_kind(),
453-
to_kind: ReflectKind::Array,
439+
let reflect_array = reflect.reflect_ref().as_array()?;
440+
441+
if array.len() != reflect_array.len() {
442+
return Err(ApplyError::DifferentSize {
443+
from_size: reflect_array.len(),
444+
to_size: array.len(),
454445
});
455446
}
447+
448+
for (i, value) in reflect_array.iter().enumerate() {
449+
let v = array.get_mut(i).unwrap();
450+
v.try_apply(value)?;
451+
}
452+
456453
Ok(())
457454
}
458455

@@ -507,7 +504,7 @@ pub fn array_debug(dyn_array: &dyn Array, f: &mut Formatter<'_>) -> std::fmt::Re
507504
}
508505
#[cfg(test)]
509506
mod tests {
510-
use crate::{Reflect, ReflectRef};
507+
use crate::Reflect;
511508
#[test]
512509
fn next_index_increment() {
513510
const SIZE: usize = if cfg!(debug_assertions) {
@@ -519,9 +516,7 @@ mod tests {
519516

520517
let b = Box::new([(); SIZE]).into_reflect();
521518

522-
let ReflectRef::Array(array) = b.reflect_ref() else {
523-
panic!("Not an array...");
524-
};
519+
let array = b.reflect_ref().as_array().unwrap();
525520

526521
let mut iter = array.iter();
527522
iter.index = SIZE - 1;

crates/bevy_reflect/src/enums/dynamic_enum.rs

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -322,55 +322,50 @@ impl PartialReflect for DynamicEnum {
322322

323323
#[inline]
324324
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
325-
if let ReflectRef::Enum(value) = value.reflect_ref() {
326-
if Enum::variant_name(self) == value.variant_name() {
327-
// Same variant -> just update fields
328-
match value.variant_type() {
329-
VariantType::Struct => {
330-
for field in value.iter_fields() {
331-
let name = field.name().unwrap();
332-
if let Some(v) = Enum::field_mut(self, name) {
333-
v.try_apply(field.value())?;
334-
}
325+
let value = value.reflect_ref().as_enum()?;
326+
327+
if Enum::variant_name(self) == value.variant_name() {
328+
// Same variant -> just update fields
329+
match value.variant_type() {
330+
VariantType::Struct => {
331+
for field in value.iter_fields() {
332+
let name = field.name().unwrap();
333+
if let Some(v) = Enum::field_mut(self, name) {
334+
v.try_apply(field.value())?;
335335
}
336336
}
337-
VariantType::Tuple => {
338-
for (index, field) in value.iter_fields().enumerate() {
339-
if let Some(v) = Enum::field_at_mut(self, index) {
340-
v.try_apply(field.value())?;
341-
}
342-
}
343-
}
344-
_ => {}
345337
}
346-
} else {
347-
// New variant -> perform a switch
348-
let dyn_variant = match value.variant_type() {
349-
VariantType::Unit => DynamicVariant::Unit,
350-
VariantType::Tuple => {
351-
let mut dyn_tuple = DynamicTuple::default();
352-
for field in value.iter_fields() {
353-
dyn_tuple.insert_boxed(field.value().clone_value());
338+
VariantType::Tuple => {
339+
for (index, field) in value.iter_fields().enumerate() {
340+
if let Some(v) = Enum::field_at_mut(self, index) {
341+
v.try_apply(field.value())?;
354342
}
355-
DynamicVariant::Tuple(dyn_tuple)
356343
}
357-
VariantType::Struct => {
358-
let mut dyn_struct = DynamicStruct::default();
359-
for field in value.iter_fields() {
360-
dyn_struct
361-
.insert_boxed(field.name().unwrap(), field.value().clone_value());
362-
}
363-
DynamicVariant::Struct(dyn_struct)
364-
}
365-
};
366-
self.set_variant(value.variant_name(), dyn_variant);
344+
}
345+
_ => {}
367346
}
368347
} else {
369-
return Err(ApplyError::MismatchedKinds {
370-
from_kind: value.reflect_kind(),
371-
to_kind: ReflectKind::Enum,
372-
});
348+
// New variant -> perform a switch
349+
let dyn_variant = match value.variant_type() {
350+
VariantType::Unit => DynamicVariant::Unit,
351+
VariantType::Tuple => {
352+
let mut dyn_tuple = DynamicTuple::default();
353+
for field in value.iter_fields() {
354+
dyn_tuple.insert_boxed(field.value().clone_value());
355+
}
356+
DynamicVariant::Tuple(dyn_tuple)
357+
}
358+
VariantType::Struct => {
359+
let mut dyn_struct = DynamicStruct::default();
360+
for field in value.iter_fields() {
361+
dyn_struct.insert_boxed(field.name().unwrap(), field.value().clone_value());
362+
}
363+
DynamicVariant::Struct(dyn_struct)
364+
}
365+
};
366+
self.set_variant(value.variant_name(), dyn_variant);
373367
}
368+
374369
Ok(())
375370
}
376371

crates/bevy_reflect/src/impls/smallvec.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,15 @@ where
194194
T::Item: FromReflect + MaybeTyped + TypePath,
195195
{
196196
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
197-
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
198-
let mut new_list = Self::with_capacity(ref_list.len());
199-
for field in ref_list.iter() {
200-
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
201-
}
202-
Some(new_list)
203-
} else {
204-
None
197+
let ref_list = reflect.reflect_ref().as_list().ok()?;
198+
199+
let mut new_list = Self::with_capacity(ref_list.len());
200+
201+
for field in ref_list.iter() {
202+
new_list.push(<T as SmallArray>::Item::from_reflect(field)?);
205203
}
204+
205+
Some(new_list)
206206
}
207207
}
208208

crates/bevy_reflect/src/impls/std.rs

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,15 @@ macro_rules! impl_reflect_for_veclike {
544544

545545
impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration> FromReflect for $ty {
546546
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
547-
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
548-
let mut new_list = Self::with_capacity(ref_list.len());
549-
for field in ref_list.iter() {
550-
$push(&mut new_list, T::from_reflect(field)?);
551-
}
552-
Some(new_list)
553-
} else {
554-
None
547+
let ref_list = reflect.reflect_ref().as_list().ok()?;
548+
549+
let mut new_list = Self::with_capacity(ref_list.len());
550+
551+
for field in ref_list.iter() {
552+
$push(&mut new_list, T::from_reflect(field)?);
555553
}
554+
555+
Some(new_list)
556556
}
557557
}
558558
};
@@ -792,17 +792,17 @@ macro_rules! impl_reflect_for_hashmap {
792792
S: TypePath + BuildHasher + Default + Send + Sync,
793793
{
794794
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
795-
if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
796-
let mut new_map = Self::with_capacity_and_hasher(ref_map.len(), S::default());
797-
for (key, value) in ref_map.iter() {
798-
let new_key = K::from_reflect(key)?;
799-
let new_value = V::from_reflect(value)?;
800-
new_map.insert(new_key, new_value);
801-
}
802-
Some(new_map)
803-
} else {
804-
None
795+
let ref_map = reflect.reflect_ref().as_map().ok()?;
796+
797+
let mut new_map = Self::with_capacity_and_hasher(ref_map.len(), S::default());
798+
799+
for (key, value) in ref_map.iter() {
800+
let new_key = K::from_reflect(key)?;
801+
let new_value = V::from_reflect(value)?;
802+
new_map.insert(new_key, new_value);
805803
}
804+
805+
Some(new_map)
806806
}
807807
}
808808
};
@@ -1013,16 +1013,16 @@ macro_rules! impl_reflect_for_hashset {
10131013
S: TypePath + BuildHasher + Default + Send + Sync,
10141014
{
10151015
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
1016-
if let ReflectRef::Set(ref_set) = reflect.reflect_ref() {
1017-
let mut new_set = Self::with_capacity_and_hasher(ref_set.len(), S::default());
1018-
for value in ref_set.iter() {
1019-
let new_value = V::from_reflect(value)?;
1020-
new_set.insert(new_value);
1021-
}
1022-
Some(new_set)
1023-
} else {
1024-
None
1016+
let ref_set = reflect.reflect_ref().as_set().ok()?;
1017+
1018+
let mut new_set = Self::with_capacity_and_hasher(ref_set.len(), S::default());
1019+
1020+
for value in ref_set.iter() {
1021+
let new_value = V::from_reflect(value)?;
1022+
new_set.insert(new_value);
10251023
}
1024+
1025+
Some(new_set)
10261026
}
10271027
}
10281028
};
@@ -1251,17 +1251,17 @@ where
12511251
V: FromReflect + MaybeTyped + TypePath + GetTypeRegistration,
12521252
{
12531253
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
1254-
if let ReflectRef::Map(ref_map) = reflect.reflect_ref() {
1255-
let mut new_map = Self::new();
1256-
for (key, value) in ref_map.iter() {
1257-
let new_key = K::from_reflect(key)?;
1258-
let new_value = V::from_reflect(value)?;
1259-
new_map.insert(new_key, new_value);
1260-
}
1261-
Some(new_map)
1262-
} else {
1263-
None
1254+
let ref_map = reflect.reflect_ref().as_map().ok()?;
1255+
1256+
let mut new_map = Self::new();
1257+
1258+
for (key, value) in ref_map.iter() {
1259+
let new_key = K::from_reflect(key)?;
1260+
let new_value = V::from_reflect(value)?;
1261+
new_map.insert(new_key, new_value);
12641262
}
1263+
1264+
Some(new_map)
12651265
}
12661266
}
12671267

@@ -1422,15 +1422,15 @@ impl<T: FromReflect + MaybeTyped + TypePath + GetTypeRegistration, const N: usiz
14221422
for [T; N]
14231423
{
14241424
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
1425-
if let ReflectRef::Array(ref_array) = reflect.reflect_ref() {
1426-
let mut temp_vec = Vec::with_capacity(ref_array.len());
1427-
for field in ref_array.iter() {
1428-
temp_vec.push(T::from_reflect(field)?);
1429-
}
1430-
temp_vec.try_into().ok()
1431-
} else {
1432-
None
1425+
let ref_array = reflect.reflect_ref().as_array().ok()?;
1426+
1427+
let mut temp_vec = Vec::with_capacity(ref_array.len());
1428+
1429+
for field in ref_array.iter() {
1430+
temp_vec.push(T::from_reflect(field)?);
14331431
}
1432+
1433+
temp_vec.try_into().ok()
14341434
}
14351435
}
14361436

@@ -1795,15 +1795,15 @@ impl<T: FromReflect + MaybeTyped + Clone + TypePath + GetTypeRegistration> FromR
17951795
for Cow<'static, [T]>
17961796
{
17971797
fn from_reflect(reflect: &dyn PartialReflect) -> Option<Self> {
1798-
if let ReflectRef::List(ref_list) = reflect.reflect_ref() {
1799-
let mut temp_vec = Vec::with_capacity(ref_list.len());
1800-
for field in ref_list.iter() {
1801-
temp_vec.push(T::from_reflect(field)?);
1802-
}
1803-
Some(temp_vec.into())
1804-
} else {
1805-
None
1798+
let ref_list = reflect.reflect_ref().as_list().ok()?;
1799+
1800+
let mut temp_vec = Vec::with_capacity(ref_list.len());
1801+
1802+
for field in ref_list.iter() {
1803+
temp_vec.push(T::from_reflect(field)?);
18061804
}
1805+
1806+
Some(temp_vec.into())
18071807
}
18081808
}
18091809

0 commit comments

Comments
 (0)