tm_rs/
entity.rs

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        // This is leaked
95        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}