1use crate::alloc::vec::Vec;
2use core::any::{type_name, TypeId};
3use core::ptr::NonNull;
4use core::{fmt, mem};
5
6use crate::archetype::TypeInfo;
7use crate::Component;
8
9pub fn bundle_satisfies_query<B: Bundle, Q: crate::Query>() -> bool {
11 use crate::Fetch;
12
13 let arch = B::with_static_type_info(|info| crate::Archetype::new(info.into()));
14 Q::Fetch::access(&arch).is_some()
15}
16
17pub fn dynamic_bundle_satisfies_query<B: DynamicBundle, Q: crate::Query>(b: &B) -> bool {
20 use crate::Fetch;
21
22 let arch = crate::Archetype::new(b.type_info());
23 Q::Fetch::access(&arch).is_some()
24}
25
26#[allow(clippy::missing_safety_doc)]
31pub unsafe trait DynamicBundle {
32 #[doc(hidden)]
34 fn key(&self) -> Option<TypeId> {
35 None
36 }
37
38 fn has<T: Component>(&self) -> bool {
49 self.with_ids(|types| types.contains(&TypeId::of::<T>()))
50 }
51
52 #[doc(hidden)]
54 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T;
55
56 #[doc(hidden)]
58 fn type_info(&self) -> Vec<TypeInfo>;
59 #[doc(hidden)]
63 unsafe fn put(self, f: impl FnMut(*mut u8, TypeInfo));
64}
65
66#[allow(clippy::missing_safety_doc)]
71pub unsafe trait Bundle: DynamicBundle {
72 #[doc(hidden)]
73 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T;
74
75 #[doc(hidden)]
77 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T;
78
79 #[doc(hidden)]
86 unsafe fn get(f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent>
87 where
88 Self: Sized;
89}
90
91#[allow(clippy::missing_safety_doc)]
93pub unsafe trait DynamicBundleClone: DynamicBundle {
94 #[doc(hidden)]
99 unsafe fn put_with_clone(self, f: impl FnMut(*mut u8, TypeInfo, DynamicClone));
100}
101
102#[derive(Copy, Clone)]
103pub struct DynamicClone {
105 pub(crate) func: unsafe fn(*const u8, &mut dyn FnMut(*mut u8, TypeInfo)),
106}
107
108impl DynamicClone {
109 pub fn new<T: Component + Clone>() -> Self {
111 Self {
112 func: |src, f| {
113 let mut tmp = unsafe { (*src.cast::<T>()).clone() };
114 f((&mut tmp as *mut T).cast(), TypeInfo::of::<T>());
115 core::mem::forget(tmp);
116 },
117 }
118 }
119}
120
121#[derive(Debug, Clone, Eq, PartialEq, Hash)]
123pub struct MissingComponent(&'static str);
124
125impl MissingComponent {
126 pub fn new<T: Component>() -> Self {
128 Self(type_name::<T>())
129 }
130}
131
132impl fmt::Display for MissingComponent {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 write!(f, "missing {} component", self.0)
135 }
136}
137
138#[cfg(feature = "std")]
139impl std::error::Error for MissingComponent {}
140
141macro_rules! tuple_impl {
142 ($($name: ident),*) => {
143 unsafe impl<$($name: Component),*> DynamicBundle for ($($name,)*) {
144 fn has<T: Component>(&self) -> bool {
145 false $(|| TypeId::of::<$name>() == TypeId::of::<T>())*
146 }
147
148 fn key(&self) -> Option<TypeId> {
149 Some(TypeId::of::<Self>())
150 }
151
152 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
153 Self::with_static_ids(f)
154 }
155
156 fn type_info(&self) -> Vec<TypeInfo> {
157 Self::with_static_type_info(|info| info.to_vec())
158 }
159
160 #[allow(unused_variables, unused_mut)]
161 unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
162 #[allow(non_snake_case)]
163 let ($(mut $name,)*) = self;
164 $(
165 f(
166 (&mut $name as *mut $name).cast::<u8>(),
167 TypeInfo::of::<$name>()
168 );
169 mem::forget($name);
170 )*
171 }
172 }
173
174 unsafe impl<$($name: Component + Clone),*> DynamicBundleClone for ($($name,)*) {
175 #[allow(unused_variables, unused_mut)]
177 unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
178 #[allow(non_snake_case)]
179 let ($(mut $name,)*) = self;
180 $(
181 f(
182 (&mut $name as *mut $name).cast::<u8>(),
183 TypeInfo::of::<$name>(),
184 DynamicClone::new::<$name>()
185 );
186 mem::forget($name);
187 )*
188 }
189 }
190
191 #[allow(clippy::zero_repeat_side_effects)]
192 unsafe impl<$($name: Component),*> Bundle for ($($name,)*) {
193 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T {
194 const N: usize = count!($($name),*);
195 let mut xs: [(usize, TypeId); N] = [$((mem::align_of::<$name>(), TypeId::of::<$name>())),*];
196 xs.sort_unstable_by(|x, y| x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)));
197 let mut ids = [TypeId::of::<()>(); N];
198 for (slot, &(_, id)) in ids.iter_mut().zip(xs.iter()) {
199 *slot = id;
200 }
201 f(&ids)
202 }
203
204 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T {
205 const N: usize = count!($($name),*);
206 let mut xs: [TypeInfo; N] = [$(TypeInfo::of::<$name>()),*];
207 xs.sort_unstable();
208 f(&xs)
209 }
210
211 #[allow(unused_variables, unused_mut)]
212 unsafe fn get(mut f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent> {
213 #[allow(non_snake_case)]
214 let ($(mut $name,)*) = ($(
215 f(TypeInfo::of::<$name>()).ok_or_else(MissingComponent::new::<$name>)?
216 .as_ptr()
217 .cast::<$name>(),)*
218 );
219 Ok(($($name.read(),)*))
220 }
221 }
222 }
223}
224
225macro_rules! count {
226 () => { 0 };
227 ($x: ident $(, $rest: ident)*) => { 1 + count!($($rest),*) };
228}
229
230smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);