Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/bundle/impls.rs
6849 views
1
use core::any::TypeId;
2
3
use bevy_ptr::{MovingPtr, OwningPtr};
4
use core::mem::MaybeUninit;
5
use variadics_please::all_tuples_enumerated;
6
7
use crate::{
8
bundle::{Bundle, BundleFromComponents, DynamicBundle, NoBundleEffect},
9
component::{Component, ComponentId, Components, ComponentsRegistrator, StorageType},
10
world::EntityWorldMut,
11
};
12
13
// 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.
16
unsafe impl<C: Component> Bundle for C {
17
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)) {
18
ids(components.register_component::<C>());
19
}
20
21
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)) {
22
ids(components.get_id(TypeId::of::<C>()));
23
}
24
}
25
26
// SAFETY:
27
// - `Bundle::from_components` calls `func` exactly once for C, which is the exact value returned by `Bundle::component_ids`.
28
unsafe impl<C: Component> BundleFromComponents for C {
29
unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
30
where
31
// Ensure that the `OwningPtr` is used correctly
32
F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,
33
Self: Sized,
34
{
35
let ptr = func(ctx);
36
// Safety: The id given in `component_ids` is for `Self`
37
unsafe { ptr.read() }
38
}
39
}
40
41
impl<C: Component> DynamicBundle for C {
42
type Effect = ();
43
#[inline]
44
unsafe fn get_components(
45
ptr: MovingPtr<'_, Self>,
46
func: &mut impl FnMut(StorageType, OwningPtr<'_>),
47
) -> Self::Effect {
48
func(C::STORAGE_TYPE, OwningPtr::from(ptr));
49
}
50
51
#[inline]
52
unsafe fn apply_effect(_ptr: MovingPtr<'_, MaybeUninit<Self>>, _entity: &mut EntityWorldMut) {}
53
}
54
55
macro_rules! tuple_impl {
56
($(#[$meta:meta])* $(($index:tt, $name: ident, $alias: ident)),*) => {
57
#[expect(
58
clippy::allow_attributes,
59
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
60
)]
61
#[allow(
62
unused_mut,
63
unused_variables,
64
reason = "Zero-length tuples won't use any of the parameters."
65
)]
66
$(#[$meta])*
67
// SAFETY:
68
// - `Bundle::component_ids` calls `ids` for each component type in the
69
// bundle, in the exact order that `DynamicBundle::get_components` is called.
70
// - `Bundle::from_components` calls `func` exactly once for each `ComponentId` returned by `Bundle::component_ids`.
71
// - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
72
// `StorageType` into the callback.
73
unsafe impl<$($name: Bundle),*> Bundle for ($($name,)*) {
74
fn component_ids(components: &mut ComponentsRegistrator, ids: &mut impl FnMut(ComponentId)){
75
$(<$name as Bundle>::component_ids(components, ids);)*
76
}
77
78
fn get_component_ids(components: &Components, ids: &mut impl FnMut(Option<ComponentId>)){
79
$(<$name as Bundle>::get_component_ids(components, ids);)*
80
}
81
}
82
83
#[expect(
84
clippy::allow_attributes,
85
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
86
)]
87
#[allow(
88
unused_mut,
89
unused_variables,
90
reason = "Zero-length tuples won't use any of the parameters."
91
)]
92
$(#[$meta])*
93
// SAFETY:
94
// - `Bundle::component_ids` calls `ids` for each component type in the
95
// bundle, in the exact order that `DynamicBundle::get_components` is called.
96
// - `Bundle::from_components` calls `func` exactly once for each `ComponentId` returned by `Bundle::component_ids`.
97
// - `Bundle::get_components` is called exactly once for each member. Relies on the above implementation to pass the correct
98
// `StorageType` into the callback.
99
unsafe impl<$($name: BundleFromComponents),*> BundleFromComponents for ($($name,)*) {
100
#[allow(
101
clippy::unused_unit,
102
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."
103
)]
104
unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> Self
105
where
106
F: FnMut(&mut T) -> OwningPtr<'_>
107
{
108
#[allow(
109
unused_unsafe,
110
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."
111
)]
112
// SAFETY: Rust guarantees that tuple calls are evaluated 'left to right'.
113
// https://doc.rust-lang.org/reference/expressions.html#evaluation-order-of-operands
114
unsafe { ($(<$name as BundleFromComponents>::from_components(ctx, func),)*) }
115
}
116
}
117
118
#[expect(
119
clippy::allow_attributes,
120
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
121
)]
122
#[allow(
123
unused_mut,
124
unused_variables,
125
reason = "Zero-length tuples won't use any of the parameters."
126
)]
127
$(#[$meta])*
128
impl<$($name: Bundle),*> DynamicBundle for ($($name,)*) {
129
type Effect = ($($name::Effect,)*);
130
#[allow(
131
clippy::unused_unit,
132
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."
133
)]
134
#[inline(always)]
135
unsafe fn get_components(ptr: MovingPtr<'_, Self>, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) {
136
bevy_ptr::deconstruct_moving_ptr!({
137
let tuple { $($index: $alias,)* } = ptr;
138
});
139
// SAFETY: Caller ensures requirements for calling `get_components` are met.
140
$( $name::get_components($alias, func); )*
141
}
142
143
#[allow(
144
clippy::unused_unit,
145
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."
146
)]
147
#[inline(always)]
148
unsafe fn apply_effect(ptr: MovingPtr<'_, MaybeUninit<Self>>, entity: &mut EntityWorldMut) {
149
bevy_ptr::deconstruct_moving_ptr!({
150
let MaybeUninit::<tuple> { $($index: $alias,)* } = ptr;
151
});
152
// SAFETY: Caller ensures requirements for calling `apply_effect` are met.
153
$( $name::apply_effect($alias, entity); )*
154
}
155
}
156
157
$(#[$meta])*
158
impl<$($name: NoBundleEffect),*> NoBundleEffect for ($($name,)*) {}
159
}
160
}
161
162
all_tuples_enumerated!(
163
#[doc(fake_variadic)]
164
tuple_impl,
165
0,
166
15,
167
B,
168
field_
169
);
170
171