-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Mitigate stack overflow on large Bundle inserts #20772
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
Changes from all commits
eb9ea33
b6e3bfd
b65945c
4aab60f
14c0669
347b3e3
ed19829
949ffcf
a31ff32
ef6a097
86d0d12
f797072
a6b342f
051c256
c453b08
2f4a5d5
a2aba3e
97b0188
a9d2f3a
ea489e5
13688aa
3bcc2fb
2d38772
46badec
83bd955
63fa898
bc74acf
207ca9a
cc16b6d
57d7fd3
1ac8358
82894f1
ed3ca7e
959fe01
e84cce2
a452621
9043bf6
ed9eb64
c5e4696
0f85d1e
294a9d0
606794e
f659939
23b54f2
607ba15
77d8ce3
a6400c4
00cc71e
2e4670f
ab12802
0fbc2e3
18dca82
205f19b
3da7fb5
5c4afb5
5e1a16e
d7ffbd7
f873b74
5e4034f
5582bf5
72f4001
e9f9356
afd4b86
95d81a6
7f0a0d9
31fea98
df5a255
742f70b
bf1542a
3514457
bc02b40
bf882d3
b051573
eb12baf
96b15b7
fd06151
4b5789b
877b2d2
32b38d0
1e2c514
afb4a29
d618a30
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| use bevy_ecs::prelude::*; | ||
|
|
||
| #[derive(Component, Debug)] | ||
| pub struct A(usize); | ||
|
|
||
| // this should fail since destructuring T: Drop cannot be split. | ||
| #[derive(Bundle, Debug)] | ||
| //~^ E0509 | ||
| pub struct DropBundle { | ||
| component_a: A, | ||
| } | ||
|
|
||
| impl Drop for DropBundle { | ||
| fn drop(&mut self) { | ||
| // Just need the impl | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,20 +115,23 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { | |
|
|
||
| let mut active_field_types = Vec::new(); | ||
| let mut active_field_tokens = Vec::new(); | ||
| let mut active_field_alias: Vec<proc_macro2::TokenStream> = Vec::new(); | ||
| let mut inactive_field_tokens = Vec::new(); | ||
| for (((i, field_type), field_kind), field) in field_type | ||
| .iter() | ||
| .enumerate() | ||
| .zip(field_kind.iter()) | ||
| .zip(field.iter()) | ||
| { | ||
| let field_alias = format_ident!("field_{}", i).to_token_stream(); | ||
| let field_tokens = match field { | ||
| Some(field) => field.to_token_stream(), | ||
| None => Index::from(i).to_token_stream(), | ||
| }; | ||
| match field_kind { | ||
| BundleFieldKind::Component => { | ||
| active_field_types.push(field_type); | ||
| active_field_alias.push(field_alias); | ||
| active_field_tokens.push(field_tokens); | ||
| } | ||
|
|
||
|
|
@@ -163,16 +166,46 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { | |
| }; | ||
|
|
||
| let dynamic_bundle_impl = quote! { | ||
| #[allow(deprecated)] | ||
| #[doc(hidden)] | ||
| #[expect(dead_code, reason = "This is a static assertion.")] | ||
| impl #impl_generics #struct_name #ty_generics #where_clause { | ||
| // Types that implement `Drop` cannot have their fields moved out. The implementation in | ||
| // `get_componments` avoids this with pointers, so there needs to be a static assertion | ||
| // that this is a sound thing to do. See https://doc.rust-lang.org/error_codes/E0509.html | ||
| // for more information. | ||
| fn check_no_bundle_drop(self) { | ||
| // This has no effect, but we need to make sure the compiler doesn't optimize it out | ||
| // black_box is used to do this | ||
| #( core::hint::black_box(self.#active_field_tokens); )* | ||
| } | ||
| } | ||
|
|
||
| impl #impl_generics #ecs_path::bundle::DynamicBundle for #struct_name #ty_generics #where_clause { | ||
| type Effect = (); | ||
| #[allow(unused_variables)] | ||
| #[inline] | ||
| fn get_components( | ||
| self, | ||
| unsafe fn get_components( | ||
| ptr: #ecs_path::ptr::MovingPtr<'_, Self>, | ||
| func: &mut impl FnMut(#ecs_path::component::StorageType, #ecs_path::ptr::OwningPtr<'_>) | ||
| ) { | ||
| #(<#active_field_types as #ecs_path::bundle::DynamicBundle>::get_components(self.#active_field_tokens, &mut *func);)* | ||
| use #ecs_path::__macro_exports::DebugCheckedUnwrap; | ||
|
|
||
| #( let #active_field_alias = ptr.move_field(|ptr| &raw mut (*ptr).#active_field_tokens); )* | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this doing the same thing as
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The macro isn't quite flexible enough to support both normal structts and tuple structs, hence why there's the usage of |
||
| core::mem::forget(ptr); | ||
| #( | ||
| <#active_field_types as #ecs_path::bundle::DynamicBundle>::get_components( | ||
| #active_field_alias.try_into().debug_checked_unwrap(), | ||
| func | ||
| ); | ||
| )* | ||
| } | ||
|
|
||
| #[allow(unused_variables)] | ||
| #[inline] | ||
| unsafe fn apply_effect( | ||
| ptr: #ecs_path::ptr::MovingPtr<'_, core::mem::MaybeUninit<Self>>, | ||
| func: &mut #ecs_path::world::EntityWorldMut<'_>, | ||
| ) { | ||
| } | ||
| } | ||
| }; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.