1use core::{any::TypeId, iter};
23use bevy_ptr::{MovingPtr, OwningPtr};
4use core::mem::MaybeUninit;
5use variadics_please::all_tuples_enumerated;
67use crate::{
8 bundle::{Bundle, BundleFromComponents, DynamicBundle, NoBundleEffect},
9 component::{Component, ComponentId, Components, ComponentsRegistrator, StorageType},
10world::EntityWorldMut,
11};
1213// SAFETY:
14// - `Bundle::component_ids` calls `ids` for C's component id (and nothing else)
15// - `Bundle::get_components` is called exactly once for C and passes the component's storage type based on its associated constant.
16unsafe impl<C: Component> Bundlefor C {
17fn component_ids(
18 components: &mut ComponentsRegistrator,
19 ) -> impl Iterator<Item = ComponentId> + use<C> {
20 iter::once(components.register_component::<C>())
21 }
2223fn get_component_ids(components: &Components) -> impl Iterator<Item = Option<ComponentId>> {
24 iter::once(components.get_id(TypeId::of::<C>()))
25 }
26}
2728// SAFETY:
29// - `Bundle::from_components` calls `func` exactly once for C, which is the exact value returned by `Bundle::component_ids`.
30unsafe impl<C: Component> BundleFromComponentsfor C {
31unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
32where
33// Ensure that the `OwningPtr` is used correctly
34F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
35Self: Sized,
36 {
37let ptr = func(ctx);
38// Safety: The id given in `component_ids` is for `Self`
39unsafe { ptr.read() }
40 }
41}
4243impl<C: Component> DynamicBundlefor C {
44type Effect = ();
45#[inline]
46unsafe fn get_components(
47 ptr: MovingPtr<'_, Self>,
48 func: &mut impl FnMut(StorageType, OwningPtr<'_>),
49 ) -> Self::Effect {
50func(C::STORAGE_TYPE, OwningPtr::from(ptr));
51 }
5253#[inline]
54unsafe fn apply_effect(_ptr: MovingPtr<'_, MaybeUninit<Self>>, _entity: &mut EntityWorldMut) {}
55}
5657macro_rules! tuple_impl {
58 ($(#[$meta:meta])* $(($index:tt, $name: ident, $alias: ident)),*) => {
59#[expect(
60 clippy::allow_attributes,
61 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
62)]
63 #[allow(
64 unused_mut,
65 unused_variables,
66 reason = "Zero-length tuples won't use any of the parameters."
67)]
68$(#[$meta])*
69// SAFETY:
70 // - `Bundle::component_ids` calls `ids` for each component type in the
71 // bundle, in the exact order that `DynamicBundle::get_components` is called.
72 // - `Bundle::from_components` calls `func` exactly once for each `ComponentId` returned by `Bundle::component_ids`.
73 // - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
74 // `StorageType` into the callback.
75unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
76fn component_ids<'a>(components: &'a mut ComponentsRegistrator) -> impl Iterator<Item = ComponentId> + use<$($name,)*> {
77 iter::empty()$(.chain(<$name as Bundle>::component_ids(components)))*
78 }
7980fn get_component_ids(components: &Components) -> impl Iterator<Item = Option<ComponentId>> {
81 iter::empty()$(.chain(<$name as Bundle>::get_component_ids(components)))*
82 }
83 }
8485#[expect(
86 clippy::allow_attributes,
87 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
88)]
89 #[allow(
90 unused_mut,
91 unused_variables,
92 reason = "Zero-length tuples won't use any of the parameters."
93)]
94$(#[$meta])*
95// SAFETY:
96 // - `Bundle::component_ids` calls `ids` for each component type in the
97 // bundle, in the exact order that `DynamicBundle::get_components` is called.
98 // - `Bundle::from_components` calls `func` exactly once for each `ComponentId` returned by `Bundle::component_ids`.
99 // - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
100 // `StorageType` into the callback.
101unsafe impl<$($name: BundleFromComponents),*> BundleFromComponents for ($($name,)*) {
102#[allow(
103 clippy::unused_unit,
104 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
105)]
106unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
107where
108F: FnMut(&mut T) -> OwningPtr<'_>
109 {
110#[allow(
111 unused_unsafe,
112 reason = "Zero-length tuples will not run anything in the unsafe block. Additionally, rewriting this to move the () outside of the unsafe would require putting the safety comment inside the tuple, hurting readability of the code."
113)]
114// SAFETY: Rust guarantees that tuple calls are evaluated 'left to right'.
115 // https://doc.rust-lang.org/reference/expressions.html#evaluation-order-of-operands
116unsafe { ($(<$name as BundleFromComponents>::from_components(ctx, func),)*) }
117 }
118 }
119120#[expect(
121 clippy::allow_attributes,
122 reason = "This is a tuple-related macro; as such, the lints below may not always apply."
123)]
124 #[allow(
125 unused_mut,
126 unused_variables,
127 reason = "Zero-length tuples won't use any of the parameters."
128)]
129$(#[$meta])*
130impl<$($name: Bundle),*> DynamicBundle for ($($name,)*) {
131type Effect = ($($name::Effect,)*);
132#[allow(
133 clippy::unused_unit,
134 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
135)]
136 #[inline(always)]
137unsafe fn get_components(ptr: MovingPtr<'_, Self>, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
138bevy_ptr::deconstruct_moving_ptr!({
139let tuple { $($index: $alias,)* } = ptr;
140 });
141#[allow(
142 unused_unsafe,
143 reason = "Zero-length tuples will generate a function body equivalatent to (); however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
144)]
145// SAFETY: Caller ensures requirements for calling `get_components` are met.
146unsafe {
147 $( $name::get_components($alias, func); )*
148 }
149 }
150151#[allow(
152 clippy::unused_unit,
153 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
154)]
155 #[inline(always)]
156unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
157bevy_ptr::deconstruct_moving_ptr!({
158let MaybeUninit::<tuple> { $($index: $alias,)* } = ptr;
159 });
160#[allow(
161 unused_unsafe,
162 reason = "Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
163)]
164// SAFETY: Caller ensures requirements for calling `apply_effect` are met.
165unsafe {
166 $( $name::apply_effect($alias, entity); )*
167 }
168 }
169 }
170171 $(#[$meta])*
172impl<$($name: NoBundleEffect),*> NoBundleEffect for ($($name,)*) {}
173 }
174}
175176#[expect(clippy :: allow_attributes, reason =
"This is a tuple-related macro; as such, the lints below may not always apply.")]
#[allow(unused_mut, unused_variables, reason =
"Zero-length tuples won't use any of the parameters.")]
#[doc(hidden)]
unsafe impl<B0: Bundle, B1: Bundle, B2: Bundle, B3: Bundle, B4: Bundle,
B5: Bundle, B6: Bundle, B7: Bundle, B8: Bundle, B9: Bundle, B10: Bundle,
B11: Bundle, B12: Bundle, B13: Bundle, B14: Bundle> Bundle for
(B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14) {
fn component_ids<'a>(components: &'a mut ComponentsRegistrator)
->
impl Iterator<Item = ComponentId> +
use<B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13,
B14> {
iter::empty().chain(<B0 as
Bundle>::component_ids(components)).chain(<B1 as
Bundle>::component_ids(components)).chain(<B2 as
Bundle>::component_ids(components)).chain(<B3 as
Bundle>::component_ids(components)).chain(<B4 as
Bundle>::component_ids(components)).chain(<B5 as
Bundle>::component_ids(components)).chain(<B6 as
Bundle>::component_ids(components)).chain(<B7 as
Bundle>::component_ids(components)).chain(<B8 as
Bundle>::component_ids(components)).chain(<B9 as
Bundle>::component_ids(components)).chain(<B10 as
Bundle>::component_ids(components)).chain(<B11 as
Bundle>::component_ids(components)).chain(<B12 as
Bundle>::component_ids(components)).chain(<B13 as
Bundle>::component_ids(components)).chain(<B14 as
Bundle>::component_ids(components))
}
fn get_component_ids(components: &Components)
-> impl Iterator<Item = Option<ComponentId>> {
iter::empty().chain(<B0 as
Bundle>::get_component_ids(components)).chain(<B1 as
Bundle>::get_component_ids(components)).chain(<B2 as
Bundle>::get_component_ids(components)).chain(<B3 as
Bundle>::get_component_ids(components)).chain(<B4 as
Bundle>::get_component_ids(components)).chain(<B5 as
Bundle>::get_component_ids(components)).chain(<B6 as
Bundle>::get_component_ids(components)).chain(<B7 as
Bundle>::get_component_ids(components)).chain(<B8 as
Bundle>::get_component_ids(components)).chain(<B9 as
Bundle>::get_component_ids(components)).chain(<B10 as
Bundle>::get_component_ids(components)).chain(<B11 as
Bundle>::get_component_ids(components)).chain(<B12 as
Bundle>::get_component_ids(components)).chain(<B13 as
Bundle>::get_component_ids(components)).chain(<B14 as
Bundle>::get_component_ids(components))
}
}
#[expect(clippy :: allow_attributes, reason =
"This is a tuple-related macro; as such, the lints below may not always apply.")]
#[allow(unused_mut, unused_variables, reason =
"Zero-length tuples won't use any of the parameters.")]
#[doc(hidden)]
unsafe impl<B0: BundleFromComponents, B1: BundleFromComponents,
B2: BundleFromComponents, B3: BundleFromComponents,
B4: BundleFromComponents, B5: BundleFromComponents,
B6: BundleFromComponents, B7: BundleFromComponents,
B8: BundleFromComponents, B9: BundleFromComponents,
B10: BundleFromComponents, B11: BundleFromComponents,
B12: BundleFromComponents, B13: BundleFromComponents,
B14: BundleFromComponents> BundleFromComponents for
(B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14) {
#[allow(clippy :: unused_unit, reason =
"Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")]
unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self where
F: FnMut(&mut T) -> OwningPtr<'_> {
#[allow(unused_unsafe, reason =
"Zero-length tuples will not run anything in the unsafe block. Additionally, rewriting this to move the () outside of the unsafe would require putting the safety comment inside the tuple, hurting readability of the code.")]
unsafe {
(<B0 as BundleFromComponents>::from_components(ctx, func),
<B1 as BundleFromComponents>::from_components(ctx, func),
<B2 as BundleFromComponents>::from_components(ctx, func),
<B3 as BundleFromComponents>::from_components(ctx, func),
<B4 as BundleFromComponents>::from_components(ctx, func),
<B5 as BundleFromComponents>::from_components(ctx, func),
<B6 as BundleFromComponents>::from_components(ctx, func),
<B7 as BundleFromComponents>::from_components(ctx, func),
<B8 as BundleFromComponents>::from_components(ctx, func),
<B9 as BundleFromComponents>::from_components(ctx, func),
<B10 as BundleFromComponents>::from_components(ctx, func),
<B11 as BundleFromComponents>::from_components(ctx, func),
<B12 as BundleFromComponents>::from_components(ctx, func),
<B13 as BundleFromComponents>::from_components(ctx, func),
<B14 as BundleFromComponents>::from_components(ctx, func))
}
}
}
#[expect(clippy :: allow_attributes, reason =
"This is a tuple-related macro; as such, the lints below may not always apply.")]
#[allow(unused_mut, unused_variables, reason =
"Zero-length tuples won't use any of the parameters.")]
#[doc(hidden)]
impl<B0: Bundle, B1: Bundle, B2: Bundle, B3: Bundle, B4: Bundle, B5: Bundle,
B6: Bundle, B7: Bundle, B8: Bundle, B9: Bundle, B10: Bundle, B11: Bundle,
B12: Bundle, B13: Bundle, B14: Bundle> DynamicBundle for
(B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14) {
type Effect =
(B0::Effect, B1::Effect, B2::Effect, B3::Effect, B4::Effect,
B5::Effect, B6::Effect, B7::Effect, B8::Effect, B9::Effect,
B10::Effect, B11::Effect, B12::Effect, B13::Effect, B14::Effect);
#[allow(clippy :: unused_unit, reason =
"Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")]
#[inline(always)]
unsafe fn get_components(ptr: MovingPtr<'_, Self>,
func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
let mut ptr: ::bevy_ptr::MovingPtr<_, _> = ptr;
let _ =
||
{
let value = &mut *ptr;
core::hint::black_box((&mut value.0, &mut value.1,
&mut value.2, &mut value.3, &mut value.4, &mut value.5,
&mut value.6, &mut value.7, &mut value.8, &mut value.9,
&mut value.10, &mut value.11, &mut value.12, &mut value.13,
&mut value.14));
fn unreachable<T>(_index: usize) -> T {
::core::panicking::panic("internal error: entered unreachable code")
}
*value =
(unreachable(0), unreachable(1), unreachable(2),
unreachable(3), unreachable(4), unreachable(5),
unreachable(6), unreachable(7), unreachable(8),
unreachable(9), unreachable(10), unreachable(11),
unreachable(12), unreachable(13), unreachable(14));
};
let field_0 = unsafe { ptr.move_field(|f| &raw mut (*f).0) };
let field_1 = unsafe { ptr.move_field(|f| &raw mut (*f).1) };
let field_2 = unsafe { ptr.move_field(|f| &raw mut (*f).2) };
let field_3 = unsafe { ptr.move_field(|f| &raw mut (*f).3) };
let field_4 = unsafe { ptr.move_field(|f| &raw mut (*f).4) };
let field_5 = unsafe { ptr.move_field(|f| &raw mut (*f).5) };
let field_6 = unsafe { ptr.move_field(|f| &raw mut (*f).6) };
let field_7 = unsafe { ptr.move_field(|f| &raw mut (*f).7) };
let field_8 = unsafe { ptr.move_field(|f| &raw mut (*f).8) };
let field_9 = unsafe { ptr.move_field(|f| &raw mut (*f).9) };
let field_10 = unsafe { ptr.move_field(|f| &raw mut (*f).10) };
let field_11 = unsafe { ptr.move_field(|f| &raw mut (*f).11) };
let field_12 = unsafe { ptr.move_field(|f| &raw mut (*f).12) };
let field_13 = unsafe { ptr.move_field(|f| &raw mut (*f).13) };
let field_14 = unsafe { ptr.move_field(|f| &raw mut (*f).14) };
core::mem::forget(ptr);
;
#[allow(unused_unsafe, reason =
"Zero-length tuples will generate a function body equivalatent to (); however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")]
unsafe {
B0::get_components(field_0, func);
B1::get_components(field_1, func);
B2::get_components(field_2, func);
B3::get_components(field_3, func);
B4::get_components(field_4, func);
B5::get_components(field_5, func);
B6::get_components(field_6, func);
B7::get_components(field_7, func);
B8::get_components(field_8, func);
B9::get_components(field_9, func);
B10::get_components(field_10, func);
B11::get_components(field_11, func);
B12::get_components(field_12, func);
B13::get_components(field_13, func);
B14::get_components(field_14, func);
}
}
#[allow(clippy :: unused_unit, reason =
"Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")]
#[inline(always)]
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>,
entity: &mut EntityWorldMut) {
let mut ptr: ::bevy_ptr::MovingPtr<core::mem::MaybeUninit<_>, _> =
ptr;
let _ =
||
{
let value = unsafe { ptr.assume_init_mut() };
core::hint::black_box((&mut value.0, &mut value.1,
&mut value.2, &mut value.3, &mut value.4, &mut value.5,
&mut value.6, &mut value.7, &mut value.8, &mut value.9,
&mut value.10, &mut value.11, &mut value.12, &mut value.13,
&mut value.14));
fn unreachable<T>(_index: usize) -> T {
::core::panicking::panic("internal error: entered unreachable code")
}
*value =
(unreachable(0), unreachable(1), unreachable(2),
unreachable(3), unreachable(4), unreachable(5),
unreachable(6), unreachable(7), unreachable(8),
unreachable(9), unreachable(10), unreachable(11),
unreachable(12), unreachable(13), unreachable(14));
};
let field_0 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).0) };
let field_1 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).1) };
let field_2 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).2) };
let field_3 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).3) };
let field_4 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).4) };
let field_5 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).5) };
let field_6 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).6) };
let field_7 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).7) };
let field_8 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).8) };
let field_9 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).9) };
let field_10 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).10) };
let field_11 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).11) };
let field_12 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).12) };
let field_13 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).13) };
let field_14 =
unsafe { ptr.move_maybe_uninit_field(|f| &raw mut (*f).14) };
core::mem::forget(ptr);
;
#[allow(unused_unsafe, reason =
"Zero-length tuples will generate a function body equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case.")]
unsafe {
B0::apply_effect(field_0, entity);
B1::apply_effect(field_1, entity);
B2::apply_effect(field_2, entity);
B3::apply_effect(field_3, entity);
B4::apply_effect(field_4, entity);
B5::apply_effect(field_5, entity);
B6::apply_effect(field_6, entity);
B7::apply_effect(field_7, entity);
B8::apply_effect(field_8, entity);
B9::apply_effect(field_9, entity);
B10::apply_effect(field_10, entity);
B11::apply_effect(field_11, entity);
B12::apply_effect(field_12, entity);
B13::apply_effect(field_13, entity);
B14::apply_effect(field_14, entity);
}
}
}
#[doc(hidden)]
impl<B0: NoBundleEffect, B1: NoBundleEffect, B2: NoBundleEffect,
B3: NoBundleEffect, B4: NoBundleEffect, B5: NoBundleEffect,
B6: NoBundleEffect, B7: NoBundleEffect, B8: NoBundleEffect,
B9: NoBundleEffect, B10: NoBundleEffect, B11: NoBundleEffect,
B12: NoBundleEffect, B13: NoBundleEffect, B14: NoBundleEffect>
NoBundleEffect for
(B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14) {
}all_tuples_enumerated!(
177#[doc(fake_variadic)]
178tuple_impl,
1790,
18015,
181 B,
182 field_
183);