1use core::{
10 alloc::Layout,
11 any::TypeId,
12 fmt,
13 marker::PhantomData,
14 mem::{align_of, replace, size_of, ManuallyDrop},
15 ptr::{self, NonNull},
16};
17
18use smallvec::SmallVec;
19
20use crate::{
21 component::{Component, ComponentInfo},
22 type_id,
23};
24
25pub unsafe trait DynamicBundle {
37 fn valid(&self) -> bool;
39
40 fn key() -> Option<TypeId> {
42 None
43 }
44
45 fn contains_id(&self, ty: TypeId) -> bool;
47
48 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R;
50
51 fn put(self, f: impl FnMut(NonNull<u8>, TypeId, usize));
54}
55
56pub unsafe trait DynamicComponentBundle: DynamicBundle + 'static {
63 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R;
65}
66
67pub unsafe trait Bundle: DynamicBundle {
79 fn static_valid() -> bool;
81
82 fn static_key() -> TypeId;
84
85 fn static_contains_id(ty: TypeId) -> bool;
87
88 fn static_with_ids<R>(f: impl FnOnce(&[TypeId]) -> R) -> R;
90}
91
92pub unsafe trait ComponentBundle: Bundle + DynamicComponentBundle {
99 fn static_with_components<R>(f: impl FnOnce(&[ComponentInfo]) -> R) -> R;
101}
102
103macro_rules! impl_bundle {
104 () => {
105 unsafe impl DynamicBundle for () {
106 #[inline(always)]
107 fn valid(&self) -> bool { true }
108
109 #[inline(always)]
110 fn key() -> Option<TypeId> {
111 Some(Self::static_key())
112 }
113
114 #[inline(always)]
115 fn contains_id(&self, ty: TypeId) -> bool {
116 Self::static_contains_id(ty)
117 }
118
119 #[inline(always)]
120 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R {
121 Self::static_with_ids(f)
122 }
123
124 #[inline(always)]
125 fn put(self, _f: impl FnMut(NonNull<u8>, TypeId, usize)) {}
126 }
127
128 unsafe impl DynamicComponentBundle for () {
129 #[inline(always)]
130 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
131 Self::static_with_components(f)
132 }
133 }
134
135 unsafe impl Bundle for () {
136 fn static_valid() -> bool { true }
137
138 #[inline(always)]
139 fn static_key() -> TypeId {
140 type_id::<()>()
141 }
142
143 #[inline(always)]
144 fn static_contains_id(_ty: TypeId) -> bool {
145 false
146 }
147
148 #[inline(always)]
149 fn static_with_ids<R>(f: impl FnOnce(&[TypeId]) -> R) -> R {
150 f(&[])
151 }
152 }
153
154 unsafe impl ComponentBundle for () {
155 #[inline(always)]
156 fn static_with_components<R>(f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
157 f(&[])
158 }
159 }
160 };
161
162 ($($a:ident)+) => {
163 unsafe impl<$($a),+> DynamicBundle for ($($a,)+)
164 where $($a: 'static,)+
165 {
166 #[inline(always)]
167 fn valid(&self) -> bool {
168 <Self as Bundle>::static_valid()
169 }
170
171 #[inline(always)]
172 fn key() -> Option<TypeId> {
173 Some(<Self as Bundle>::static_key())
174 }
175
176 #[inline(always)]
177 fn contains_id(&self, ty: TypeId) -> bool {
178 <Self as Bundle>::static_contains_id(ty)
179 }
180
181 #[inline(always)]
182 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R {
183 <Self as Bundle>::static_with_ids(f)
184 }
185
186 #[inline(always)]
187 fn put(self, mut f: impl FnMut(NonNull<u8>, TypeId, usize)) {
188 #![allow(non_snake_case)]
189
190 let ($($a,)+) = self;
191 let ($($a,)+) = ($(ManuallyDrop::new($a),)+);
192 $(
193 f(NonNull::from(&*$a).cast(), type_id::<$a>(), size_of::<$a>());
194 )+
195 }
196 }
197
198 unsafe impl<$($a),+> DynamicComponentBundle for ($($a,)+)
199 where $($a: Component,)+
200 {
201 #[inline(always)]
202 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
203 <Self as ComponentBundle>::static_with_components(f)
204 }
205 }
206
207 unsafe impl<$($a),+> Bundle for ($($a,)+)
208 where $($a: 'static,)+
209 {
210 fn static_valid() -> bool {
211 let mut ids: &[_] = &[$(type_id::<$a>(),)+];
212 while let [check, rest @ ..] = ids {
213 let mut rest = rest;
214 if let [head, tail @ ..] = rest {
215 if head == check {
216 return false;
217 }
218 rest = tail;
219 }
220 ids = rest;
221 }
222 true
223 }
224
225 #[inline(always)]
226 fn static_key() -> TypeId {
227 type_id::<Self>()
228 }
229
230 #[inline(always)]
231 fn static_contains_id(ty: TypeId) -> bool {
232 $( type_id::<$a>() == ty )|| *
233 }
234
235 #[inline(always)]
236 fn static_with_ids<R>(f: impl FnOnce(&[TypeId]) -> R) -> R {
237 f(&[$(type_id::<$a>(),)+])
238 }
239 }
240
241
242 unsafe impl<$($a),+> ComponentBundle for ($($a,)+)
243 where $($a: Component,)+
244 {
245 #[inline(always)]
246 fn static_with_components<R>(f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
247 f(&[$(ComponentInfo::of::<$a>(),)+])
248 }
249 }
250 };
251}
252
253for_tuple!(impl_bundle);
254
255pub struct EntityBuilder {
260 ptr: NonNull<u8>,
261 layout: Layout,
262 len: usize,
263
264 ids: SmallVec<[TypeId; 8]>,
265 infos: SmallVec<[ComponentInfo; 8]>,
266 offsets: SmallVec<[usize; 8]>,
267}
268
269unsafe impl Send for EntityBuilder {}
272
273impl Drop for EntityBuilder {
274 fn drop(&mut self) {
275 for (info, &offset) in self.infos.iter().zip(&self.offsets) {
276 let ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) };
277 info.final_drop(ptr, 1);
278 }
279 }
280}
281
282impl fmt::Debug for EntityBuilder {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 let mut ds = f.debug_struct("EntityBuilder");
285 for info in &self.infos {
286 ds.field("component", &info.name());
287 }
288 ds.finish()
289 }
290}
291
292impl EntityBuilder {
293 #[inline(always)]
295 pub fn new() -> Self {
296 EntityBuilder {
297 ptr: NonNull::dangling(),
298 len: 0,
299 layout: Layout::new::<[u8; 0]>(),
300 ids: SmallVec::new(),
301 infos: SmallVec::new(),
302 offsets: SmallVec::new(),
303 }
304 }
305
306 #[inline(always)]
309 pub fn with<T>(mut self, value: T) -> Self
310 where
311 T: Component + Send,
312 {
313 self.add(value);
314 self
315 }
316
317 pub fn add<T>(&mut self, value: T) -> &mut Self
320 where
321 T: Component + Send,
322 {
323 if let Some(existing) = self.get_mut::<T>() {
324 *existing = value;
326 return self;
327 }
328
329 debug_assert!(self.len <= self.layout.size());
330 let value_layout = Layout::from_size_align(self.len, self.layout.align()).unwrap();
331
332 let (new_value_layout, value_offset) = value_layout
333 .extend(Layout::new::<T>())
334 .expect("EntityBuilder overflow");
335
336 self.ids.reserve(1);
337 self.infos.reserve(1);
338 self.offsets.reserve(1);
339
340 if self.layout.align() != new_value_layout.align()
341 || self.layout.size() < new_value_layout.size()
342 {
343 const MIN_LAYOUT_ALIGN: usize = align_of::<u128>();
345 const MIN_LAYOUT_SIZE: usize = 128;
346
347 let cap = if self.layout.size() < new_value_layout.size() {
348 if MIN_LAYOUT_SIZE >= new_value_layout.size() {
349 MIN_LAYOUT_SIZE
350 } else {
351 match self.layout.size().checked_mul(2) {
352 Some(cap) if cap >= new_value_layout.size() => cap,
353 _ => new_value_layout.size(),
354 }
355 }
356 } else {
357 self.layout.size()
358 };
359
360 let align = new_value_layout.align().max(MIN_LAYOUT_ALIGN);
361 let new_layout = Layout::from_size_align(cap, align).unwrap_or(new_value_layout);
362
363 unsafe {
364 let new_ptr = alloc::alloc::alloc(new_layout);
365 let new_ptr = NonNull::new(new_ptr).unwrap();
366
367 ptr::copy_nonoverlapping(self.ptr.as_ptr(), new_ptr.as_ptr(), self.len);
368
369 let old_ptr = replace(&mut self.ptr, new_ptr);
370 let old_layout = replace(&mut self.layout, new_layout);
371
372 alloc::alloc::dealloc(old_ptr.as_ptr(), old_layout);
373 }
374 }
375
376 unsafe {
377 debug_assert!(self.len <= self.layout.size());
378 debug_assert!(self.len <= value_offset);
379 debug_assert!(value_offset + size_of::<T>() <= self.layout.size());
380
381 ptr::write(self.ptr.as_ptr().add(value_offset).cast(), value);
382 self.len = value_offset + size_of::<T>();
383 }
384
385 self.ids.push(type_id::<T>());
386 self.infos.push(ComponentInfo::of::<T>());
387 self.offsets.push(value_offset);
388
389 self
390 }
391
392 #[inline(always)]
394 pub fn get<T>(&self) -> Option<&T>
395 where
396 T: 'static,
397 {
398 let idx = self.ids.iter().position(|id| *id == type_id::<T>())?;
399 let offset = self.offsets[idx];
400 Some(unsafe { &*self.ptr.as_ptr().add(offset).cast::<T>() })
401 }
402
403 #[inline(always)]
405 pub fn get_mut<T>(&mut self) -> Option<&mut T>
406 where
407 T: 'static,
408 {
409 let idx = self.ids.iter().position(|id| *id == type_id::<T>())?;
410 let offset = self.offsets[idx];
411 Some(unsafe { &mut *self.ptr.as_ptr().add(offset).cast::<T>() })
412 }
413
414 #[inline(always)]
416 pub fn component_types(&self) -> impl Iterator<Item = &ComponentInfo> {
417 self.infos.iter()
418 }
419
420 #[inline(always)]
422 pub fn is_empty(&self) -> bool {
423 self.ids.is_empty()
424 }
425}
426
427unsafe impl DynamicBundle for EntityBuilder {
428 #[inline(always)]
429 fn valid(&self) -> bool {
430 true
432 }
433
434 #[inline(always)]
435 fn contains_id(&self, ty: TypeId) -> bool {
436 self.ids.iter().any(|id| *id == ty)
437 }
438
439 #[inline(always)]
440 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R {
441 f(&self.ids)
442 }
443
444 #[inline(always)]
445 fn put(self, mut f: impl FnMut(NonNull<u8>, TypeId, usize)) {
446 let me = ManuallyDrop::new(self);
447 for (info, &offset) in me.infos.iter().zip(&me.offsets) {
448 let ptr = unsafe { NonNull::new_unchecked(me.ptr.as_ptr().add(offset)) };
449 f(ptr, info.id(), info.layout().size());
450 }
451 }
452}
453
454unsafe impl DynamicComponentBundle for EntityBuilder {
455 #[inline(always)]
456 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
457 f(&self.infos)
458 }
459}
460
461pub(super) trait BundleDesc {
463 fn key() -> Option<TypeId>;
465
466 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R;
468}
469
470pub(super) trait ComponentBundleDesc: BundleDesc {
472 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R;
474}
475
476impl<B> BundleDesc for B
477where
478 B: DynamicBundle,
479{
480 #[inline(always)]
481 fn key() -> Option<TypeId> {
482 <B as DynamicBundle>::key()
483 }
484
485 #[inline(always)]
486 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R {
487 DynamicBundle::with_ids(self, f)
488 }
489}
490
491impl<B> ComponentBundleDesc for B
492where
493 B: DynamicComponentBundle,
494{
495 #[inline(always)]
496 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
497 DynamicComponentBundle::with_components(self, f)
498 }
499}
500
501impl<B> BundleDesc for PhantomData<B>
502where
503 B: Bundle,
504{
505 #[inline(always)]
506 fn key() -> Option<TypeId> {
507 Some(B::static_key())
508 }
509
510 #[inline(always)]
511 fn with_ids<R>(&self, f: impl FnOnce(&[TypeId]) -> R) -> R {
512 B::static_with_ids(f)
513 }
514}
515
516impl<B> ComponentBundleDesc for PhantomData<B>
517where
518 B: ComponentBundle,
519{
520 #[inline(always)]
521 fn with_components<R>(&self, f: impl FnOnce(&[ComponentInfo]) -> R) -> R {
522 B::static_with_components(f)
523 }
524}