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