edict/
component.rs

1//! This module defines [`Component`] trait and related types.
2
3use alloc::{sync::Arc, vec, vec::Vec};
4use core::{
5    alloc::Layout,
6    any::{type_name, Any, TypeId},
7    borrow::{Borrow, BorrowMut},
8    marker::PhantomData,
9    mem::{transmute, ManuallyDrop},
10    ptr::{self, drop_in_place, slice_from_raw_parts_mut, NonNull},
11};
12
13use hashbrown::hash_map::{Entry, HashMap};
14
15use crate::{action::LocalActionEncoder, entity::EntityId, hash::NoOpHasherBuilder, type_id};
16
17pub use edict_proc::Component;
18
19#[doc(hidden)]
20pub type BorrowFn<T> = for<'r> unsafe fn(NonNull<u8>, PhantomData<&'r T>) -> &'r T;
21
22#[doc(hidden)]
23pub type BorrowFnMut<T> = for<'r> unsafe fn(NonNull<u8>, PhantomData<&'r mut T>) -> &'r mut T;
24
25/// Defines conversion of reference to component into reference to target type.
26#[derive(Clone, Copy)]
27pub struct ComponentBorrow {
28    ty: TypeId,
29
30    // Actually is `BorrowFn<T>` where `type_id::<T>() == target`.
31    borrow: BorrowFn<()>,
32
33    // Actually is `BorrowFnMut<T>` where `type_id::<T>() == target`.
34    borrow_mut: Option<BorrowFnMut<()>>,
35}
36
37// Types used by proc-macros
38#[doc(hidden)]
39pub mod private {
40    use core::borrow::{Borrow, BorrowMut};
41
42    use super::ComponentBorrow;
43
44    pub struct DispatchBorrowMut<T, U>(pub DispatchBorrow<T, U>);
45
46    pub struct DispatchBorrow<T, U>(pub core::marker::PhantomData<(T, U)>);
47
48    impl<T, U> core::ops::Deref for DispatchBorrowMut<T, U> {
49        type Target = DispatchBorrow<T, U>;
50
51        fn deref(&self) -> &DispatchBorrow<T, U> {
52            &self.0
53        }
54    }
55
56    impl<T, U> DispatchBorrowMut<T, U>
57    where
58        T: BorrowMut<U> + Send + Sync + 'static,
59        U: 'static,
60    {
61        pub fn insert(&self, extend: &mut impl core::iter::Extend<ComponentBorrow>) {
62            extend.extend(Some(ComponentBorrow::make(
63                |ptr: core::ptr::NonNull<u8>, core::marker::PhantomData| -> &U {
64                    unsafe { ptr.cast::<T>().as_ref().borrow() }
65                },
66                core::option::Option::Some(
67                    |ptr: core::ptr::NonNull<u8>, core::marker::PhantomData| -> &mut U {
68                        unsafe { ptr.cast::<T>().as_mut().borrow_mut() }
69                    },
70                ),
71            )));
72        }
73    }
74
75    impl<T, U> DispatchBorrow<T, U>
76    where
77        T: Borrow<U> + Sync + 'static,
78        U: 'static,
79    {
80        pub fn insert(&self, extend: &mut impl core::iter::Extend<ComponentBorrow>) {
81            extend.extend(Some(ComponentBorrow::make(
82                |ptr: core::ptr::NonNull<u8>, core::marker::PhantomData| -> &U {
83                    unsafe { ptr.cast::<T>().as_ref().borrow() }
84                },
85                core::option::Option::None,
86            )));
87        }
88    }
89
90    impl<T, U> DispatchBorrowMut<T, U> {
91        pub fn new() -> Self {
92            DispatchBorrowMut(DispatchBorrow(core::marker::PhantomData::<(T, U)>))
93        }
94    }
95
96    /// Extends output with `ComponentBorrow` to borrow borrowed type.
97    /// Mutably if possible.
98    #[macro_export]
99    macro_rules! type_borrow {
100        ($self:ty as $other:ty => $borrows:ident) => {
101            let dispatch = $crate::component::private::DispatchBorrowMut::<$self, $other>::new();
102            dispatch.insert(&mut $borrows);
103        };
104    }
105
106    /// Extends output with `ComponentBorrow` to borrow dyn trait object.
107    /// `dyn Trait + Send + Sync` and all valid combinations are automatically added.
108    #[macro_export]
109    macro_rules! trait_borrow {
110        ($self:ty as $trait:path => $borrows:ident) => {{
111            struct DispatchTraitBorrowSendSync<T> { send: DispatchTraitBorrowSend<T> }
112            struct DispatchTraitBorrowSend<T>{ sync: DispatchTraitBorrowSync<T> }
113            struct DispatchTraitBorrowSync<T>{ bare: DispatchTraitBorrow<T> }
114            struct DispatchTraitBorrow<T>(core::marker::PhantomData<T>);
115
116            impl<T> core::ops::Deref for DispatchTraitBorrowSendSync<T> {
117                type Target = DispatchTraitBorrowSend<T>;
118
119                fn deref(&self) -> &DispatchTraitBorrowSend<T> {
120                    &self.send
121                }
122            }
123
124            impl<T> core::ops::Deref for DispatchTraitBorrowSend<T> {
125                type Target = DispatchTraitBorrowSync<T>;
126
127                fn deref(&self) -> &DispatchTraitBorrowSync<T> {
128                    &self.sync
129                }
130            }
131
132            impl<T> core::ops::Deref for DispatchTraitBorrowSync<T> {
133                type Target = DispatchTraitBorrow<T>;
134
135                fn deref(&self) -> &DispatchTraitBorrow<T> {
136                    &self.bare
137                }
138            }
139
140            impl<T> DispatchTraitBorrowSendSync<T> {
141                fn new() -> Self {
142                    DispatchTraitBorrowSendSync {
143                        send: DispatchTraitBorrowSend {
144                            sync: DispatchTraitBorrowSync {
145                                bare: DispatchTraitBorrow(core::marker::PhantomData::<T>),
146                            },
147                        },
148
149                    }
150                }
151            }
152
153            impl<T: $trait + $crate::private::Send + $crate::private::Sync + 'static> DispatchTraitBorrowSendSync<T> {
154                #[allow(unused)]
155                fn insert(
156                    &self,
157                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
158                ) {
159                    self.insert_one(extend);
160                    self.send.insert_one(extend);
161                    self.sync.insert_one(extend);
162                    self.bare.insert_one(extend);
163                }
164
165                #[allow(unused)]
166                fn insert_one(
167                    &self,
168                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
169                ) {
170                    extend.extend(Some($crate::component::ComponentBorrow::make(
171                        |ptr: $crate::private::NonNull<u8>,
172                         $crate::private::PhantomData|
173                         -> &(dyn $trait + $crate::private::Send + $crate::private::Sync) {
174                            unsafe { ptr.cast::<T>().as_ref() }
175                        },
176                        $crate::private::Option::Some(
177                            |ptr: $crate::private::NonNull<u8>,
178                             $crate::private::PhantomData|
179                             -> &mut (dyn $trait + $crate::private::Send + $crate::private::Sync) {
180                                unsafe { ptr.cast::<T>().as_mut() }
181                            },
182                        ),
183                    )));
184                }
185            }
186
187            impl<T: $trait + $crate::private::Send + 'static> DispatchTraitBorrowSend<T> {
188                #[allow(unused)]
189                fn insert(
190                    &self,
191                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
192                ) {
193                    self.insert_one(extend);
194                    self.bare.insert_one(extend);
195                }
196
197                #[allow(unused)]
198                fn insert_one(
199                    &self,
200                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
201                ) {
202                    extend.extend(Some($crate::component::ComponentBorrow::make(
203                        |ptr: $crate::private::NonNull<u8>,
204                         $crate::private::PhantomData|
205                         -> &(dyn $trait + Send) {
206                            unsafe { ptr.cast::<T>().as_ref() }
207                        },
208                        $crate::private::Option::Some(
209                            |ptr: $crate::private::NonNull<u8>,
210                             $crate::private::PhantomData|
211                             -> &mut (dyn $trait + Send) {
212                                unsafe { ptr.cast::<T>().as_mut() }
213                            },
214                        ),
215                    )));
216                }
217            }
218
219            impl<T: $trait + $crate::private::Sync + 'static> DispatchTraitBorrowSync<T> {
220                #[allow(unused)]
221                fn insert(
222                    &self,
223                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
224                ) {
225                    self.insert_one(extend);
226                    self.bare.insert_one(extend);
227                }
228
229                #[allow(unused)]
230                fn insert_one(
231                    &self,
232                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
233                ) {
234                    extend.extend(Some($crate::component::ComponentBorrow::make(
235                        |ptr: $crate::private::NonNull<u8>,
236                         $crate::private::PhantomData|
237                         -> &(dyn $trait + Sync) {
238                            unsafe { ptr.cast::<T>().as_ref() }
239                        },
240                        $crate::private::Option::Some(
241                            |ptr: $crate::private::NonNull<u8>,
242                             $crate::private::PhantomData|
243                             -> &mut (dyn $trait + Sync) {
244                                unsafe { ptr.cast::<T>().as_mut() }
245                            },
246                        ),
247                    )));
248                }
249            }
250
251            impl<T: $trait + 'static> DispatchTraitBorrow<T> {
252                #[allow(unused)]
253                fn insert(
254                    &self,
255                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
256                ) {
257                    self.insert_one(extend);
258                }
259
260                fn insert_one(
261                    &self,
262                    extend: &mut $crate::private::Vec<$crate::component::ComponentBorrow>,
263                ) {
264                    extend.extend(Some($crate::component::ComponentBorrow::make(
265                        |ptr: $crate::private::NonNull<u8>, $crate::private::PhantomData| -> &dyn $trait {
266                            unsafe { ptr.cast::<T>().as_ref() }
267                        },
268                        $crate::private::Option::Some(
269                            |ptr: $crate::private::NonNull<u8>,
270                             $crate::private::PhantomData|
271                             -> &mut dyn $trait {
272                                unsafe { ptr.cast::<T>().as_mut() }
273                            },
274                        ),
275                    )));
276                }
277            }
278
279            let dispatch = DispatchTraitBorrowSendSync::<$self>::new();
280            dispatch.insert(&mut $borrows);
281        }};
282    }
283}
284
285impl ComponentBorrow {
286    /// Constructs `ComponentBorrow` from its fields.
287    /// Not public API. intended to be used by macros only.
288    #[doc(hidden)]
289    pub fn make<T: ?Sized + 'static>(
290        borrow: BorrowFn<T>,
291        borrow_mut: Option<BorrowFnMut<T>>,
292    ) -> Self {
293        ComponentBorrow {
294            ty: type_id::<T>(),
295            borrow: unsafe { transmute(borrow) },
296            borrow_mut: borrow_mut.map(|f| unsafe { transmute(f) }),
297        }
298    }
299
300    /// Creates new `ComponentBorrow` from type to borrow
301    /// using `Borrow` impl.
302    pub fn from_borrow<T, U>() -> Self
303    where
304        T: Borrow<U> + 'static,
305        U: ?Sized + 'static,
306    {
307        ComponentBorrow::make(|ptr, PhantomData| unsafe { ptr.cast::<T>().as_ref() }, None)
308    }
309
310    /// Creates new `ComponentBorrow` from type to borrow
311    /// using `BorrowMut` impl.
312    pub fn from_borrow_mut<T, U>() -> Self
313    where
314        T: Component + BorrowMut<U>,
315        U: ?Sized + 'static,
316    {
317        ComponentBorrow::make(
318            |ptr, PhantomData| unsafe { ptr.cast::<T>().as_ref() },
319            Some(|ptr, PhantomData| unsafe { ptr.cast::<T>().as_mut() }),
320        )
321    }
322
323    /// Returns type to borrow self.
324    pub fn auto<T>() -> Self
325    where
326        T: 'static,
327    {
328        ComponentBorrow::make(
329            |ptr, PhantomData| unsafe { ptr.cast::<T>().as_ref() },
330            Some(|ptr, PhantomData| unsafe { ptr.cast::<T>().as_mut() }),
331        )
332    }
333
334    pub(crate) fn target(&self) -> TypeId {
335        self.ty
336    }
337
338    pub(crate) fn borrow<'a, T: ?Sized + 'static>(&self) -> BorrowFn<T> {
339        debug_assert!(self.ty == type_id::<T>());
340        unsafe { transmute(self.borrow) }
341    }
342
343    pub(crate) fn has_borrow_mut(&self) -> bool {
344        self.borrow_mut.is_some()
345    }
346
347    pub(crate) fn borrow_mut<'a, T: ?Sized + 'static>(&self) -> Option<BorrowFnMut<T>> {
348        debug_assert!(self.ty == type_id::<T>());
349        unsafe { self.borrow_mut.map(|f| transmute(f)) }
350    }
351}
352
353/// Defines component properties and behavior.
354/// Types may implement this trait to act as components and support implicit self-registration.
355///
356/// Types that do not implement this trait may still be used as components.
357/// They are called "external", must be registered manually and require usage of
358/// [`World::spawn_external`], [`World::insert_external`], and [`World::insert_external_bundle`] methods that would panic
359/// when component type is not yet registered. Even if the type happens to implement [`Component`] trait.
360///
361/// [`World::spawn_external`]: edict::world::World::spawn_external
362/// [`World::insert_external`]: edict::world::World::insert_external
363/// [`World::insert_external_bundle`]: edict::world::World::insert_external_bundle
364pub trait Component: Sized + 'static {
365    /// Returns name of the component type.
366    #[inline(always)]
367    fn name() -> &'static str {
368        core::any::type_name::<Self>()
369    }
370
371    /// Hook that is executed when entity with component is dropped.
372    #[inline(always)]
373    fn on_drop(&mut self, id: EntityId, encoder: LocalActionEncoder) {
374        let _ = id;
375        let _ = encoder;
376    }
377
378    /// Hook that is executed whenever new value is assigned to the component.
379    /// If this method returns `true` then `on_remove` is executed for old value before assignment.
380    #[inline(always)]
381    fn on_replace(&mut self, value: &Self, id: EntityId, encoder: LocalActionEncoder) -> bool
382    where
383        Self: Sized,
384    {
385        let _ = value;
386        let _ = id;
387        let _ = encoder;
388        true
389    }
390
391    /// Returns array of component borrows supported by the type.
392    #[inline(always)]
393    fn borrows() -> Vec<ComponentBorrow> {
394        vec![ComponentBorrow::auto::<Self>()]
395    }
396}
397
398/// Type information required for components.
399#[derive(Clone)]
400pub struct ComponentInfo {
401    /// [`TypeId`] of the component.
402    ty: TypeId,
403
404    /// [`Layout`] of the component.
405    layout: Layout,
406
407    /// Name of the component.
408    name: &'static str,
409
410    /// Function that calls drop glue for a component.
411    /// Supports custom hooks.
412    drop_one: DropOneFn,
413
414    /// Context for `drop_one` command when component is dropped.
415    on_drop: Arc<dyn Any + Send + Sync>,
416
417    /// Function that replaces component at target location.
418    /// Supports custom hooks.
419    set_one: SetOneFn,
420
421    /// Context for `set_one` command.
422    on_replace: Arc<dyn Any + Send + Sync>,
423
424    /// Function that calls drop glue for a component.
425    /// Does not support custom hooks.
426    final_drop: FinalDrop,
427
428    /// An array of possible component borrows.
429    borrows: Arc<[ComponentBorrow]>,
430}
431
432impl ComponentInfo {
433    /// Returns component information for specified component type.
434    #[inline(always)]
435    pub fn of<T>() -> Self
436    where
437        T: Component,
438    {
439        ComponentInfo {
440            ty: type_id::<T>(),
441            layout: Layout::new::<T>(),
442            name: T::name(),
443            drop_one: drop_one::<T, DefaultDropHook>,
444            on_drop: Arc::new(DefaultDropHook),
445            set_one: set_one::<T, DefaultSetHook, DefaultDropHook>,
446            on_replace: Arc::new(DefaultSetHook),
447            final_drop: final_drop::<T>,
448            borrows: Arc::from(T::borrows()),
449        }
450    }
451
452    /// Returns component information for specified external type.
453    #[inline(always)]
454    pub fn external<T>() -> Self
455    where
456        T: 'static,
457    {
458        ComponentInfo {
459            ty: type_id::<T>(),
460            layout: Layout::new::<T>(),
461            name: type_name::<T>(),
462            drop_one: drop_one::<T, ExternalDropHook>,
463            on_drop: Arc::new(ExternalDropHook),
464            set_one: set_one::<T, ExternalSetHook, ExternalDropHook>,
465            on_replace: Arc::new(ExternalSetHook),
466            final_drop: final_drop::<T>,
467            borrows: vec![ComponentBorrow::auto::<T>()].into(),
468        }
469    }
470
471    #[inline(always)]
472    pub fn id(&self) -> TypeId {
473        self.ty
474    }
475
476    #[inline(always)]
477    pub fn layout(&self) -> Layout {
478        self.layout
479    }
480
481    #[inline(always)]
482    pub fn name(&self) -> &'static str {
483        self.name
484    }
485
486    #[inline(always)]
487    pub fn borrows(&self) -> &[ComponentBorrow] {
488        &self.borrows
489    }
490
491    #[inline(always)]
492    pub fn has_borrow(&self, ty: TypeId) -> bool {
493        self.borrows.iter().any(|b| b.target() == ty)
494    }
495
496    #[inline(always)]
497    pub fn has_borrow_mut(&self, ty: TypeId) -> bool {
498        self.borrows
499            .iter()
500            .find(|b| b.target() == ty)
501            .map_or(false, |b| b.has_borrow_mut())
502    }
503
504    #[inline(always)]
505    pub(crate) fn drop_one(&self, ptr: NonNull<u8>, id: EntityId, encoder: LocalActionEncoder) {
506        unsafe {
507            (self.drop_one)(NonNull::from(&*self.on_drop).cast(), ptr, id, encoder);
508        }
509    }
510
511    #[inline(always)]
512    pub(crate) fn set_one(
513        &self,
514        dst: NonNull<u8>,
515        src: NonNull<u8>,
516        id: EntityId,
517        encoder: LocalActionEncoder,
518    ) {
519        unsafe {
520            (self.set_one)(
521                NonNull::from(&*self.on_replace).cast(),
522                NonNull::from(&*self.on_drop).cast(),
523                dst,
524                src,
525                id,
526                encoder,
527            );
528        }
529    }
530
531    #[inline(always)]
532    pub(crate) fn final_drop(&self, ptr: NonNull<u8>, count: usize) {
533        unsafe {
534            (self.final_drop)(ptr, count);
535        }
536    }
537}
538
539/// Trait to be implemented by custom drop hooks.
540/// Has blanket implementation for `Fn(&mut T, EntityId, LocalActionEncoder)`.
541pub trait DropHook<T: ?Sized>: Send + Sync + 'static {
542    /// Called when entity with component is dropped.
543    fn on_drop(&self, component: &mut T, id: EntityId, encoder: LocalActionEncoder);
544}
545
546impl<T, F> DropHook<T> for F
547where
548    T: ?Sized,
549    F: Fn(&mut T, EntityId, LocalActionEncoder) + Send + Sync + 'static,
550{
551    #[inline(always)]
552    fn on_drop(&self, component: &mut T, id: EntityId, encoder: LocalActionEncoder) {
553        self(component, id, encoder);
554    }
555}
556
557/// Trait to be implemented by custom set hooks.
558/// Has blanket implementation for `Fn(&mut T, &T, EntityId, LocalActionEncoder)`.
559pub trait SetHook<T: ?Sized>: Send + Sync + 'static {
560    /// Called when new value is assigned to component instance.
561    /// By default fallbacks to drop hook.
562    fn on_replace(
563        &self,
564        component: &mut T,
565        value: &T,
566        id: EntityId,
567        encoder: LocalActionEncoder,
568    ) -> bool;
569}
570
571impl<T, F> SetHook<T> for F
572where
573    T: ?Sized,
574    F: Fn(&mut T, &T, EntityId, LocalActionEncoder) -> bool + Send + Sync + 'static,
575{
576    #[inline(always)]
577    fn on_replace(
578        &self,
579        component: &mut T,
580        value: &T,
581        id: EntityId,
582        encoder: LocalActionEncoder,
583    ) -> bool {
584        self(component, value, id, encoder)
585    }
586}
587
588/// Default drop hook type.
589#[derive(Clone, Copy, Debug)]
590pub struct DefaultDropHook;
591
592impl<T> DropHook<T> for DefaultDropHook
593where
594    T: Component,
595{
596    #[inline(always)]
597    fn on_drop(&self, component: &mut T, id: EntityId, encoder: LocalActionEncoder) {
598        T::on_drop(component, id, encoder);
599    }
600}
601
602/// Default set hook type.
603#[derive(Clone, Copy, Debug)]
604pub struct DefaultSetHook;
605
606impl<T> SetHook<T> for DefaultSetHook
607where
608    T: Component,
609{
610    #[inline(always)]
611    fn on_replace(&self, dst: &mut T, src: &T, id: EntityId, encoder: LocalActionEncoder) -> bool {
612        T::on_replace(dst, src, id, encoder)
613    }
614}
615
616/// External drop hook type.
617#[derive(Clone, Copy, Debug)]
618pub struct ExternalDropHook;
619
620impl<T> DropHook<T> for ExternalDropHook {
621    #[inline(always)]
622    fn on_drop(&self, _component: &mut T, _id: EntityId, _encoder: LocalActionEncoder) {}
623}
624
625/// External set hook type.
626#[derive(Clone, Copy, Debug)]
627pub struct ExternalSetHook;
628
629impl<T> SetHook<T> for ExternalSetHook {
630    #[inline(always)]
631    fn on_replace(
632        &self,
633        _dst: &mut T,
634        _src: &T,
635        _entity: EntityId,
636        _encoder: LocalActionEncoder,
637    ) -> bool {
638        true
639    }
640}
641
642/// Reference to registered [`ComponentInfo`].
643/// Allows user to setup custom drop and set hooks.
644pub struct ComponentInfoRef<
645    'a,
646    T: 'static,
647    D: DropHook<T> = DefaultDropHook,
648    S: SetHook<T> = DefaultSetHook,
649> {
650    info: Option<&'a mut ComponentInfo>,
651    phantom: PhantomData<T>,
652    drop: ManuallyDrop<D>,
653    set: ManuallyDrop<S>,
654    name: Option<&'static str>,
655}
656
657impl<T, D, S> Drop for ComponentInfoRef<'_, T, D, S>
658where
659    T: 'static,
660    D: DropHook<T>,
661    S: SetHook<T>,
662{
663    #[inline(always)]
664    fn drop(&mut self) {
665        self.drop_impl();
666    }
667}
668
669impl<'a, T, D, S> ComponentInfoRef<'a, T, D, S>
670where
671    T: 'static,
672    D: DropHook<T>,
673    S: SetHook<T>,
674{
675    #[inline(always)]
676    fn drop_impl(&mut self) {
677        let info = self.info.as_mut().unwrap();
678        info.drop_one = drop_one::<T, D>;
679        info.on_drop = Arc::new(unsafe { ManuallyDrop::take(&mut self.drop) });
680        info.set_one = set_one::<T, S, D>;
681        info.on_replace = Arc::new(unsafe { ManuallyDrop::take(&mut self.set) });
682        if let Some(name) = self.name {
683            info.name = name;
684        }
685    }
686
687    /// Finishes component registration.
688    /// Returns resulting [`ComponentInfo`]
689    pub fn finish(self) -> &'a ComponentInfo {
690        let mut me = ManuallyDrop::new(self);
691        me.drop_impl();
692        me.info.take().unwrap()
693    }
694
695    /// Configures drop hook for this component.
696    /// Drop hook is executed when component is dropped.
697    ///
698    /// This hook is not executed on shutdown when `Archetype` is dropped.
699    pub fn on_drop<F>(self, hook: F) -> ComponentInfoRef<'a, T, F, S>
700    where
701        F: DropHook<T>,
702    {
703        let me = ManuallyDrop::new(self);
704
705        ComponentInfoRef {
706            info: unsafe { ptr::read(&me.info) },
707            phantom: me.phantom,
708            drop: ManuallyDrop::new(hook),
709            set: unsafe { ptr::read(&me.set) },
710            name: me.name,
711        }
712    }
713
714    /// Configures drop hook for this component.
715    /// Drop hook is executed when component is dropped.
716    ///
717    /// This hook is not executed on shutdown when `Archetype` is dropped.
718    pub fn on_drop_fn<F>(self, hook: F) -> ComponentInfoRef<'a, T, F, S>
719    where
720        F: Fn(&mut T, EntityId, LocalActionEncoder) + Send + Sync + 'static,
721    {
722        self.on_drop(hook)
723    }
724
725    /// Configures set hook for this component.
726    /// Set hook is executed when component is assigned a new value.
727    ///
728    /// By default, set hook is calling `on_drop`.
729    pub fn on_replace<F>(self, hook: F) -> ComponentInfoRef<'a, T, D, F>
730    where
731        F: SetHook<T>,
732    {
733        let me = ManuallyDrop::new(self);
734
735        ComponentInfoRef {
736            info: unsafe { ptr::read(&me.info) },
737            phantom: me.phantom,
738            drop: unsafe { ptr::read(&me.drop) },
739            set: ManuallyDrop::new(hook),
740            name: me.name,
741        }
742    }
743
744    /// Configures set hook for this component.
745    /// Set hook is executed when component is assigned a new value.
746    ///
747    /// By default, set hook is calling `on_drop`.
748    pub fn on_replace_fn<F>(self, hook: F) -> ComponentInfoRef<'a, T, D, F>
749    where
750        F: Fn(&mut T, &T, EntityId, LocalActionEncoder) -> bool + Send + Sync + 'static,
751    {
752        self.on_replace(hook)
753    }
754
755    /// Overrides default component type name.
756    pub fn name(mut self, name: &'static str) -> Self {
757        self.name = Some(name);
758        self
759    }
760}
761
762/// Container for [`ComponentInfo`]s.
763pub(crate) struct ComponentRegistry {
764    components: HashMap<TypeId, ComponentInfo, NoOpHasherBuilder>,
765}
766
767impl ComponentRegistry {
768    pub const fn new() -> Self {
769        Self {
770            components: HashMap::with_hasher(NoOpHasherBuilder),
771        }
772    }
773
774    pub fn get_or_register<T>(&mut self) -> &ComponentInfo
775    where
776        T: Component,
777    {
778        self.components
779            .entry(type_id::<T>())
780            .or_insert_with(ComponentInfo::of::<T>)
781    }
782
783    pub fn get_or_register_raw(&mut self, info: ComponentInfo) -> &ComponentInfo {
784        self.components.entry(info.id()).or_insert(info)
785    }
786
787    pub fn register_raw(&mut self, info: ComponentInfo) {
788        match self.components.entry(info.id()) {
789            Entry::Occupied(_) => panic!("Component already registered"),
790            Entry::Vacant(e) => {
791                e.insert(info);
792            }
793        }
794    }
795
796    pub fn ensure_component_registered<T>(&mut self)
797    where
798        T: Component,
799    {
800        self.get_or_register_raw(ComponentInfo::of::<T>());
801    }
802
803    pub fn ensure_external_registered<T>(&mut self)
804    where
805        T: 'static,
806    {
807        self.get_or_register_raw(ComponentInfo::external::<T>());
808    }
809
810    pub fn register_component<'a, T>(&'a mut self) -> ComponentInfoRef<'a, T>
811    where
812        T: Component,
813    {
814        let info = match self.components.entry(type_id::<T>()) {
815            Entry::Occupied(_) => panic!("Component already registered"),
816            Entry::Vacant(e) => e.insert(ComponentInfo::of::<T>()),
817        };
818
819        ComponentInfoRef {
820            info: Some(info),
821            phantom: PhantomData,
822            drop: ManuallyDrop::new(DefaultDropHook),
823            set: ManuallyDrop::new(DefaultSetHook),
824            name: None,
825        }
826    }
827
828    pub fn register_external<'a, T>(
829        &'a mut self,
830    ) -> ComponentInfoRef<'a, T, ExternalDropHook, ExternalSetHook>
831    where
832        T: 'static,
833    {
834        let info = match self.components.entry(type_id::<T>()) {
835            Entry::Occupied(_) => panic!("Component already registered"),
836            Entry::Vacant(e) => e.insert(ComponentInfo::external::<T>()),
837        };
838
839        ComponentInfoRef {
840            info: Some(info),
841            phantom: PhantomData,
842            drop: ManuallyDrop::new(ExternalDropHook),
843            set: ManuallyDrop::new(ExternalSetHook),
844            name: None,
845        }
846    }
847
848    pub fn get_info(&self, ty: TypeId) -> Option<&ComponentInfo> {
849        self.components.get(&ty)
850    }
851
852    pub fn iter_info(&self) -> impl Iterator<Item = &ComponentInfo> {
853        self.components.values()
854    }
855}
856
857struct Opaque;
858
859type DropOneFn = unsafe fn(NonNull<Opaque>, NonNull<u8>, EntityId, LocalActionEncoder);
860type SetOneFn = unsafe fn(
861    NonNull<Opaque>,
862    NonNull<Opaque>,
863    NonNull<u8>,
864    NonNull<u8>,
865    EntityId,
866    LocalActionEncoder,
867);
868type FinalDrop = unsafe fn(NonNull<u8>, usize);
869
870unsafe fn drop_one<T, D>(
871    hook: NonNull<Opaque>,
872    ptr: NonNull<u8>,
873    id: EntityId,
874    encoder: LocalActionEncoder,
875) where
876    T: 'static,
877    D: DropHook<T>,
878{
879    let mut ptr = ptr.cast::<T>();
880    let hook = unsafe { hook.cast::<D>().as_ref() };
881    let value = unsafe { ptr.as_mut() };
882    hook.on_drop(value, id, encoder);
883    unsafe {
884        drop_in_place(value);
885    }
886}
887
888unsafe fn set_one<T, S, D>(
889    on_replace: NonNull<Opaque>,
890    on_drop: NonNull<Opaque>,
891    dst: NonNull<u8>,
892    src: NonNull<u8>,
893    id: EntityId,
894    mut encoder: LocalActionEncoder,
895) where
896    T: 'static,
897    S: SetHook<T>,
898    D: DropHook<T>,
899{
900    let src = unsafe { src.cast::<T>().as_ref() };
901    let dst = unsafe { dst.cast::<T>().as_mut() };
902    let on_replace = unsafe { on_replace.cast::<S>().as_ref() };
903    if on_replace.on_replace(dst, src, id, encoder.reborrow()) {
904        let on_drop = unsafe { on_drop.cast::<D>().as_ref() };
905        on_drop.on_drop(dst, id, encoder);
906    }
907    unsafe {
908        *dst = ptr::read(src);
909    }
910}
911
912/// This drop is always called for all components when `Archetype` is dropped.
913/// Does not invoke any hooks.
914unsafe fn final_drop<T>(ptr: NonNull<u8>, count: usize) {
915    let slice = slice_from_raw_parts_mut(ptr.cast::<T>().as_ptr(), count);
916    unsafe {
917        drop_in_place(slice);
918    }
919}
920
921/// Value component properties and behavior.
922pub trait Value: 'static {
923    /// Returns name of the component type.
924    fn name(&self) -> &'static str;
925}
926
927impl<T> Value for T
928where
929    T: Component,
930{
931    #[inline(always)]
932    fn name(&self) -> &'static str {
933        T::name()
934    }
935}