wormhole-engine 0.1.0

A portable, no-editor game engine with Rust core and Crystal scripting
Documentation
use libloading::{Library, Symbol};

type ScriptInitFn = unsafe extern "C" fn();
type ScriptUpdateFn = unsafe extern "C" fn(f32);
type ScriptRenderFn = unsafe extern "C" fn();

pub struct ScriptHost {
    _lib: Library,
    init_fn: Symbol<'static, ScriptInitFn>,
    update_fn: Symbol<'static, ScriptUpdateFn>,
    render_fn: Symbol<'static, ScriptRenderFn>,
}

impl ScriptHost {
    pub fn load(path: &std::path::Path) -> Result<Self, Box<dyn std::error::Error>> {
        let lib = unsafe { Library::new(path)? };

        unsafe {
            let init: Symbol<ScriptInitFn> = lib.get(b"script_init\0")?;
            let update: Symbol<ScriptUpdateFn> = lib.get(b"script_update\0")?;
            let render: Symbol<ScriptRenderFn> = lib.get(b"script_render\0")?;

            // Extract function pointers - these are valid as long as the library is loaded
            let init_fn = std::mem::transmute::<Symbol<ScriptInitFn>, Symbol<'static, ScriptInitFn>>(init);
            let update_fn = std::mem::transmute::<Symbol<ScriptUpdateFn>, Symbol<'static, ScriptUpdateFn>>(update);
            let render_fn = std::mem::transmute::<Symbol<ScriptRenderFn>, Symbol<'static, ScriptRenderFn>>(render);

            Ok(ScriptHost {
                _lib: lib,
                init_fn,
                update_fn,
                render_fn,
            })
        }
    }

    pub fn call_init(&self) {
        unsafe {
            (self.init_fn)();
        }
    }

    pub fn call_update(&self, delta: f32) {
        unsafe {
            (self.update_fn)(delta);
        }
    }

    pub fn call_render(&self) {
        unsafe {
            (self.render_fn)();
        }
    }
}