use std::mem;
use std::slice;
use std::ffi::{CStr, CString};
use libc::{c_int, c_char};
use ffi;
use {ErrorType, Type, Pointer, InterpretResult};
fn default_write(_: &mut VM, text: &str) {
print!("{}", text);
}
fn default_error(_: &mut VM, _type: ErrorType, module: &str, line: i32, message: &str) {
match _type {
ErrorType::Compile => println!("[{} line {}] {}", module, line, message),
ErrorType::Runtime => println!("{}", message),
ErrorType::StackTrace => println!("[{} line {}] in {}", module, line, message),
}
}
fn default_load_module(_: &mut VM, name: &str) -> Option<String> {
use std::path::PathBuf;
use std::fs::File;
use std::io::Read;
let mut buffer = String::new();
let mut name_path = PathBuf::new();
name_path.push(name);
name_path.set_extension("wren");
let result = File::open(&name_path).map(|mut f| f.read_to_string(&mut buffer));
if result.is_ok() {
return Some(buffer);
}
name_path.set_extension("");
name_path.push("module");
name_path.set_extension("wren");
buffer.clear();
let result = File::open(&name_path).map(|mut f| f.read_to_string(&mut buffer));
if result.is_ok() { Some(buffer) } else { None }
}
pub struct Configuration(ffi::WrenConfiguration);
impl Configuration {
pub fn new() -> Configuration {
let mut raw: ffi::WrenConfiguration = unsafe { mem::uninitialized() };
unsafe { ffi::wrenInitConfiguration(&mut raw) }
let mut cfg = Configuration(raw);
cfg.set_write_fn(wren_write_fn!(default_write));
cfg.set_error_fn(wren_error_fn!(default_error));
cfg.set_load_module_fn(wren_load_module_fn!(default_load_module));
cfg
}
pub fn set_reallocate_fn(&mut self, f: ::ReallocateFn) {
self.0.reallocate_fn = f;
}
pub fn set_load_module_fn(&mut self, f: ::LoadModuleFn) {
self.0.load_module_fn = f;
}
pub fn set_bind_foreign_method_fn(&mut self, f: ::BindForeignMethodFn) {
self.0.bind_foreign_method_fn = f;
}
pub fn set_bind_foreign_class_fn(&mut self, f: ::BindForeignClassFn) {
self.0.bind_foreign_class_fn = f;
}
pub fn set_write_fn(&mut self, f: ::WriteFn) {
self.0.write_fn = f;
}
pub fn set_error_fn(&mut self, f: ::ErrorFn) {
self.0.error_fn = f;
}
pub fn set_initial_heap_size(&mut self, size: usize) {
self.0.initial_heap_size = size;
}
pub fn set_min_heap_size(&mut self, size: usize) {
self.0.min_heap_size = size;
}
pub fn set_heap_growth_percent(&mut self, percent: i32) {
self.0.heap_growth_percent = percent;
}
pub fn set_user_data(&mut self, data: Pointer) {
self.0.user_data = data;
}
}
#[derive(Copy, Clone)]
pub struct Handle(*mut ffi::WrenHandle);
#[derive(Copy, Clone)]
pub struct ForeignClassMethods(ffi::WrenForeignClassMethods);
impl ForeignClassMethods {
pub fn new() -> ForeignClassMethods {
ForeignClassMethods(ffi::WrenForeignClassMethods {
allocate: None,
finalize: None,
})
}
pub fn set_allocate_fn(&mut self, f: ::ForeignMethodFn) {
self.0.allocate = f;
}
pub fn set_finalize_fn(&mut self, f: ::FinalizerFn) {
self.0.finalize = f;
}
#[doc(hidden)]
pub fn get(&self) -> ffi::WrenForeignClassMethods {
self.0
}
}
pub struct VM {
raw: *mut ffi::WrenVM,
owned: bool,
}
impl VM {
pub fn new(cfg: Configuration) -> VM {
let mut cfg = cfg;
let raw = unsafe { ffi::wrenNewVM(&mut cfg.0) };
VM { raw, owned: true }
}
pub unsafe fn from_ptr(ptr: *mut ffi::WrenVM) -> VM {
VM {
raw: ptr,
owned: false,
}
}
pub fn collect_garbage(&mut self) {
unsafe { ffi::wrenCollectGarbage(self.raw) }
}
pub fn interpret(&mut self, source: &str) -> InterpretResult {
let source_cstr = CString::new(source).unwrap();
unsafe { ffi::wrenInterpret(self.raw, source_cstr.as_ptr()) }
}
pub fn make_call_handle(&mut self, signature: &str) -> Handle {
let signature_cstr = CString::new(signature).unwrap();
let handle = unsafe { ffi::wrenMakeCallHandle(self.raw, signature_cstr.as_ptr()) };
Handle(handle)
}
pub fn call(&mut self, method: Handle) -> InterpretResult {
unsafe { ffi::wrenCall(self.raw, method.0) }
}
pub fn release_handle(&mut self, handle: Handle) {
unsafe { ffi::wrenReleaseHandle(self.raw, handle.0) }
}
pub fn get_slot_count(&mut self) -> i32 {
unsafe { ffi::wrenGetSlotCount(self.raw) }
}
pub fn ensure_slots(&mut self, num_slots: i32) {
unsafe { ffi::wrenEnsureSlots(self.raw, num_slots) }
}
pub fn get_slot_type(&mut self, slot: i32) -> Type {
unsafe { ffi::wrenGetSlotType(self.raw, slot) }
}
pub fn get_slot_bool(&mut self, slot: i32) -> bool {
unsafe { ffi::wrenGetSlotBool(self.raw, slot) != 0 }
}
pub fn get_slot_bytes(&mut self, slot: i32) -> &[u8] {
let mut length = unsafe { mem::uninitialized() };
let ptr = unsafe { ffi::wrenGetSlotBytes(self.raw, slot, &mut length) };
unsafe { slice::from_raw_parts(ptr as *const u8, length as usize) }
}
pub fn get_slot_double(&mut self, slot: i32) -> f64 {
unsafe { ffi::wrenGetSlotDouble(self.raw, slot) }
}
pub fn get_slot_foreign(&mut self, slot: i32) -> Pointer {
unsafe { ffi::wrenGetSlotForeign(self.raw, slot) }
}
pub fn get_slot_string(&mut self, slot: i32) -> &str {
let ptr = unsafe { ffi::wrenGetSlotString(self.raw, slot) };
unsafe { CStr::from_ptr(ptr).to_str().unwrap() }
}
pub fn get_slot_handle(&mut self, slot: i32) -> Handle {
let handle = unsafe { ffi::wrenGetSlotHandle(self.raw, slot) };
Handle(handle)
}
pub fn set_slot_bool(&mut self, slot: i32, value: bool) {
unsafe { ffi::wrenSetSlotBool(self.raw, slot, value as c_int) }
}
pub fn set_slot_bytes(&mut self, slot: i32, bytes: &[u8]) {
let ptr = bytes.as_ptr() as *const c_char;
let len = bytes.len();
unsafe { ffi::wrenSetSlotBytes(self.raw, slot, ptr, len) }
}
pub fn set_slot_double(&mut self, slot: i32, value: f64) {
unsafe { ffi::wrenSetSlotDouble(self.raw, slot, value) }
}
pub fn set_slot_new_foreign(&mut self, slot: i32, class_slot: i32, size: usize) -> Pointer {
unsafe { ffi::wrenSetSlotNewForeign(self.raw, slot, class_slot, size) }
}
pub fn set_slot_new_list(&mut self, slot: i32) {
unsafe { ffi::wrenSetSlotNewList(self.raw, slot) }
}
pub fn set_slot_null(&mut self, slot: i32) {
unsafe { ffi::wrenSetSlotNull(self.raw, slot) }
}
pub fn set_slot_string(&mut self, slot: i32, s: &str) {
let cstr = CString::new(s).unwrap();
unsafe { ffi::wrenSetSlotString(self.raw, slot, cstr.as_ptr()) }
}
pub fn set_slot_handle(&mut self, slot: i32, handle: Handle) {
unsafe { ffi::wrenSetSlotHandle(self.raw, slot, handle.0) }
}
pub fn get_list_count(&mut self, slot: i32) -> i32 {
unsafe { ffi::wrenGetListCount(self.raw, slot) }
}
pub fn get_list_element(&mut self, list_slot: i32, index: i32, element_slot: i32) {
unsafe { ffi::wrenGetListElement(self.raw, list_slot, index, element_slot) }
}
pub fn insert_in_list(&mut self, list_slot: i32, index: i32, element_slot: i32) {
unsafe { ffi::wrenInsertInList(self.raw, list_slot, index, element_slot) }
}
pub fn get_variable(&mut self, module: &str, name: &str, slot: i32) {
let module_cstr = CString::new(module).unwrap();
let name_cstr = CString::new(name).unwrap();
unsafe { ffi::wrenGetVariable(self.raw, module_cstr.as_ptr(), name_cstr.as_ptr(), slot) }
}
pub fn abort_fiber(&mut self, slot: i32) {
unsafe { ffi::wrenAbortFiber(self.raw, slot) }
}
pub fn get_user_data(&mut self) -> Pointer {
unsafe { ffi::wrenGetUserData(self.raw) }
}
pub fn set_user_data(&mut self, data: Pointer) {
unsafe { ffi::wrenSetUserData(self.raw, data) }
}
}
impl Drop for VM {
fn drop(&mut self) {
if self.owned {
unsafe { ffi::wrenFreeVM(self.raw) }
}
}
}