Introduce ReflectConvert, a generic reflection mechanism for type conversions, intended for asset BSN.#23742
Open
pcwalton wants to merge 6 commits intobevyengine:mainfrom
Open
Introduce ReflectConvert, a generic reflection mechanism for type conversions, intended for asset BSN.#23742pcwalton wants to merge 6 commits intobevyengine:mainfrom
ReflectConvert, a generic reflection mechanism for type conversions, intended for asset BSN.#23742pcwalton wants to merge 6 commits intobevyengine:mainfrom
Conversation
conversions, intended for asset BSN.
One of the important features of BSN is that supplying a value of type T
where a value of type U is expected is allowed if a `From` conversion
exists from T to U. This is what allows `HandleTemplate`s to be
automatically created from string literals. We need this feature for BSN
like this to be valid:
```rust
SceneRoot("models/FlightHelmet/FlightHelmet.gltf#Scene0")
```
And for this to be valid:
```rust
EnvironmentMapLight {
diffuse_map: "environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2",
specular_map: "environment_maps/pisa_specular_rgb9e5_zstd.ktx2",
intensity: 250.0,
}
```
Unfortunately, the `From` trait isn't reflectable, and this is a problem
as reflection drives asset BSN. It's not immediately clear how to make
`From` reflectable either, as a syntax like `#[reflect(From)]` wouldn't
work as it's a generic trait.
Instead of making `From` directly reflectable, this patch introduces
`ReflectConvert`, a new `TypeData` that encodes a generic way to convert
a value of type T to type U. You register a type conversion like this:
```rust
App::new()
.register_type::<i32>()
.register_type::<String>()
.register_type_conversion::<i32, String>(|n| Ok(n.into()));
```
And you invoke the conversion like this:
```rust
let reflect_convert = registry
.get_type_data::<ReflectConvert>(TypeId::of::<String>())
.unwrap();
let converted = reflect_convert
.try_convert_from(Box::new(12345i32))
.unwrap()
.downcast::<String>()
.unwrap();
```
I tested `ReflectConvert` with asset BSN (PR bevyengine#23576). The
`ReflectConvert` trait as implemented in this patch successfully enables
`HandleTemplate`s to be created from strings, without hard-coding
`HandleTemplate` anywhere in the patch generation logic.
andriyDev
approved these changes
Apr 9, 2026
| /// | ||
| /// See [`bevy_reflect::TypeRegistry::register_type_conversion`]. | ||
| #[cfg(feature = "bevy_reflect")] | ||
| pub fn register_type_conversion<T, U>(&mut self, function: fn(T) -> Result<U, T>) -> &mut Self |
Contributor
There was a problem hiding this comment.
I wonder if we should have a register_into_type_conversion that just does the into for you? I suspect most calls to this will just be into.
Contributor
Author
There was a problem hiding this comment.
Yeah, I was considering that too. In an earlier version you were just able to write .register_type_conversion::<T,U>(Into::into) but I realized that was incompatible with fallible conversions, and I'm pretty sure we do want fallible conversions.
Contributor
There was a problem hiding this comment.
To clarify: I meant provide both: the into is just a convenience for calling the more general TryInto
Contributor
Author
There was a problem hiding this comment.
I added register_into_type_conversion as requested.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One of the important features of BSN is that supplying a value of type T where a value of type U is expected is allowed if a
Fromconversion exists from T to U. This is what allowsHandleTemplates to be automatically created from string literals. We need this feature for BSN like this to be valid:And for this to be valid:
Unfortunately, the
Fromtrait isn't reflectable, and this is a problem as reflection drives asset BSN. It's not immediately clear how to makeFromreflectable either, as a syntax like#[reflect(From)]wouldn't work as it's a generic trait.Instead of making
Fromdirectly reflectable, this patch introducesReflectConvert, a newTypeDatathat encodes a generic way to convert a value of type T to type U. You register a type conversion like this:And you invoke the conversion like this:
I tested
ReflectConvertwith asset BSN (PR #23576). TheReflectConverttrait as implemented in this patch successfully enablesHandleTemplates to be created from strings, without hard-codingHandleTemplateanywhere in the patch generation logic.