1use crate::alloc::vec::Vec;
9use core::any::{type_name, TypeId};
10use core::ptr::NonNull;
11use core::{fmt, mem};
12
13use crate::archetype::TypeInfo;
14use crate::Component;
15
16#[allow(clippy::missing_safety_doc)]
21pub unsafe trait DynamicBundle {
22 #[doc(hidden)]
24 fn key(&self) -> Option<TypeId> {
25 None
26 }
27
28 fn has<T: Component>(&self) -> bool {
39 self.with_ids(|types| types.contains(&TypeId::of::<T>()))
40 }
41
42 #[doc(hidden)]
44 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T;
45
46 #[doc(hidden)]
48 fn type_info(&self) -> Vec<TypeInfo>;
49 #[doc(hidden)]
53 unsafe fn put(self, f: impl FnMut(*mut u8, TypeInfo));
54}
55
56#[allow(clippy::missing_safety_doc)]
61pub unsafe trait Bundle: DynamicBundle {
62 #[doc(hidden)]
63 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T;
64
65 #[doc(hidden)]
67 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T;
68
69 #[doc(hidden)]
76 unsafe fn get(f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent>
77 where
78 Self: Sized;
79}
80
81#[allow(clippy::missing_safety_doc)]
83pub unsafe trait DynamicBundleClone: DynamicBundle {
84 #[doc(hidden)]
89 unsafe fn put_with_clone(self, f: impl FnMut(*mut u8, TypeInfo, DynamicClone));
90}
91
92#[derive(Copy, Clone)]
93pub struct DynamicClone {
95 pub(crate) func: unsafe fn(*const u8, &mut dyn FnMut(*mut u8, TypeInfo)),
96}
97
98impl DynamicClone {
99 pub fn new<T: Component + Clone>() -> Self {
101 Self {
102 func: |src, f| {
103 let mut tmp = unsafe { (*src.cast::<T>()).clone() };
104 f((&mut tmp as *mut T).cast(), TypeInfo::of::<T>());
105 core::mem::forget(tmp);
106 },
107 }
108 }
109}
110
111#[derive(Debug, Clone, Eq, PartialEq, Hash)]
113pub struct MissingComponent(&'static str);
114
115impl MissingComponent {
116 pub fn new<T: Component>() -> Self {
118 Self(type_name::<T>())
119 }
120}
121
122impl fmt::Display for MissingComponent {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 write!(f, "missing {} component", self.0)
125 }
126}
127
128#[cfg(feature = "std")]
129impl std::error::Error for MissingComponent {}
130
131macro_rules! tuple_impl {
132 ($($name: ident),*) => {
133 unsafe impl<$($name: Component),*> DynamicBundle for ($($name,)*) {
134 fn has<T: Component>(&self) -> bool {
135 false $(|| TypeId::of::<$name>() == TypeId::of::<T>())*
136 }
137
138 fn key(&self) -> Option<TypeId> {
139 Some(TypeId::of::<Self>())
140 }
141
142 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
143 Self::with_static_ids(f)
144 }
145
146 fn type_info(&self) -> Vec<TypeInfo> {
147 Self::with_static_type_info(|info| info.to_vec())
148 }
149
150 #[allow(unused_variables, unused_mut)]
151 unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
152 #[allow(non_snake_case)]
153 let ($(mut $name,)*) = self;
154 $(
155 f(
156 (&mut $name as *mut $name).cast::<u8>(),
157 TypeInfo::of::<$name>()
158 );
159 mem::forget($name);
160 )*
161 }
162 }
163
164 unsafe impl<$($name: Component + Clone),*> DynamicBundleClone for ($($name,)*) {
165 #[allow(unused_variables, unused_mut)]
167 unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
168 #[allow(non_snake_case)]
169 let ($(mut $name,)*) = self;
170 $(
171 f(
172 (&mut $name as *mut $name).cast::<u8>(),
173 TypeInfo::of::<$name>(),
174 DynamicClone::new::<$name>()
175 );
176 mem::forget($name);
177 )*
178 }
179 }
180
181 unsafe impl<$($name: Component),*> Bundle for ($($name,)*) {
182 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T {
183 const N: usize = count!($($name),*);
184 let mut xs: [(usize, TypeId); N] = [$((mem::align_of::<$name>(), TypeId::of::<$name>())),*];
185 xs.sort_unstable_by(|x, y| x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)));
186 let mut ids = [TypeId::of::<()>(); N];
187 for (slot, &(_, id)) in ids.iter_mut().zip(xs.iter()) {
188 *slot = id;
189 }
190 f(&ids)
191 }
192
193 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T {
194 const N: usize = count!($($name),*);
195 let mut xs: [TypeInfo; N] = [$(TypeInfo::of::<$name>()),*];
196 xs.sort_unstable();
197 f(&xs)
198 }
199
200 #[allow(unused_variables, unused_mut)]
201 unsafe fn get(mut f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent> {
202 #[allow(non_snake_case)]
203 let ($(mut $name,)*) = ($(
204 f(TypeInfo::of::<$name>()).ok_or_else(MissingComponent::new::<$name>)?
205 .as_ptr()
206 .cast::<$name>(),)*
207 );
208 Ok(($($name.read(),)*))
209 }
210 }
211 }
212}
213
214macro_rules! count {
215 () => { 0 };
216 ($x: ident $(, $rest: ident)*) => { 1 + count!($($rest),*) };
217}
218
219smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);