bevy_ecs: add untyped methods for inserting components and bundles
Objective
- #4447 implemented untyped (using component ids instead of generics and
TypeId) APIs for inserting/accessing resources and accessing components, but left inserting components for another PR (this one)
Solution
- add
EntityMut::{insert_by_id, insert_bundle_by_id} - split
BundleintoDynamicBundlewithget_componentsandBundle: DynamicBundle. This allows theBundleInsertermachinery to be reused for bundles that can only be written, not read, and have no statically availableComponentIds - add
Bundles::bundle_ids_dynamic: HashMap<Vec<ComponentId>, BundleId>next to theHashMap<TypeId, BundleId>
Changelog
- add methods for inserting bundles and components to:
world.entity_mut(entity).insert_bundle_by_id/insert_by_id
Unresolved questions
-
can we get rid of some allocations?
-
init_info_dynamiccould remove a.clone()of aVec<ComponentId>whenHashMap::raw_entrystabilizes -
insert_by_idcould not reuseinsert_bundle_by_idto avoid theVecoverhead, or alternativelyinsert_bundle_by_idcould maybe be changed to not require theVecfor theOwningPtrs
-
-
currently
insert_bundle_by_idsrequires takes aVec<ComponentId>that must be sorted and aVec<OwningPtr<'_>that must match the component ids. This is because internally we also need theVec<ComponentId>so if the caller already has it we can just use that.- should we just accept a
&[(ComponentId, OwningPtr<'_>)]and internally collect that into a sorted vec of component ids? - [x] alternatively, should we sort the
ComponentIdvec in the function so that we don't have such a subtle safety requirement? sorting an already sorted vec is the best case scenario for insertion sort (which is used forstdsort for <=20 elements) so it's just a smallO(n)cost
- should we just accept a
Pining here to see if there is any plans to pursue this PR? I wanted to pick up #5074 however, it relies on a DynamicBundle like interface (which is what this PR provides). I can always adopt this PR, at the discretion of @jakobhellermann of course.
ping @jakobhellermann Any plans to move forward w/ this PR? I'm more than happy to take it over if that's easier.
ping @jakobhellermann Any plans to move forward w/ this PR? I'm more than happy to take it over if that's easier.
Sorry for not responding earlier. I'm a bit busy with Uni right now but feel free to adopt this PR.
I rebased the PR and adressed the review comments.
It's not quite ready for review yet because I made the DynamicBundle trait safe because I noticed that it had no actual safety requirements anymore and need to properly think about it to make sure that is correct. Also I don't know if Drop logic is correct right now, so I need to look into that as well. I will do both tomorrow probably.
rebased the PR
This PR looks amazing and is super helpful!
I was looking into implementing something similar and would like to throw a suggestion up for discussion,
Would it be possible to move the ComponentId correctness check into init_info_dynamic which could be made safe and public?
The resulting BundleId could be stored by the user and used in fn insert_bundle_by_ids(&mut self, bundle_id, ...).
This would have the added benefit of being able to remove bundle_ids_dynamic, and init_info_dynamic would document that all dynamic queries will be assigned a unique BundleId (this is akin to what happens to "Components::init_component_with_descriptor").
Could rename init_info_dynamic to init_dynamic_bundle.
EDIT: Dumped the changes in https://github.com/jakobhellermann/bevy/pull/69
Controversial because we need to decide between this and #7204 :)