use std::ffi::{CString,CStr}; use std::mem::MaybeUninit; mod wren; pub struct Config { config: wren::WrenConfiguration, } pub struct VM { vm: *mut wren::WrenVM, } impl Config { fn init() -> Config { extern "C" fn write_fn(_vm: *mut wren::WrenVM, text: *const i8) { let s = unsafe { CStr::from_ptr(text) }; print!("{}", s.to_str().unwrap()); } unsafe { let mut config = MaybeUninit::uninit(); wren::wrenInitConfiguration(config.as_mut_ptr()); let mut config = config.assume_init(); config.writeFn = Some(write_fn); Config { config: config } } } fn mk_vm(&mut self) -> VM { let vm = unsafe { wren::wrenNewVM(&mut self.config as *mut _) }; VM { vm } } } impl VM { fn interpret(&self, module: &str, code: &str) -> bool { let mod_str = CString::new(module).unwrap(); let code_str = CString::new(code).unwrap(); let result = unsafe { wren::wrenInterpret(self.vm, mod_str.as_ptr(), code_str.as_ptr()) }; result == 0 } fn ensure_slots(&self, n: i32) { unsafe { wren::wrenEnsureSlots(self.vm, n) } } fn call_handle(&self, sig: &str) -> Option { unsafe { let sig_str = CString::new(sig).unwrap(); let handle = wren::wrenMakeCallHandle(self.vm, sig_str.as_ptr()); if handle.is_null() { None } else { Some(Handle { handle, vm: self }) } } } } impl Drop for VM { fn drop(&mut self) { unsafe { wren::wrenFreeVM(self.vm) } } } struct Handle<'a> { vm: &'a VM, handle: *mut wren::WrenHandle, } impl<'t> Handle<'t> { fn call(&self, args: &[&dyn WrenValue]) { self.vm.ensure_slots(args.len() as i32); for (i, v) in args.iter().enumerate() { v.set_slot(&self.vm, i as i32); } unsafe { wren::wrenCall(self.vm.vm, self.handle); } } } impl<'t> Drop for Handle<'t> { fn drop(&mut self) { unsafe { wren::wrenReleaseHandle(self.vm.vm, self.handle) } } } fn c_str(s: &str) -> CString { CString::new(s).unwrap() } trait WrenValue { // fn get_slot(vm: &VM, slot: i32) -> Self; fn set_slot(&self, vm: &VM, slot: i32); } impl WrenValue for String { fn set_slot(&self, vm: &VM, slot: i32) { unsafe { wren::wrenSetSlotString(vm.vm, slot, c_str(self).as_ptr()) } } } struct Var { module: &'static str, name: &'static str, } impl WrenValue for Var { fn set_slot(&self, vm: &VM, slot: i32) { unsafe { wren::wrenGetVariable(vm.vm, c_str(self.module).as_ptr(), c_str(self.name).as_ptr(), slot); } } } fn main() { let vm = Config::init().mk_vm(); vm.interpret("main", "class Foo { static hello(name) { System.print(\"what's up, %(name)\") } }"); let hello = vm.call_handle("hello(_)").unwrap(); hello.call(&[ &Var { module: "main", name: "Foo" }, &format!("my dog"), ]); }