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);