-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Get Component's dyn Trait by ComponentId #9837
base: main
Are you sure you want to change the base?
Conversation
crates/bevy_ecs/src/reflect/world.rs
Outdated
use crate::prelude::{AppTypeRegistry, World}; | ||
|
||
/// An extension trait for World for reflection related functions | ||
pub trait WorldExt { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like having these methods stored separately, but I don't really see the point of the trait extension method rather than just another impl block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I referred to ReflectCommandExt
, and these methods depend on AppTypeRegistry
, so I also defined a WorldExt
, which I'm not sure is better
return None; | ||
}; | ||
|
||
let type_registry = self.resource::<AppTypeRegistry>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be a get_resource
, with a ?
operator again. No need to introduce panics.
/// This trait can be implemented automatically by the `#[reflect_trait]` macro, | ||
/// | ||
/// If you implement [`TypeData`] for your component yourself, you should also implement this trait if you need to dynamically get the dyn object | ||
pub trait ReflectFnsTypeData: TypeData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a huge fan of creating a new trait, but I understand why it might be useful.
However, if we decide to add this, I feel like the name should reflect the specific kind of type data we're dealing with here, which are reflected traits. (The other kind would be custom type data, which may represent traits but do not convert a dyn Reflect
into a dyn Trait
.)
Perhaps, we rename this to TraitTypeData
? Or maybe even just TraitObject
?
Ping @JoJoJet because they made |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer defer on JoJoJet for whether this should be added or not.
/// | ||
/// If you implement [`TypeData`] for your component yourself, you should also implement this trait if you need to dynamically get the dyn object | ||
pub trait ReflectFnsTypeData: TypeData { | ||
type Dyn: ?Sized; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This breaks when the TypeData
doesn't have an associated trait. For example in https://lib.rs/crates/cuicui_reflect_query, Queryable
is not a trait. It would stop compiling, and I don't think it's an isolated use-case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeData
can choose not to implement this trait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why I think renaming this trait would help clarify its intent
I cleaned up all the clearly resolved conversations for you :) @ycysdf, feel free to do that yourself in the future on your Bevy PRs as you submit fixes: it really helps reviewers understand what's outstanding. |
@alice-i-cecile thank you |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am mostly unfamiliar with the bevy's reflection system, since I used my own registry in order to implement bevy-trait-query
, which let me optimize single-item trait queries to be nearly as fast as concrete type queries. One benefit of the approach used in this PR is that is plays more nicely with reflection, since trait impls will be registered along with the type -- compare this to bevy-trait-query
, where each trait impl currently needs to be registered separately, even when the type itself has already been registered. However, I don't know what the performance implications of doing it this way are -- since this PR does not attempt to implement queries, I take it that performance is not a priority here.
One syntactic concern I have is the use of auto-generated reflect types for traits. If I have
#[reflect_trait]
trait MyTrait {}
I would get a trait object by calling
world.get_dyn_mut_by_id::<ReflectMyTrait>(entity, component_id);
I believe it would be more intuitive if this instead looked like
world.get_dyn_mut_by_id::<dyn MyTrait>(entity, component_id);
Would this change be doable?
Good Idea ! I tried to implement it, but the solution needed to add a new Trait 'TraitTypeDataRelevance' |
Now can get the world.get_dyn_mut_by_id::<ReflectMyTrait>(entity, component_id); and world.get_dyn_mut_by_id::<dyn MyTrait>(entity, component_id); |
@JoJoJet I think the trait query of 'bevy-trait query' is very good |
/// Associate a `TraitTypeData` | ||
pub trait TraitTypeDataRelevance { | ||
type TypeData: TraitTypeData; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably needs more documentation considering manual implementors may want to make use of it.
@@ -599,6 +602,39 @@ impl<T: Reflect> FromType<T> for ReflectFromPtr { | |||
} | |||
} | |||
|
|||
/// Associate a `TraitTypeData` | |||
pub trait TraitTypeDataRelevance { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshed: I think a name like AsoociatedTypeData
, TypeDataAssoc
, TypeDataMapper
, etc. would be more indicative of how this is meant to be used.
Additionally, I think we can leave out the Trait
part of the name since this doesn't necessarily need to be used for dyn Trait
. For example, a user could associate a Player
struct type with a ReflectPlayerSettings
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rename to TyepDataMapper
and update TypeDataMapper::TypeData
bound to TypeData
. I feel better about it.
crates/bevy_ecs/src/reflect/world.rs
Outdated
} | ||
|
||
/// Retrieves an immutable `dyn T` reference to the given entity's Component of the given [`ComponentId`] | ||
pub fn get_dyn_by_id<T: TraitTypeDataRelevance + ?Sized>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to add the ?Sized
bound as a supertrait of TraitTypeDataRelevance
? Or does that not work/isn't desirable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't work unfortunately. The implicit Sized
bound comes from the type parameter T
, not from the trait. All traits can have ?Sized
implementors, unless you explicitly add a Sized
bound on the trait definition.
Objective
Component
's dyn Trait byComponentId
Solution
TraitTypeData
trait. This trait associates the trait object corresponding toTypeData
Changelog
TypeDataMapper
trait. It map a type to aTraitTypeData
. This trait is implemented automatically by#[reflect_trait]
. It mapdyn MyTrait
maps toReflectMyTrait
.Migration Guide
get
,get_mut
,get_boxed
move onto the trait, Need to import theuse bevy: : reflect: : TraitTypeData ;