1use core::{any::TypeId, iter};
2
3use bevy_ptr::{MovingPtr, OwningPtr};
4use core::mem::MaybeUninit;
5use variadics_please::all_tuples_enumerated;
6
7use crate::{
8 bundle::{Bundle, BundleFromComponents, DynamicBundle, NoBundleEffect},
9 component::{Component, ComponentId, Components, ComponentsRegistrator, StorageType},
10 world::EntityWorldMut,
11};
12
13unsafe impl<C: Component> Bundle for C {
17 fn component_ids(
18 components: &mut ComponentsRegistrator,
19 ) -> impl Iterator<Item = ComponentId> + use<C> {
20 iter::once(components.register_component::<C>())
21 }
22
23 fn get_component_ids(components: &Components) -> impl Iterator<Item = Option<ComponentId>> {
24 iter::once(components.get_id(TypeId::of::<C>()))
25 }
26}
27
28unsafe impl<C: Component> BundleFromComponents for C {
31 unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
32 where
33 F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
35 Self: Sized,
36 {
37 let ptr = func(ctx);
38 unsafe { ptr.read() }
40 }
41}
42
43impl<C: Component> DynamicBundle for C {
44 type Effect = ();
45 #[inline]
46 unsafe fn get_components(
47 ptr: MovingPtr<'_, Self>,
48 func: &mut impl FnMut(StorageType, OwningPtr<'_>),
49 ) -> Self::Effect {
50 func(C::STORAGE_TYPE, OwningPtr::from(ptr));
51 }
52
53 #[inline]
54 unsafe fn apply_effect(_ptr: MovingPtr<'_, MaybeUninit<Self>>, _entity: &mut EntityWorldMut) {}
55}
56
57macro_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 unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
76 fn component_ids<'a>(components: &'a mut ComponentsRegistrator) -> impl Iterator<Item = ComponentId> + use<$($name,)*> {
77 iter::empty()$(.chain(<$name as Bundle>::component_ids(components)))*
78 }
79
80 fn get_component_ids(components: &Components) -> impl Iterator<Item = Option<ComponentId>> {
81 iter::empty()$(.chain(<$name as Bundle>::get_component_ids(components)))*
82 }
83 }
84
85 #[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 unsafe 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 )]
106 unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
107 where
108 F: 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 unsafe { ($(<$name as BundleFromComponents>::from_components(ctx, func),)*) }
117 }
118 }
119
120 #[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])*
130 impl<$($name: Bundle),*> DynamicBundle for ($($name,)*) {
131 type 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)]
137 unsafe fn get_components(ptr: MovingPtr<'_, Self>, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
138 bevy_ptr::deconstruct_moving_ptr!({
139 let 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 unsafe {
147 $( $name::get_components($alias, func); )*
148 }
149 }
150
151 #[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)]
156 unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
157 bevy_ptr::deconstruct_moving_ptr!({
158 let 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 unsafe {
166 $( $name::apply_effect($alias, entity); )*
167 }
168 }
169 }
170
171 $(#[$meta])*
172 impl<$($name: NoBundleEffect),*> NoBundleEffect for ($($name,)*) {}
173 }
174}
175
176all_tuples_enumerated!(
177 #[doc(fake_variadic)]
178 tuple_impl,
179 0,
180 15,
181 B,
182 field_
183);