Skip to content

Bundle refactor - Option bundles and Box<dyn Bundle> #19491

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

Draft
wants to merge 50 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
646c0d1
Introduce StaticBundle
SkiFire13 Jun 2, 2025
bc76283
Switch register_bundle to StaticBundle
SkiFire13 Jun 2, 2025
50a8670
Switch Entity{Ref,Mut}Except to StaticBundle
SkiFire13 Jun 2, 2025
762f525
Switch EntityClonerBuilder to StaticBundle
SkiFire13 Jun 2, 2025
c482ee0
Switch Observer and Trigger to StaticBundle
SkiFire13 Jun 2, 2025
89f9530
Switch component removal to StaticBundle
SkiFire13 Jun 2, 2025
8d3991d
Switch EntityWorldMut::retain to StaticBundle
SkiFire13 Jun 2, 2025
77688c9
Require StaticBundle in batch spawning
SkiFire13 Jun 2, 2025
6cd5783
Require StaticBundle in ReflectBundle
SkiFire13 Jun 2, 2025
c9ceb5a
Require StaticBundle in ExtractComponent
SkiFire13 Jun 2, 2025
756aeea
Add IS_STATIC and IS_BOUNDED flags to Bundle
SkiFire13 Jun 2, 2025
b875cb4
Add cache_key method to Bundle
SkiFire13 Jun 2, 2025
6daa55f
Add component_ids taking &self to Bundle
SkiFire13 Jun 2, 2025
a22c29b
Add register_required_components taking &self to Bundle
SkiFire13 Jun 2, 2025
f9eb711
Rename Bundles::bundle_ids to Bundles::static_bundle_ids
SkiFire13 Jun 2, 2025
977be66
Rename Bundles::register_info to register_static_info and add more dy…
SkiFire13 Jun 2, 2025
cce6806
Convert BundleInserter to using the new register_info
SkiFire13 Jun 2, 2025
1dfd29c
Rename World::register_bundle to World::register_static_bundle
SkiFire13 Jun 2, 2025
1931130
Rename register_contributed_bundle_info to register_static_contribute…
SkiFire13 Jun 2, 2025
26d8fc8
Add missing safety comments
SkiFire13 Jun 2, 2025
787c168
No longer require Bundle: StaticBundle
SkiFire13 Jun 2, 2025
a2ab6f4
Improve error message for an invalid dynamic Bundle
SkiFire13 Jun 2, 2025
d39bee2
WIP Implement Bundle for Option<T: Bundle>
SkiFire13 Jun 2, 2025
3167fc3
Simplify Bundle macro implementation
SkiFire13 Jun 3, 2025
2e6997c
Fix bug when #[bundle(ignore)] is followed by another one
SkiFire13 Jun 3, 2025
cded294
Add support for #[bundle(dynamic)] attribute
SkiFire13 Jun 3, 2025
1b0b20c
Add simple test for Option bundles
SkiFire13 Jun 3, 2025
22eb8a3
Switch IS_STATIC and IS_BOUNDED to associated functions
SkiFire13 Jun 4, 2025
fa493ce
Rename DynamicBundle to ComponentsFromBundle
SkiFire13 Jun 4, 2025
f64aa7a
(WIP) Implement Bundle for Box<dyn Bundle>
SkiFire13 Jun 4, 2025
a662e60
Fix formatting & doc issues
SkiFire13 Jun 4, 2025
0fddef0
Fix other CI issues
SkiFire13 Jun 4, 2025
086c12d
Improve docs and safety comments
SkiFire13 Jun 4, 2025
afdb838
Simplify Bundle derive implementation a bit more
SkiFire13 Jun 4, 2025
e308c16
Fix typo
SkiFire13 Jun 4, 2025
41f3152
Implement Bundle for Vec<Box<dyn Bundle>>
SkiFire13 Jun 5, 2025
1140ace
Add some tests
SkiFire13 Jun 5, 2025
a2139bb
Add benchmarks for bundles
SkiFire13 Jun 7, 2025
335c9d2
Add BoundedBundleKey to simplify implementations of cache_key
SkiFire13 Jun 7, 2025
b902d5f
Add migration guide
SkiFire13 Jun 7, 2025
275f14a
Add release notes
SkiFire13 Jun 7, 2025
0276d68
Implement ReflectBundle::get_boxes
SkiFire13 Jun 7, 2025
1b141b3
Add more benchmarks
SkiFire13 Jun 8, 2025
6c28eb4
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 9, 2025
7d18aa3
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 10, 2025
5b089f5
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 12, 2025
4a86893
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 12, 2025
5446247
Fix imports and re-exports
SkiFire13 Jun 12, 2025
385d1f0
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 13, 2025
a075fc5
Merge remote-tracking branch 'upstream/main' into new-bundle
SkiFire13 Jun 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions benches/benches/bevy_ecs/bundles/insert_many.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use benches::bench;
use bevy_ecs::{component::Component, world::World};
use criterion::Criterion;

const ENTITY_COUNT: usize = 2_000;

#[derive(Component)]
struct C<const N: usize>(usize);

#[derive(Component)]
struct W<T>(T);

pub fn insert_many(criterion: &mut Criterion) {
let mut group = criterion.benchmark_group(bench!("insert_many"));

group.bench_function("all", |bencher| {
bencher.iter(|| {
let mut world = World::new();
for _ in 0..ENTITY_COUNT {
world
.spawn_empty()
.insert(C::<0>(1))
.insert(C::<1>(1))
.insert(C::<2>(1))
.insert(C::<3>(1))
.insert(C::<4>(1))
.insert(C::<5>(1))
.insert(C::<6>(1))
.insert(C::<7>(1))
.insert(C::<8>(1))
.insert(C::<9>(1))
.insert(C::<10>(1))
.insert(C::<11>(1))
.insert(C::<12>(1))
.insert(C::<13>(1))
.insert(C::<14>(1));
}
});
});

group.bench_function("only_last", |bencher| {
bencher.iter(|| {
let mut world = World::new();
for _ in 0..ENTITY_COUNT {
world
.spawn((
C::<0>(1),
C::<1>(1),
C::<2>(1),
C::<3>(1),
C::<4>(1),
C::<5>(1),
C::<6>(1),
C::<7>(1),
C::<8>(1),
C::<9>(1),
C::<10>(1),
C::<11>(1),
C::<12>(1),
C::<13>(1),
))
.insert(C::<14>(1));
}
});
});

group.finish();
}
63 changes: 63 additions & 0 deletions benches/benches/bevy_ecs/bundles/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use bevy_ecs::{
bundle::{BoundedBundleKey, Bundle, ComponentsFromBundle},
component::{ComponentId, ComponentsRegistrator, RequiredComponents, StorageType},
ptr::OwningPtr,
};
use criterion::criterion_group;

mod insert_many;
mod spawn_many;
mod spawn_many_zst;
mod spawn_one_zst;

criterion_group!(
benches,
spawn_one_zst::spawn_one_zst,
spawn_many_zst::spawn_many_zst,
spawn_many::spawn_many,
insert_many::insert_many,
);

struct MakeDynamic<B>(B);

// SAFETY:
// - setting is_static and is_bounded to false is always safe and makes cache_key irrelevant
// - everything else is delegated to B, which is a valid Bundle
unsafe impl<B: Bundle> Bundle for MakeDynamic<B> {
fn is_static() -> bool {
false
}

fn is_bounded() -> bool {
false
}

fn cache_key(&self) -> BoundedBundleKey {
BoundedBundleKey::empty()
}

fn component_ids(
&self,
components: &mut ComponentsRegistrator,
ids: &mut impl FnMut(ComponentId),
) {
self.0.component_ids(components, ids);
}

fn register_required_components(
&self,
components: &mut ComponentsRegistrator,
required_components: &mut RequiredComponents,
) {
self.0
.register_required_components(components, required_components);
}
}

impl<B: ComponentsFromBundle> ComponentsFromBundle for MakeDynamic<B> {
type Effect = <B as ComponentsFromBundle>::Effect;

fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) -> Self::Effect {
self.0.get_components(func)
}
}
Loading