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 #[doc(hidden)]
30 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T;
31
32 #[doc(hidden)]
34 fn type_info(&self) -> Vec<TypeInfo>;
35 #[doc(hidden)]
39 unsafe fn put(self, f: impl FnMut(*mut u8, TypeInfo));
40}
41
42#[allow(clippy::missing_safety_doc)]
47pub unsafe trait Bundle: DynamicBundle {
48 #[doc(hidden)]
49 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T;
50
51 #[doc(hidden)]
53 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T;
54
55 #[doc(hidden)]
62 unsafe fn get(f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent>
63 where
64 Self: Sized;
65}
66
67#[allow(clippy::missing_safety_doc)]
69pub unsafe trait DynamicBundleClone: DynamicBundle {
70 #[doc(hidden)]
75 unsafe fn put_with_clone(self, f: impl FnMut(*mut u8, TypeInfo, DynamicClone));
76}
77
78#[derive(Copy, Clone)]
79pub struct DynamicClone {
81 pub(crate) func: unsafe fn(*const u8, &mut dyn FnMut(*mut u8, TypeInfo)),
82}
83
84impl DynamicClone {
85 pub fn new<T: Component + Clone>() -> Self {
87 Self {
88 func: |src, f| {
89 let mut tmp = unsafe { (*src.cast::<T>()).clone() };
90 f((&mut tmp as *mut T).cast(), TypeInfo::of::<T>());
91 core::mem::forget(tmp);
92 },
93 }
94 }
95}
96
97#[derive(Debug, Clone, Eq, PartialEq, Hash)]
99pub struct MissingComponent(&'static str);
100
101impl MissingComponent {
102 pub fn new<T: Component>() -> Self {
104 Self(type_name::<T>())
105 }
106}
107
108impl fmt::Display for MissingComponent {
109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(f, "missing {} component", self.0)
111 }
112}
113
114#[cfg(feature = "std")]
115impl std::error::Error for MissingComponent {}
116
117macro_rules! tuple_impl {
118 ($($name: ident),*) => {
119 unsafe impl<$($name: Component),*> DynamicBundle for ($($name,)*) {
120 fn key(&self) -> Option<TypeId> {
121 Some(TypeId::of::<Self>())
122 }
123
124 fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
125 Self::with_static_ids(f)
126 }
127
128 fn type_info(&self) -> Vec<TypeInfo> {
129 Self::with_static_type_info(|info| info.to_vec())
130 }
131
132 #[allow(unused_variables, unused_mut)]
133 unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
134 #[allow(non_snake_case)]
135 let ($(mut $name,)*) = self;
136 $(
137 f(
138 (&mut $name as *mut $name).cast::<u8>(),
139 TypeInfo::of::<$name>()
140 );
141 mem::forget($name);
142 )*
143 }
144 }
145
146 unsafe impl<$($name: Component + Clone),*> DynamicBundleClone for ($($name,)*) {
147 #[allow(unused_variables, unused_mut)]
149 unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
150 #[allow(non_snake_case)]
151 let ($(mut $name,)*) = self;
152 $(
153 f(
154 (&mut $name as *mut $name).cast::<u8>(),
155 TypeInfo::of::<$name>(),
156 DynamicClone::new::<$name>()
157 );
158 mem::forget($name);
159 )*
160 }
161 }
162
163 unsafe impl<$($name: Component),*> Bundle for ($($name,)*) {
164 fn with_static_ids<T>(f: impl FnOnce(&[TypeId]) -> T) -> T {
165 const N: usize = count!($($name),*);
166 let mut xs: [(usize, TypeId); N] = [$((mem::align_of::<$name>(), TypeId::of::<$name>())),*];
167 xs.sort_unstable_by(|x, y| x.0.cmp(&y.0).reverse().then(x.1.cmp(&y.1)));
168 let mut ids = [TypeId::of::<()>(); N];
169 for (slot, &(_, id)) in ids.iter_mut().zip(xs.iter()) {
170 *slot = id;
171 }
172 f(&ids)
173 }
174
175 fn with_static_type_info<T>(f: impl FnOnce(&[TypeInfo]) -> T) -> T {
176 const N: usize = count!($($name),*);
177 let mut xs: [TypeInfo; N] = [$(TypeInfo::of::<$name>()),*];
178 xs.sort_unstable();
179 f(&xs)
180 }
181
182 #[allow(unused_variables, unused_mut)]
183 unsafe fn get(mut f: impl FnMut(TypeInfo) -> Option<NonNull<u8>>) -> Result<Self, MissingComponent> {
184 #[allow(non_snake_case)]
185 let ($(mut $name,)*) = ($(
186 f(TypeInfo::of::<$name>()).ok_or_else(MissingComponent::new::<$name>)?
187 .as_ptr()
188 .cast::<$name>(),)*
189 );
190 Ok(($($name.read(),)*))
191 }
192 }
193 }
194}
195
196macro_rules! count {
197 () => { 0 };
198 ($x: ident $(, $rest: ident)*) => { 1 + count!($($rest),*) };
199}
200
201smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);