1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use crate::private::ArchetypeMetadata;
use std::any::{Any, TypeId};
use std::mem::MaybeUninit;
use std::{mem, ptr};

/// Defines archetype objects (entity states) with definite components.
pub trait ArchetypeState: Send + Sync + 'static {
    fn ty(&self) -> TypeId;
    fn as_ptr(&self) -> *const u8;
    fn forget(self);
    fn metadata(&self) -> fn() -> ArchetypeMetadata;
}

/// Defines archetype objects (entity states).
pub trait StaticArchetype: ArchetypeState {
    const N_COMPONENTS: usize;

    fn into_any(self) -> AnyState
    where
        Self: Sized + 'static,
    {
        let ty = self.type_id();
        let size = mem::size_of::<Self>();
        let metadata = self.metadata();

        let mut data = Vec::<u8>::with_capacity(size);
        unsafe {
            ptr::write(data.as_mut_ptr() as *mut Self, self);
            data.set_len(size);
        }

        AnyState { ty, data, metadata }
    }
}

/// Entity state with arbitrary components.
pub struct AnyState {
    pub(crate) ty: TypeId,
    pub(crate) data: Vec<u8>,
    pub(crate) metadata: fn() -> ArchetypeMetadata,
}

impl AnyState {
    pub fn into_static<S: StaticArchetype>(mut self) -> Option<S> {
        if TypeId::of::<S>() != self.ty {
            return None;
        }

        let mut result = MaybeUninit::<S>::uninit();

        unsafe {
            let src_ptr = self.data.as_ptr() as *const S;
            src_ptr.copy_to_nonoverlapping(result.as_mut_ptr(), mem::size_of::<S>());

            (&mut self.data as *mut Vec<_>).drop_in_place();
            mem::forget(self);

            Some(result.assume_init())
        }
    }
}

impl ArchetypeState for AnyState {
    fn ty(&self) -> TypeId {
        self.ty
    }

    fn as_ptr(&self) -> *const u8 {
        self.data.as_ptr()
    }

    fn forget(mut self) {
        unsafe { (&mut self.data as *mut Vec<_>).drop_in_place() };
        mem::forget(self);
    }

    fn metadata(&self) -> fn() -> ArchetypeMetadata {
        self.metadata
    }
}

impl<T: StaticArchetype> From<T> for AnyState {
    fn from(state: T) -> Self {
        state.into_any()
    }
}

impl Clone for AnyState {
    fn clone(&self) -> Self {
        let data = (self.metadata()().clone_func)(self.data.as_ptr());
        Self {
            ty: self.ty,
            data,
            metadata: self.metadata,
        }
    }
}

impl Drop for AnyState {
    fn drop(&mut self) {
        (self.metadata()().drop_func)(self.data.as_mut_ptr());
    }
}