1use crate::{
2 api::{self, Api, ApiWithCtx, ApiWithCtxMut},
3 component::{ComponentTuple, ComponentsIterator},
4};
5use std::{
6 ffi::{c_void, CString},
7};
8use tm_sys::ffi::{
9 tm_component_i, tm_component_mask_t, tm_engine_i, tm_engine_o, tm_engine_update_set_t,
10 tm_entity_api, tm_entity_context_o, TM_ENTITY_API_NAME,
11};
12
13#[derive(Copy, Clone)]
14pub struct EntityApi {
15 api: *mut tm_entity_api,
16}
17
18unsafe impl Send for EntityApi {}
19unsafe impl Sync for EntityApi {}
20
21impl Api for EntityApi {
22 type CType = *mut tm_entity_api;
23 const NAME: &'static [u8] = TM_ENTITY_API_NAME;
24
25 #[inline]
26 fn new(api: *mut c_void) -> Self {
27 Self {
28 api: api as Self::CType,
29 }
30 }
31}
32
33#[derive(Copy, Clone)]
34pub struct EntityApiInstance {
35 pub api: *mut tm_entity_api,
36 pub ctx: *const tm_entity_context_o,
37}
38
39#[derive(Copy, Clone)]
40pub struct EntityApiInstanceMut {
41 pub api: *mut tm_entity_api,
42 pub ctx: *mut tm_entity_context_o,
43}
44
45impl ApiWithCtx for EntityApi {
46 type Ctx = tm_entity_context_o;
47 type ApiInstance = EntityApiInstance;
48
49 #[inline]
50 fn wrap(self, ctx: *const Self::Ctx) -> Self::ApiInstance {
51 EntityApiInstance { api: self.api, ctx }
52 }
53}
54
55impl ApiWithCtxMut for EntityApi {
56 type ApiInstanceMut = EntityApiInstanceMut;
57
58 #[inline]
59 fn wrap_mut(self, ctx: *mut Self::Ctx) -> Self::ApiInstanceMut {
60 EntityApiInstanceMut { api: self.api, ctx }
61 }
62}
63
64struct EngineCallbackData {
65 ctx: *mut tm_entity_context_o,
66 update: Box<dyn Fn(*mut tm_entity_context_o, &mut tm_engine_update_set_t)>,
67}
68
69unsafe extern "C" fn engine_update(inst: *mut tm_engine_o, data: *mut tm_engine_update_set_t) {
70 assert!(!inst.is_null());
71 assert!(!data.is_null());
72
73 let callback_data = (inst as *const EngineCallbackData).as_ref().unwrap();
74
75 (callback_data.update)(callback_data.ctx, data.as_mut().unwrap());
76}
77
78impl EntityApiInstanceMut {
79 #[inline]
80 pub fn lookup_component(&mut self, name_hash: u64) -> u32 {
81 unsafe { (*self.api).lookup_component.unwrap()(self.ctx, name_hash) }
82 }
83
84 #[inline]
85 pub fn register_engine<C>(
86 &mut self,
87 name: &'static str,
88 update: impl Fn(&mut EntityApiInstanceMut, ComponentsIterator<C>) + Send + Sync + 'static,
89 ) where
90 C: ComponentTuple,
91 {
92 let name = CString::new(name).unwrap();
93
94 let inst = Box::into_raw(Box::new(EngineCallbackData {
96 ctx: self.ctx,
97 update: Box::new(move |ctx, update_set| {
98 let mut entity_api = api::with_ctx_mut::<EntityApi>(ctx);
99 let components = ComponentsIterator::<C>::new(update_set);
100 update(&mut entity_api, components)
101 }),
102 })) as *mut tm_engine_o;
103
104 let engine = tm_engine_i {
105 name: name.as_ptr(),
106 disabled: false,
107 _padding_215: [0; 3],
108 num_components: C::get_count(),
109 components: C::get_components(self),
110 excludes: [false; 16],
111 writes: C::get_writes(),
112 inst,
113 update: Some(engine_update),
114 filter: None,
115 };
116
117 unsafe {
118 (*self.api).register_engine.unwrap()(
119 self.ctx,
120 &engine as *const ::tm_sys::ffi::tm_engine_i,
121 );
122 }
123 }
124
125 #[inline]
126 pub fn register_component(&mut self, component: &tm_component_i) -> u32 {
127 unsafe {
128 (*self.api).register_component.unwrap()(
129 self.ctx,
130 component as *const ::tm_sys::ffi::tm_component_i,
131 )
132 }
133 }
134}
135
136#[inline]
137pub fn mask_has_component(mask: &tm_component_mask_t, i: u32) -> bool {
138 (mask.bits[(i / 64) as usize] & (1 << (i % 64))) > 0
139}