-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypePath required for generic #[reflect(ignore)] field #9094
Comments
Unfortunately, this cannot be lifted. The new, stable type paths require that all generics also implement The solution would probably be for LWIM to add |
That's what I figured, thought I'd ask though just in case. Thanks for the confirmation! I doubt this will be an issue for any LWIM users since they will likely just be using their own enum, they can just derive reflect on if they haven't already. Hopefully cases where crates don't own either type can find a work around, I'd guess make a wrapper struct and manually implement TypePath? Is this something worth mentioning in the migration guide? https://bevyengine.org/learn/migration-guides/0.10-0.11/#bevy-reflect-stable-type-path-v2 |
Created a PR for the migration guide, don't think there's anything else to do here so I'll close this. I welcome feedback on that PR: bevyengine/bevy-website#698 |
I'm actually going to re-open this issue because I think we may want to consider adding alternative options for when types cannot possibly implement For such scenarios, we have a couple options:
1 is annoying but currently possible. I think 2 is feasible, but would require more work to properly generate the I personally don't think 3 is the way to go, but it's an option. |
Option 3 won't really work for types that are meant to be generic and not clash, so that information has to be present somehow. Option 2 seems like the 'safest' bet, but as long as it can be 'contained' to just the part that has been opted out. I don't know whether for the case of So, just how unstable is |
# Objective Fixes #9094 ## Solution Takes a bit from [this](#9094 (comment)) comment as well as a [comment](https://discord.com/channels/691052431525675048/1002362493634629796/1128024873260810271) from @soqb. This allows users to opt-out of the `TypePath` implementation that is automatically generated by the `Reflect` derive macro, allowing custom `TypePath` implementations. ```rust #[derive(Reflect)] #[reflect(type_path = false)] struct Foo<T> { #[reflect(ignore)] _marker: PhantomData<T>, } struct NotTypePath; impl<T: 'static> TypePath for Foo<T> { fn type_path() -> &'static str { std::any::type_name::<Self>() } fn short_type_path() -> &'static str { static CELL: GenericTypePathCell = GenericTypePathCell::new(); CELL.get_or_insert::<Self, _>(|| { bevy_utils::get_short_name(std::any::type_name::<Self>()) }) } fn crate_name() -> Option<&'static str> { Some("my_crate") } fn module_path() -> Option<&'static str> { Some("my_crate::foo") } fn type_ident() -> Option<&'static str> { Some("Foo") } } // Can use `TypePath` let _ = <Foo<NotTypePath> as TypePath>::type_path(); // Can register the type let mut registry = TypeRegistry::default(); registry.register::<Foo<NotTypePath>>(); ``` #### Type Path Stability The stability of type paths mainly come into play during serialization. If a type is moved between builds, an unstable type path may become invalid. Users that opt-out of `TypePath` and rely on something like `std::any::type_name` as in the example above, should be aware that this solution removes the stability guarantees. Deserialization thus expects that type to never move. If it does, then the serialized type paths will need to be updated accordingly. If a user depends on stability, they will need to implement that stability logic manually (probably by looking at the expanded output of a typical `Reflect`/`TypePath` derive). This could be difficult for type parameters that don't/can't implement `TypePath`, and will need to make heavy use of string parsing and manipulation to achieve the same effect (alternatively, they can choose to simply exclude any type parameter that doesn't implement `TypePath`). --- ## Changelog - Added the `#[reflect(type_path = false)]` attribute to opt out of the `TypePath` impl when deriving `Reflect` --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Fixes #9094 Takes a bit from [this](#9094 (comment)) comment as well as a [comment](https://discord.com/channels/691052431525675048/1002362493634629796/1128024873260810271) from @soqb. This allows users to opt-out of the `TypePath` implementation that is automatically generated by the `Reflect` derive macro, allowing custom `TypePath` implementations. ```rust struct Foo<T> { #[reflect(ignore)] _marker: PhantomData<T>, } struct NotTypePath; impl<T: 'static> TypePath for Foo<T> { fn type_path() -> &'static str { std::any::type_name::<Self>() } fn short_type_path() -> &'static str { static CELL: GenericTypePathCell = GenericTypePathCell::new(); CELL.get_or_insert::<Self, _>(|| { bevy_utils::get_short_name(std::any::type_name::<Self>()) }) } fn crate_name() -> Option<&'static str> { Some("my_crate") } fn module_path() -> Option<&'static str> { Some("my_crate::foo") } fn type_ident() -> Option<&'static str> { Some("Foo") } } // Can use `TypePath` let _ = <Foo<NotTypePath> as TypePath>::type_path(); // Can register the type let mut registry = TypeRegistry::default(); registry.register::<Foo<NotTypePath>>(); ``` The stability of type paths mainly come into play during serialization. If a type is moved between builds, an unstable type path may become invalid. Users that opt-out of `TypePath` and rely on something like `std::any::type_name` as in the example above, should be aware that this solution removes the stability guarantees. Deserialization thus expects that type to never move. If it does, then the serialized type paths will need to be updated accordingly. If a user depends on stability, they will need to implement that stability logic manually (probably by looking at the expanded output of a typical `Reflect`/`TypePath` derive). This could be difficult for type parameters that don't/can't implement `TypePath`, and will need to make heavy use of string parsing and manipulation to achieve the same effect (alternatively, they can choose to simply exclude any type parameter that doesn't implement `TypePath`). --- - Added the `#[reflect(type_path = false)]` attribute to opt out of the `TypePath` impl when deriving `Reflect` --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Bevy version
Bevy 0.11
What you did
I'm working on a PR to update leafwing-input-manager: Leafwing-Studios/leafwing-input-manager#364
What went wrong
Leafwing input manager has a struct ActionState that takes a generic that is used on a
#[reflect(ignore)]
PhantomData field:We are getting an error when registering this type with bevy saying our generic type must implement TypePath.
This seems potentially limiting to the end users of LWIM and I'm not sure it was intended as it isn't mentioned in migration guides.
Is this restriction something that could be lifted?
Additional info
There's a conversation about this on the LWIM PR starting here:
Leafwing-Studios/leafwing-input-manager#364 (comment)
To try this out, you can checkout the branch for that PR and remove the TypePath requirement I added from this line:
https://github.com/Leafwing-Studios/leafwing-input-manager/blob/7fb55b001a4aa949b1863dd2e0007d9512960625/src/lib.rs#L81
Here's the line and error we are getting:
https://github.com/Leafwing-Studios/leafwing-input-manager/blob/dfbe44b22fae01434737fb498dfb10d5ca20057d/src/plugin.rs#L146
The text was updated successfully, but these errors were encountered: