Skip to content

add ReflectFromTemplate and ReflectTemplate#24930

Draft
AwfulToTheEar wants to merge 3 commits into
bevyengine:mainfrom
AwfulToTheEar:add-reflect-for-template
Draft

add ReflectFromTemplate and ReflectTemplate#24930
AwfulToTheEar wants to merge 3 commits into
bevyengine:mainfrom
AwfulToTheEar:add-reflect-for-template

Conversation

@AwfulToTheEar

Copy link
Copy Markdown

Objective

implementation for issue (#24870)

Solution

Add ReflectFromTemplate and ReflectTemplate for creating Templates and their Output from reflection.
Derive Reflect for all Templates and Reflect FromTemplate and Template.

Testing

Added test for fetching the associated ReflectTemplate for a reflected struct and creating the struct.


Showcase

#[derive(Component, Reflect, Default, Clone)]
#[Component, FromTemplate]
struct MyStruct {
    foo: i32
}

//fetch template associated with MyStruct
let my_struct_registration = registry.get(TypeId::of::<MyStruct>()).unwrap();
let reflect_from_template = my_struct_registration.data::<ReflectFromTemplate>().unwrap();

//create template
let my_struct_template_registration = reflect_from_template.get_template(&registry).unwrap();
let reflect_template = my_struct_template_registration.data::<ReflectTemplate>().unwrap();
let reflect_default = my_struct_template_registration.data::<ReflectDefault>().unwrap();

let template = reflect_default.default();

//build MyStruct
let mut entity = world.spawn_empty();
let mut scene_entity_references = SceneEntityReferences::default();
let mut template_context = TemplateContext::new(
    &mut entity,
    &mut scene_entity_references
);
let my_struct_reflect = reflect_template.build(
    &mut template_context,
    template.as_partial_reflect(),
    &registry
).unwrap();
let my_struct = my_struct_reflect.downcast::<MyStruct>().unwrap();

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide, as well as our policy regarding AI usage, and we look forward to reviewing your pull request shortly ✨

@MrGVSV MrGVSV left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! I left some minor nitpicks. Can we also add docs and format the code please?

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated
}
}

impl<T: Reflect + Template<Output=impl Reflect> + TypePath> CreateTypeData<T> for ReflectTemplate {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly had no clue you could do impl Reflect here. How does this differ from writing Template<Output: Reflect>?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked and, writing <Output: Reflect> doesn't work, it needs to be either dyn Reflect or impl Reflect

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated
Self(fns)
}

pub fn fn_pointer(&self) -> &ReflectTemplateFns {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We should probably update the name to be plural

Suggested change
pub fn fn_pointer(&self) -> &ReflectTemplateFns {
pub fn fn_pointers(&self) -> &ReflectTemplateFns {

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated

fn clone_template(&self) -> Self {
Self {
foo: self.foo.clone()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I don't think the call to clone is needed here

Suggested change
foo: self.foo.clone()
foo: self.foo

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated
Comment on lines +99 to +108
#[cfg(feature = "reflect_auto_register")]
registry.register_derived_types();
#[cfg(not(feature = "reflect_auto_register"))]
{
registry.register::<MyStruct>();
registry.register_type_data::<MyStruct, ReflectFromTemplate>();
registry.register::<MyStructTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectDefault>();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think we should just manually register types in tests. It's simpler, more explicit, and doesn't rely on automatic-registration working properly (in the case reflect_auto_register is enabled).

Suggested change
#[cfg(feature = "reflect_auto_register")]
registry.register_derived_types();
#[cfg(not(feature = "reflect_auto_register"))]
{
registry.register::<MyStruct>();
registry.register_type_data::<MyStruct, ReflectFromTemplate>();
registry.register::<MyStructTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectDefault>();
}
registry.register::<MyStruct>();
registry.register_type_data::<MyStruct, ReflectFromTemplate>();
registry.register::<MyStructTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectTemplate>();
registry.register_type_data::<MyStructTemplate, ReflectDefault>();

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated
);
let my_struct_reflect = reflect_template.build(
&mut template_context,
template.as_partial_reflect(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think we should also be able to automatically upcast like &*template (i.e. dereference the Box). We're working to deprecate these methods (see #21772).

Comment thread crates/bevy_ecs/src/reflect/template.rs Outdated
let my_struct = my_struct_reflect.downcast::<MyStruct>().expect("Should be MyStruct");

assert_eq!(
*my_struct.deref(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The * should be enough to dereference the Box

Suggested change
*my_struct.deref(),
*my_struct,

Self(fns)
}

pub fn fn_pointer(&self) -> &ReflectFromTemplateFns {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Same here, can we make this plural?

Suggested change
pub fn fn_pointer(&self) -> &ReflectFromTemplateFns {
pub fn fn_pointers(&self) -> &ReflectFromTemplateFns {

@MrGVSV MrGVSV added A-Reflection Runtime information about types A-Scenes Composing and serializing ECS objects labels Jul 9, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Reflection Jul 9, 2026
@MrGVSV MrGVSV added C-Feature A new feature, making something new possible D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 9, 2026
@MrGVSV MrGVSV moved this from Needs SME Triage to SME Triaged in Reflection Jul 9, 2026
@MrGVSV MrGVSV added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Reflection Runtime information about types A-Scenes Composing and serializing ECS objects C-Feature A new feature, making something new possible D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged

Projects

Status: SME Triaged

Development

Successfully merging this pull request may close these issues.

2 participants