Changeset 179:a082ccef6f6f
Added broken implementation of function calling
author | unexist <christoph@unexist.dev> |
---|---|
date | Fri, 03 Jul 2020 17:35:36 +0200 |
parents | 0123686bc418 |
children | 93b622073eb0 |
files | rubtle-lib/src/rubtle.rs |
diffstat | 1 files changed, 104 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/rubtle-lib/src/rubtle.rs Fri Jul 03 17:35:13 2020 +0200 +++ b/rubtle-lib/src/rubtle.rs Fri Jul 03 17:35:36 2020 +0200 @@ -14,14 +14,19 @@ use std::{process, ptr, slice}; use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_void}; +use std::panic::{AssertUnwindSafe, catch_unwind}; -use crate::Value; +use crate::{Value, Invocation, Result}; pub struct Rubtle { /// Duktape context pub(crate) ctx: *mut ffi::duk_context, } +const FUNC: [i8; 6] = hidden_i8str!('f', 'u', 'n', 'c'); + +pub(crate) type Callback = Box<dyn Fn(Invocation) -> Result<Value>>; + impl Rubtle { /// @@ -88,7 +93,7 @@ } /// - /// Push value to stack and assign a global reachable name + /// Set value to context and assign a global reachable name /// /// # Arguments /// @@ -102,10 +107,10 @@ /// let rubtle = Rubtle::new(); /// let rval = Value::from(4); /// - /// rubtle.push_global_value("rubtle", &rval); + /// rubtle.set_global_value("rubtle", &rval); /// - pub fn push_global_value(&self, name: &str, rval: &Value) { + pub fn set_global_value(&self, name: &str, rval: &Value) { unsafe { let cstr = CString::new(to_cesu8(name)); @@ -122,7 +127,27 @@ } } - pub fn pop_global_value(&self, name: &str) -> Option<Value> { + /// + /// Get value from context for given global reachable name + /// + /// # Arguments + /// + /// `name`- Name of the value + /// + /// # Returns + /// + /// Any value on top of the stack as `Option<Value>` + /// + /// # Example + /// + /// use rubtle_lib::{Rubtle, Value}; + /// + /// let rubtle = Rubtle::new(); + /// + /// rubtle.get_global_value("rubtle"); + /// + + pub fn get_global_value(&self, name: &str) -> Option<Value> { unsafe { let cstr = CString::new(to_cesu8(name)); @@ -138,6 +163,80 @@ } } + pub fn set_global_function<F>(&self, name: &str, func: F) + where + F: Fn(Invocation) -> Result<Value> + { + unsafe extern "C" fn wrapper(ctx: *mut ffi::duk_context) -> + ffi::duk_ret_t + { + let rubtle = Rubtle { ctx }; + let nargs = ffi::duk_get_top(ctx) as usize; + let mut args = Vec::with_capacity(nargs); + + //ffi::duk_push_this(ctx); + //let this = ducc.pop_value(); + + for i in 0..nargs { + ffi::duk_dup(ctx, i as ffi::duk_idx_t); + args.push(rubtle.pop_value().unwrap()); + } + + let invocation = Invocation { + rubtle: &rubtle, + this: Value::from(1), + args: args, + }; + + ffi::duk_get_prop_string(ctx, -1, FUNC.as_ptr() as *const _); + let func_ptr = ffi::duk_get_pointer(ctx, -1) as *mut Callback; + + //let inner = || (*func)(&rubtle, (), args); + let inner = move || (* func_ptr)(invocation); + + let result = match catch_unwind(AssertUnwindSafe(inner)) { + Ok(result) => result, + Err(_) => { + ffi::duk_fatal_raw(ctx, cstr!("panic occurred during script execution")); + unreachable!(); + }, + }; + + match result { + Ok(value) => { + rubtle.push_value(&value); + 1 + }, + Err(_) => { + -1 + }, + } + } + + unsafe extern "C" fn finalizer(ctx: *mut ffi::duk_context) -> ffi::duk_ret_t { + ffi::duk_require_stack(ctx, 1); + + 0 + } + + unsafe { + let cstr = CString::new(to_cesu8(name)); + + match cstr { + Ok(cval) => { + ffi::duk_require_stack(self.ctx, 2); + ffi::duk_push_c_function(self.ctx, Some(wrapper), -1); //< (DUK_VARARGS) + ffi::duk_push_pointer(self.ctx, Box::into_raw(Box::new(func)) as *mut _); + ffi::duk_push_c_function(self.ctx, Some(finalizer), 1); + ffi::duk_set_finalizer(self.ctx, -2); + ffi::duk_put_global_lstring(self.ctx, + cval.as_ptr(), cval.as_bytes().len() as u64); + }, + Err(_) => unimplemented!() + } + } + } + /// /// Pop most recent value from duktape stack ///