use crate::SCM;
use std::ffi::c_void;
use crate::raw;
pub trait ForeignType {
fn type_name(&self) -> String;
fn slots(&self) -> Vec<String>;
fn slot_vals(&self) -> Vec<*mut c_void> {
vec![]
}
fn need_finalizer(&self) -> bool { false }
fn finalizer(&self) -> unsafe extern "C" fn(scm:*mut raw::scm_unused_struct) {
unsafe extern "C" fn default_finalizer(_scm: *mut raw::scm_unused_struct) {
}
default_finalizer
}
fn type_of(&self) -> SCM {
self.new_type()
}
fn new_type(&self) -> SCM {
let scm_name = SCM::from(self.type_name()).string_to_symbol();
let symbols:Vec<SCM> = self.slots().into_iter()
.map(SCM::from)
.map(|s| s.string_to_symbol())
.collect();
let scm_slots = SCM::list(symbols.as_slice());
let finalizer = if self.need_finalizer() {
Some(self.finalizer())
} else {
None
};
let scm_type = unsafe {
raw::scm_make_foreign_object_type(scm_name.0, scm_slots.0, finalizer)
};
SCM::new(scm_type)
}
}
impl<T:ForeignType> From<T> for SCM {
fn from(foreign: T) -> Self {
let scm_type = foreign.type_of();
let slot_vals = foreign.slot_vals();
let slot_num = foreign.slots().len();
let scm_obj = unsafe {
raw::scm_make_foreign_object_n(scm_type.0, slot_num, slot_vals.as_ptr() as *mut *mut c_void)
};
SCM::new(scm_obj)
}
}