tm_rs/
component.rs

1use std::marker::PhantomData;
2
3use tm_sys::ffi::{
4    tm_engine_update_array_t, tm_engine_update_set_t, tm_entity_context_o, tm_the_truth_o,
5};
6
7use crate::{entity::EntityApiInstanceMut, hash};
8
9pub trait Component {
10    const NAME: &'static [u8];
11    type CType: Copy;
12}
13
14pub trait DerivedComponent: Component {
15    const CREATE_TYPES: Option<unsafe extern "C" fn(*mut tm_the_truth_o)>;
16    const CREATE_COMPONENT: unsafe extern "C" fn(*mut tm_entity_context_o);
17}
18
19pub trait Accessor {
20    const WRITE: bool;
21    type C: Component;
22    type RefT;
23
24    #[allow(clippy::missing_safety_doc)]
25    unsafe fn ref_from_ptr(ptr: *mut <Self::C as Component>::CType) -> Self::RefT;
26}
27
28pub struct Read<'a, C: Component + 'a> {
29    _r: PhantomData<&'a C>,
30}
31
32impl<'a, C: Component> Accessor for Read<'a, C> {
33    const WRITE: bool = false;
34    type C = C;
35    type RefT = &'a C::CType;
36
37    #[inline]
38    unsafe fn ref_from_ptr(ptr: *mut <Self::C as Component>::CType) -> Self::RefT {
39        ptr.as_ref().unwrap()
40    }
41}
42
43pub struct Write<'a, C: Component + 'a> {
44    _w: PhantomData<&'a mut C>,
45}
46
47impl<'a, C: Component> Accessor for Write<'a, C> {
48    const WRITE: bool = true;
49    type C = C;
50    type RefT = &'a mut C::CType;
51
52    #[inline]
53    unsafe fn ref_from_ptr(ptr: *mut <Self::C as Component>::CType) -> Self::RefT {
54        ptr.as_mut().unwrap()
55    }
56}
57
58pub struct ComponentsIterator<'a, C> {
59    arrays: &'a [tm_engine_update_array_t],
60    arrays_index: usize,
61    components_index: usize,
62    phantom_data: PhantomData<C>,
63}
64
65impl<'a, C> ComponentsIterator<'a, C> {
66    #[inline]
67    pub fn new(update_set: &'a mut tm_engine_update_set_t) -> Self {
68        Self {
69            arrays: unsafe {
70                (*update_set)
71                    .arrays
72                    .as_mut_slice((*update_set).num_arrays as usize)
73            },
74            arrays_index: 0,
75            components_index: 0,
76            phantom_data: PhantomData,
77        }
78    }
79}
80
81pub trait ComponentTuple {
82    fn get_components(entity_api: &mut EntityApiInstanceMut) -> [u32; 16];
83    fn get_writes() -> [bool; 16];
84    fn get_count() -> u32;
85}
86
87macro_rules! replace_expr {
88    ($_i:ident, $sub:expr) => {
89        $sub
90    };
91}
92
93macro_rules! replace_lit {
94    ($_t:literal, $sub:expr) => {
95        $sub
96    };
97}
98
99macro_rules! count_idents {
100    ($($tts:ident),*) => {
101        0u32 $(+ replace_expr!($tts, 1u32))*
102    };
103}
104
105macro_rules! impl_component_tuple {
106    ($($t:ident),* $(,)* $($none:literal),*) => {
107
108        paste::paste! {
109            impl<'a, $($t),*> Iterator for ComponentsIterator<'a, ($($t),*,)>
110            where
111                $($t: Accessor),*
112            {
113                type Item = ($($t::RefT),*,);
114
115                #[inline]
116                fn next(&mut self) -> Option<Self::Item> {
117                    if self.arrays_index >= self.arrays.len() {
118                        return None;
119                    }
120
121                    let mut array = &self.arrays[self.arrays_index];
122
123                    if self.components_index >= array.n as usize {
124                        self.arrays_index += 1;
125                        self.components_index = 0;
126
127                        if self.arrays_index >= self.arrays.len() {
128                            return None;
129                        }
130
131                        array = &self.arrays[self.arrays_index];
132                    }
133
134                    #[allow(unused_assignments)]
135                    unsafe {
136
137                        let mut component_count = 0;
138
139                        $(
140                            let [<$t:lower>] = (array.components[component_count] as *mut <$t::C as Component>::CType)
141                                .add(self.components_index);
142
143                            component_count += 1;
144                        )*
145
146                        self.components_index += 1;
147
148                        Some(($($t::ref_from_ptr([<$t:lower>])),*,))
149                    }
150                }
151            }
152        }
153
154        impl<$($t),*> ComponentTuple for ($($t),*,)
155        where
156            $($t: Accessor),*
157        {
158            #[inline]
159            fn get_components(entity_api: &mut $crate::entity::EntityApiInstanceMut) -> [u32; 16] {
160                [
161                    $(entity_api.lookup_component(hash($t::C::NAME))),*,
162                    $(replace_lit!($none, 0)),*
163                ]
164            }
165
166            #[inline]
167            fn get_writes() -> [bool; 16] {
168                [
169                    $($t::WRITE),*,
170                    $(replace_lit!($none, false)),*
171                ]
172            }
173
174            #[inline]
175            fn get_count() -> u32 {
176                count_idents!($($t),*)
177            }
178        }
179    };
180}
181
182impl_component_tuple!(A, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
183impl_component_tuple!(A, B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
184impl_component_tuple!(A, B, C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
185impl_component_tuple!(A, B, C, D, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
186impl_component_tuple!(A, B, C, D, E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
187impl_component_tuple!(A, B, C, D, E, F, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
188impl_component_tuple!(A, B, C, D, E, F, G, 0, 0, 0, 0, 0, 0, 0, 0, 0);
189impl_component_tuple!(A, B, C, D, E, F, G, H, 0, 0, 0, 0, 0, 0, 0, 0);
190impl_component_tuple!(A, B, C, D, E, F, G, H, I, 0, 0, 0, 0, 0, 0, 0);
191impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, 0, 0, 0, 0, 0, 0);
192impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, 0, 0, 0, 0, 0);
193impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, 0, 0, 0, 0);
194impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, 0, 0, 0);
195impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, 0, 0);
196impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, 0);
197impl_component_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);