Skip to content

Commit 1a8f833

Browse files
Shrink from_reflect_with_fallback (#18296)
# Objective Reduce duplicate code generated by `from_reflect_with_fallback`. ## Solution Polymorphize part of the function. In a binary with `#[reflect(Component)]` for 100 types (and nothing else), this reduces the size of the release binary by 3.8% in my testing. The impact on a normal Bevy app will be almost nothing, but I'm hoping to make more PRs like this. --------- Co-authored-by: James Liu <[email protected]>
1 parent 582543d commit 1a8f833

File tree

1 file changed

+48
-46
lines changed
  • crates/bevy_ecs/src/reflect

1 file changed

+48
-46
lines changed

crates/bevy_ecs/src/reflect/mod.rs

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -106,53 +106,55 @@ pub fn from_reflect_with_fallback<T: Reflect + TypePath>(
106106
world: &mut World,
107107
registry: &TypeRegistry,
108108
) -> T {
109-
fn different_type_error<T: TypePath>(reflected: &str) -> ! {
110-
panic!(
111-
"The registration for the reflected `{}` trait for the type `{}` produced \
112-
a value of a different type",
113-
reflected,
114-
T::type_path(),
115-
);
116-
}
117-
118-
// First, try `FromReflect`. This is handled differently from the others because
119-
// it doesn't need a subsequent `apply` and may fail.
120-
if let Some(reflect_from_reflect) =
121-
registry.get_type_data::<ReflectFromReflect>(TypeId::of::<T>())
122-
{
109+
#[inline(never)]
110+
fn type_erased(
111+
reflected: &dyn PartialReflect,
112+
world: &mut World,
113+
registry: &TypeRegistry,
114+
id: TypeId,
115+
name: DebugName,
116+
) -> alloc::boxed::Box<dyn core::any::Any> {
117+
// First, try `FromReflect`. This is handled differently from the others because
118+
// it doesn't need a subsequent `apply` and may fail.
123119
// If it fails it's ok, we can continue checking `Default` and `FromWorld`.
124-
if let Some(value) = reflect_from_reflect.from_reflect(reflected) {
125-
return value
126-
.take::<T>()
127-
.unwrap_or_else(|_| different_type_error::<T>("FromReflect"));
120+
let (value, source) = if let Some(value) = registry
121+
.get_type_data::<ReflectFromReflect>(id)
122+
.and_then(|reflect_from_reflect| reflect_from_reflect.from_reflect(reflected))
123+
{
124+
(value, "FromReflect")
128125
}
129-
}
130-
131-
// Create an instance of `T` using either the reflected `Default` or `FromWorld`.
132-
let mut value = if let Some(reflect_default) =
133-
registry.get_type_data::<ReflectDefault>(TypeId::of::<T>())
134-
{
135-
reflect_default
136-
.default()
137-
.take::<T>()
138-
.unwrap_or_else(|_| different_type_error::<T>("Default"))
139-
} else if let Some(reflect_from_world) =
140-
registry.get_type_data::<ReflectFromWorld>(TypeId::of::<T>())
141-
{
142-
reflect_from_world
143-
.from_world(world)
144-
.take::<T>()
145-
.unwrap_or_else(|_| different_type_error::<T>("FromWorld"))
146-
} else {
147-
panic!(
148-
"Couldn't create an instance of `{}` using the reflected `FromReflect`, \
149-
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
150-
or `#[reflect(FromWorld)]`?",
151-
// FIXME: once we have unique reflect, use `TypePath`.
152-
DebugName::type_name::<T>(),
126+
// Create an instance of `T` using either the reflected `Default` or `FromWorld`.
127+
else if let Some(reflect_default) = registry.get_type_data::<ReflectDefault>(id) {
128+
let mut value = reflect_default.default();
129+
value.apply(reflected);
130+
(value, "Default")
131+
} else if let Some(reflect_from_world) = registry.get_type_data::<ReflectFromWorld>(id) {
132+
let mut value = reflect_from_world.from_world(world);
133+
value.apply(reflected);
134+
(value, "FromWorld")
135+
} else {
136+
panic!(
137+
"Couldn't create an instance of `{name}` using the reflected `FromReflect`, \
138+
`Default` or `FromWorld` traits. Are you perhaps missing a `#[reflect(Default)]` \
139+
or `#[reflect(FromWorld)]`?",
140+
);
141+
};
142+
assert_eq!(
143+
value.as_any().type_id(),
144+
id,
145+
"The registration for the reflected `{source}` trait for the type `{name}` produced \
146+
a value of a different type",
153147
);
154-
};
155-
156-
value.apply(reflected);
157-
value
148+
value
149+
}
150+
*type_erased(
151+
reflected,
152+
world,
153+
registry,
154+
TypeId::of::<T>(),
155+
// FIXME: once we have unique reflect, use `TypePath`.
156+
DebugName::type_name::<T>(),
157+
)
158+
.downcast::<T>()
159+
.unwrap()
158160
}

0 commit comments

Comments
 (0)