use crate::types::{GlobalVariable, OnFunction, HelperFunction, GrugScriptId, GrugEntity, GrugValue};
use crate::state::GrugState;
use std::ptr::NonNull;
#[derive(Debug)]
pub struct GrugAst {
pub(crate) global_variables: Vec<GlobalVariable>,
pub(crate) on_functions: Vec<Option<OnFunction>>,
pub(crate) helper_functions: Vec<HelperFunction>,
}
pub mod interpreter;
pub use interpreter::Interpreter;
pub mod bytecode;
pub use bytecode::BytecodeBackend;
pub unsafe trait Backend {
fn insert_file(&self, state: &GrugState, id: GrugScriptId, file: GrugAst);
#[must_use]
fn init_entity<'a>(&self, state: &'a GrugState, entity: &GrugEntity) -> bool;
fn clear_entities(&mut self);
#[must_use]
fn destroy_entity_data(&self, entity: &GrugEntity) -> bool;
#[must_use]
unsafe fn call_on_function_raw(&self, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: *const GrugValue) -> bool;
#[must_use]
fn call_on_function(&self, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: &[GrugValue]) -> bool;
}
const _: () = unsafe{const {std::mem::forget(std::mem::MaybeUninit::<Option<ErasedBackend>>::zeroed().assume_init())}};
const _: () = const {assert!(std::mem::size_of::<Option<ErasedBackend>>() == std::mem::size_of::<ErasedBackend>())};
#[repr(C)]
pub struct ErasedBackend {
pub data: NonNull<()>,
pub vtable: &'static BackendVTable,
}
#[repr(C)]
pub struct BackendVTable {
pub(crate) insert_file : unsafe fn(data: NonNull<()>, state: &GrugState, id: GrugScriptId, file: GrugAst),
pub(crate) init_entity : extern "C" fn(data: NonNull<()>, state: &GrugState, entity: &GrugEntity) -> bool,
pub(crate) clear_entities : extern "C" fn(data: NonNull<()>),
pub(crate) destroy_entity_data : extern "C" fn(data: NonNull<()>, entity: &GrugEntity) -> bool,
pub(crate) call_on_function_raw: unsafe extern "C" fn(data: NonNull<()>, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: *const GrugValue) -> bool,
pub(crate) call_on_function : fn(data: NonNull<()>, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: &[GrugValue]) -> bool,
pub(crate) drop : extern "C" fn(data: NonNull<()>),
}
impl ErasedBackend {
pub fn insert_file(&self, state: &GrugState, id: GrugScriptId, file: GrugAst) {
unsafe{(self.vtable.insert_file)(self.data, state, id, file)}
}
pub fn init_entity<'a>(&self, state: &'a GrugState, entity: &GrugEntity) -> bool {
(self.vtable.init_entity)(self.data, state, entity)
}
pub fn clear_entities(&mut self) {
(self.vtable.clear_entities)(self.data)
}
pub fn destroy_entity_data(&self, entity: &GrugEntity) -> bool {
(self.vtable.destroy_entity_data)(self.data, entity)
}
pub unsafe fn call_on_function_raw(&self, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: *const GrugValue) -> bool {
unsafe{(self.vtable.call_on_function_raw)(self.data, state, entity, on_fn_index, values)}
}
pub fn call_on_function(&self, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: &[GrugValue]) -> bool {
(self.vtable.call_on_function)(self.data, state, entity, on_fn_index, values)
}
}
impl Drop for ErasedBackend {
fn drop (&mut self) {
(self.vtable.drop)(self.data)
}
}
impl<T: Backend> From<T> for ErasedBackend {
fn from(other: T) -> Self {
unsafe fn insert_file<T: Backend>(data: NonNull<()>, state: &GrugState, id: GrugScriptId, file: GrugAst) {
T::insert_file(
unsafe{data.cast::<T>().as_ref()},
state,
id,
file
)
}
extern "C" fn init_entity<T: Backend>(data: NonNull<()>, state: &GrugState, entity: &GrugEntity) -> bool {
T::init_entity(
unsafe{data.cast::<T>().as_ref()},
state,
entity
)
}
extern "C" fn clear_entities<T: Backend>(data: NonNull<()>) {
T::clear_entities(
unsafe{data.cast::<T>().as_mut()},
)
}
extern "C" fn destroy_entity_data<T: Backend>(data: NonNull<()>, entity: &GrugEntity) -> bool {
T::destroy_entity_data(
unsafe{data.cast::<T>().as_ref()},
entity
)
}
unsafe extern "C" fn call_on_function_raw<T: Backend>(data: NonNull<()>, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: *const GrugValue) -> bool {
unsafe{T::call_on_function_raw(
data.cast::<T>().as_ref(),
state,
entity,
on_fn_index,
values
)}
}
fn call_on_function<T: Backend>(data: NonNull<()>, state: &GrugState, entity: &GrugEntity, on_fn_index: usize, values: &[GrugValue]) -> bool {
T::call_on_function(
unsafe{data.cast::<T>().as_ref()},
state,
entity,
on_fn_index,
values
)
}
extern "C" fn drop<T: Backend>(data: NonNull<()>) {
_ = unsafe{Box::from_raw(data.cast::<T>().as_ptr())};
}
Self {
data: unsafe{NonNull::new_unchecked(Box::into_raw(Box::new(other))).cast::<()>()},
vtable: &BackendVTable {
insert_file : insert_file::<T>,
init_entity : init_entity::<T>,
clear_entities : clear_entities::<T>,
destroy_entity_data : destroy_entity_data::<T>,
call_on_function_raw: call_on_function_raw::<T>,
call_on_function : call_on_function::<T>,
drop : drop::<T>,
}
}
}
}