tm-rs 2020.11.11

FFI bindings for the machinery api
Documentation
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,
            );
        }
    };
}