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
use tm_sys::ffi::{
    TM_ENTITY_CREATE_COMPONENT_INTERFACE_NAME, TM_THE_TRUTH_CREATE_TYPES_INTERFACE_NAME,
};

use crate::component::DerivedComponent;

use super::ffi;
use std::{ffi::c_void, os::raw::c_char};

pub struct RegistryApi {
    reg: *mut ffi::tm_api_registry_api,
    load: bool,
}

impl RegistryApi {
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn new(reg: *mut ffi::tm_api_registry_api, load: bool) -> Self {
        assert!(!reg.is_null());
        Self { reg, load }
    }

    #[inline]
    pub fn get(&mut self, name: &[u8]) -> *mut c_void {
        unsafe { (*self.reg).get.unwrap()(name.as_ptr() as *const c_char) }
    }

    #[inline]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn add_implementation(&mut self, name: &[u8], implementation: *mut c_void) {
        assert!(!implementation.is_null());
        (*self.reg).add_implementation.unwrap()(name.as_ptr() as *const c_char, implementation)
    }

    #[inline]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn remove_implementation(&mut self, name: &[u8], implementation: *mut c_void) {
        assert!(!implementation.is_null());
        (*self.reg).remove_implementation.unwrap()(name.as_ptr() as *const c_char, implementation)
    }

    #[inline]
    #[allow(clippy::missing_safety_doc)]
    pub unsafe fn add_or_remove_implementation(&mut self, name: &[u8], ptr: *mut c_void) {
        assert!(!ptr.is_null());

        if self.load {
            self.add_implementation(name, ptr);
        } else {
            self.remove_implementation(name, ptr);
        }
    }

    pub fn add_or_remove_component<C: DerivedComponent>(&mut self) {
        unsafe {
            if let Some(create_types) = C::CREATE_TYPES {
                self.add_or_remove_implementation(
                    TM_THE_TRUTH_CREATE_TYPES_INTERFACE_NAME,
                    create_types as *mut c_void,
                );
            }
            self.add_or_remove_implementation(
                TM_ENTITY_CREATE_COMPONENT_INTERFACE_NAME,
                C::CREATE_COMPONENT as *mut c_void,
            );
        }
    }
}

#[macro_export]
macro_rules! add_or_remove_entity_simulation {
    ($reg:expr, $name:ident) => {
        $crate::paste::paste! {
            unsafe extern "C" fn [<$name _extern>](ctx: *mut $crate::ffi::tm_entity_context_o) {
                assert!(!ctx.is_null());

                let mut entity_api = $crate::api::with_ctx_mut::<$crate::entity::EntityApi>(ctx);

                $name(&mut entity_api);
            }

            $reg.add_or_remove_implementation(
                $crate::ffi::TM_ENTITY_SIMULATION_INTERFACE_NAME,
                [<$name _extern>] as *mut ::std::ffi::c_void,
            );
        }
    };
}