From 7292f10a45f10817b716da4dc2a1136a5e6ba07d Mon Sep 17 00:00:00 2001 From: Shark Date: Fri, 23 Feb 2024 10:07:55 +0100 Subject: [PATCH 1/3] use once cell for V8 platform initialisation --- crates/gosub_webexecutor/src/js/v8.rs | 33 ++++++++++++--------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/crates/gosub_webexecutor/src/js/v8.rs b/crates/gosub_webexecutor/src/js/v8.rs index 27d9e6218..32a8ffce0 100644 --- a/crates/gosub_webexecutor/src/js/v8.rs +++ b/crates/gosub_webexecutor/src/js/v8.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Once; pub use array::*; pub use compile::*; @@ -22,8 +23,8 @@ mod object; mod value; // status of the V8 engine -static PLATFORM_INITIALIZED: AtomicBool = AtomicBool::new(false); -static PLATFORM_INITIALIZING: AtomicBool = AtomicBool::new(false); +static V8_INITIALIZING: AtomicBool = AtomicBool::new(false); +static V8_INITIALIZED: Once = Once::new(); trait FromContext<'a, T> { fn from_ctx(ctx: V8Context<'a>, value: T) -> Self; @@ -44,14 +45,10 @@ const MAX_V8_INIT_SECONDS: u64 = 10; impl V8Engine<'_> { pub fn initialize() { - if PLATFORM_INITIALIZED.load(Ordering::SeqCst) { - return; - } - let mut wait_time = MAX_V8_INIT_SECONDS * 1000; - if PLATFORM_INITIALIZING.load(Ordering::SeqCst) { - while !PLATFORM_INITIALIZED.load(Ordering::SeqCst) { + if V8_INITIALIZING.load(Ordering::SeqCst) { + while !V8_INITIALIZED.is_completed() { std::thread::sleep(std::time::Duration::from_millis(10)); wait_time -= 10; if wait_time <= 9 { @@ -64,15 +61,15 @@ impl V8Engine<'_> { return; } - PLATFORM_INITIALIZING.store(true, Ordering::SeqCst); - - //https://github.com/denoland/rusty_v8/issues/1381 - let platform = v8::new_unprotected_default_platform(0, false).make_shared(); - v8::V8::initialize_platform(platform); - v8::V8::initialize(); - PLATFORM_INITIALIZED.store(true, Ordering::SeqCst); - PLATFORM_INITIALIZING.store(false, Ordering::SeqCst); + V8_INITIALIZED.call_once(|| { + V8_INITIALIZING.store(true, Ordering::SeqCst); + //https://github.com/denoland/rusty_v8/issues/1381 + let platform = v8::new_unprotected_default_platform(0, false).make_shared(); + v8::V8::initialize_platform(platform); + v8::V8::initialize(); + V8_INITIALIZING.store(false, Ordering::SeqCst); + }); } pub fn new() -> Self { @@ -120,7 +117,7 @@ mod tests { use anyhow; use colored::Colorize; - use crate::js::v8::PLATFORM_INITIALIZED; + use crate::js::v8::V8_INITIALIZED; use crate::js::{JSContext, JSError, JSRuntime, JSValue}; use crate::Error; use crate::Error::JS; @@ -129,7 +126,7 @@ mod tests { fn v8_engine_initialization() { let mut engine = crate::js::v8::V8Engine::new(); - assert!(PLATFORM_INITIALIZED.load(Ordering::SeqCst)); + assert!(V8_INITIALIZED.is_completed()); } #[test] From 8bc2b3e4156a2248475d6b30f3887e9725bcfac8 Mon Sep 17 00:00:00 2001 From: Shark Date: Mon, 19 Feb 2024 22:56:20 +0100 Subject: [PATCH 2/3] add more unit tests for V8 --- crates/gosub_webexecutor/src/js.rs | 9 +- crates/gosub_webexecutor/src/js/function.rs | 10 +- crates/gosub_webexecutor/src/js/v8.rs | 1 - crates/gosub_webexecutor/src/js/v8/array.rs | 138 +++++++- .../gosub_webexecutor/src/js/v8/function.rs | 166 ++++++++-- crates/gosub_webexecutor/src/js/v8/object.rs | 145 ++++++++- crates/gosub_webexecutor/src/js/v8/value.rs | 301 +++++++++++++++++- 7 files changed, 731 insertions(+), 39 deletions(-) diff --git a/crates/gosub_webexecutor/src/js.rs b/crates/gosub_webexecutor/src/js.rs index d80622897..49ccd31f5 100644 --- a/crates/gosub_webexecutor/src/js.rs +++ b/crates/gosub_webexecutor/src/js.rs @@ -52,14 +52,14 @@ lazy_static! { pub trait JSArray { type RT: JSRuntime; - fn get::ArrayIndex>>( + fn get( &self, - index: T, + index: ::ArrayIndex, ) -> Result<::Value>; - fn set::ArrayIndex>>( + fn set( &self, - index: T, + index: ::ArrayIndex, value: &::Value, ) -> Result<()>; @@ -74,6 +74,7 @@ pub trait JSArray { //TODO: implement other things when needed. Maybe also `Iterator`? } +#[derive(Debug, Clone, PartialEq)] pub enum JSType { Undefined, Null, diff --git a/crates/gosub_webexecutor/src/js/function.rs b/crates/gosub_webexecutor/src/js/function.rs index 5a24b9e8c..fb34daa31 100644 --- a/crates/gosub_webexecutor/src/js/function.rs +++ b/crates/gosub_webexecutor/src/js/function.rs @@ -15,7 +15,10 @@ pub trait JSFunction { where Self: Sized; - fn call(&mut self, callback: &mut ::FunctionCallBack); + fn call( + &mut self, + args: &[::Value], + ) -> Result<::Value>; } pub trait JSFunctionCallBack { @@ -64,7 +67,10 @@ pub trait JSFunctionVariadic { where Self: Sized; - fn call(&mut self, callback: &mut ::FunctionCallBackVariadic); + fn call( + &mut self, + args: &[::Value], + ) -> Result<::Value>; } pub trait JSFunctionCallBackVariadic { diff --git a/crates/gosub_webexecutor/src/js/v8.rs b/crates/gosub_webexecutor/src/js/v8.rs index 32a8ffce0..bfb7ee19a 100644 --- a/crates/gosub_webexecutor/src/js/v8.rs +++ b/crates/gosub_webexecutor/src/js/v8.rs @@ -61,7 +61,6 @@ impl V8Engine<'_> { return; } - V8_INITIALIZED.call_once(|| { V8_INITIALIZING.store(true, Ordering::SeqCst); //https://github.com/denoland/rusty_v8/issues/1381 diff --git a/crates/gosub_webexecutor/src/js/v8/array.rs b/crates/gosub_webexecutor/src/js/v8/array.rs index 249c54df7..b8e3e1d84 100644 --- a/crates/gosub_webexecutor/src/js/v8/array.rs +++ b/crates/gosub_webexecutor/src/js/v8/array.rs @@ -10,13 +10,24 @@ pub struct V8Array<'a> { ctx: V8Context<'a>, } +impl<'a> V8Array<'a> { + pub fn new(ctx: &V8Context<'a>, len: u32) -> Result { + let value = Array::new(ctx.borrow_mut().scope(), len as i32); + + Ok(Self { + value, + ctx: ctx.clone(), + }) + } +} + impl<'a> JSArray for V8Array<'a> { type RT = V8Engine<'a>; - fn get>(&self, index: T) -> Result<::Value> { + fn get(&self, index: u32) -> Result<::Value> { let Some(value) = self .value - .get_index(self.ctx.borrow_mut().scope(), index.into()) + .get_index(self.ctx.borrow_mut().scope(), index) else { return Err(Error::JS(JSError::Generic( "failed to get a value from an array".to_owned(), @@ -27,10 +38,10 @@ impl<'a> JSArray for V8Array<'a> { Ok(V8Value::from_value(self.ctx.clone(), value)) } - fn set>(&self, index: T, value: &V8Value) -> Result<()> { + fn set(&self, index: u32, value: &V8Value) -> Result<()> { match self .value - .set_index(self.ctx.borrow_mut().scope(), index.into(), value.value) + .set_index(self.ctx.borrow_mut().scope(), index, value.value) { Some(_) => Ok(()), None => Err(Error::JS(JSError::Conversion( @@ -97,3 +108,122 @@ impl<'a> JSArray for V8Array<'a> { Ok(self.value.length()) } } + +#[cfg(test)] +mod tests { + use crate::web_executor::js::v8::{V8Array, V8Engine}; + use crate::web_executor::js::{JSArray, JSRuntime, JSValue, ValueConversion}; + + #[test] + fn set() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + array + .set(0, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(1, &"Hello World!".to_js_value(context).unwrap()) + .unwrap(); + + assert_eq!(array.length().unwrap(), 2); + } + + #[test] + fn get() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + + array + .set(0, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(1, &"Hello World!".to_js_value(context).unwrap()) + .unwrap(); + + assert_eq!(array.get(0).unwrap().as_number().unwrap(), 1234.0); + assert_eq!( + array.get(1).unwrap().as_string().unwrap(), + "Hello World!" + ); + } + + #[test] + fn push() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + + array + .push(1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .push("Hello World!".to_js_value(context).unwrap()) + .unwrap(); + + assert_eq!(array.length().unwrap(), 4); + } + + #[test] + fn out_of_bounds() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + + array + .set(0, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(1, &"Hello World!".to_js_value(context).unwrap()) + .unwrap(); + + assert!(array.get(2).unwrap().is_undefined()); + } + + #[test] + fn pop() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + + array + .set(0, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(1, &"Hello World!".to_js_value(context).unwrap()) + .unwrap(); + + assert_eq!(array.pop().unwrap().as_string().unwrap(), "Hello World!"); + assert_eq!(array.get(0u32).unwrap().as_number().unwrap(), 1234.0); + assert!(array.get(1u32).unwrap().is_undefined()); + } + + #[test] + fn dynamic_resize() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let array = V8Array::new(&context, 2).unwrap(); + + array + .set(0, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(1, &"Hello World!".to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(2, &1234.0.to_js_value(context.clone()).unwrap()) + .unwrap(); + array + .set(3, &"Hello World!".to_js_value(context.clone()).unwrap()) + .unwrap(); + + assert_eq!(array.length().unwrap(), 4); + } +} diff --git a/crates/gosub_webexecutor/src/js/v8/function.rs b/crates/gosub_webexecutor/src/js/v8/function.rs index 8b3a1c36e..f293610d0 100644 --- a/crates/gosub_webexecutor/src/js/v8/function.rs +++ b/crates/gosub_webexecutor/src/js/v8/function.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use v8::{ CallbackScope, External, Function, FunctionBuilder, FunctionCallbackArguments, - FunctionCallbackInfo, Local, ReturnValue, + FunctionCallbackInfo, Local, ReturnValue, TryCatch, }; use crate::js::function::{JSFunctionCallBack, JSFunctionCallBackVariadic}; @@ -26,6 +26,18 @@ pub struct V8FunctionCallBack<'a> { ret: Result>, } +impl<'a> V8FunctionCallBack<'a> { + pub fn new(ctx: V8Context<'a>, args: V8Args<'a>) -> Result> { + Ok(Self { + ctx, + args, + ret: Err(Error::JS(JSError::Execution( + "function was not called".to_owned(), + ))), + }) + } +} + pub struct V8Args<'a> { next: usize, args: Vec>, @@ -37,6 +49,15 @@ impl V8Args<'_> { } } +impl<'a> V8Args<'a> { + fn new(args: Vec>, ctx: V8Context<'a>) -> Self { + Self { + next: 0, + args: args.iter().map(|x| x.value).collect(), + } + } +} + impl<'a> Iterator for V8Args<'a> { type Item = Local<'a, v8::Value>; @@ -164,13 +185,13 @@ impl<'a> V8Function<'a> { extern "C" fn callback(info: *const FunctionCallbackInfo) { let info = unsafe { &*info }; - let scope = &mut unsafe { CallbackScope::new(info) }; let args = FunctionCallbackArguments::from_function_callback_info(info); + let mut scope = unsafe { CallbackScope::new(info) }; let rv = ReturnValue::from_function_callback_info(info); let external = match >::try_from(args.data()) { Ok(external) => external, Err(e) => { - let Some(e) = v8::String::new(scope, &e.to_string()) else { + let Some(e) = v8::String::new(&mut scope, &e.to_string()) else { eprintln!("failed to create exception string\nexception was: {e}"); return; }; @@ -181,10 +202,7 @@ extern "C" fn callback(info: *const FunctionCallbackInfo) { let data = unsafe { &mut *(external.value() as *mut CallbackWrapper) }; - let ctx = match ctx_from_function_callback_info( - unsafe { CallbackScope::new(info) }, - data.ctx.borrow().isolate, - ) { + let ctx = match ctx_from_function_callback_info(scope, data.ctx.borrow().isolate) { Ok(scope) => scope, Err((mut st, e)) => { let scope = st.get(); @@ -243,19 +261,31 @@ impl<'a> JSFunction for V8Function<'a> { } } - fn call(&mut self, cb: &mut V8FunctionCallBack) { + fn call( + &mut self, + args: &[::Value], + ) -> Result<::Value> { + let scope = &mut TryCatch::new(self.ctx.borrow_mut().scope()); + + let recv = Local::from(v8::undefined(scope)); let ret = self.function.call( - cb.ctx.borrow_mut().scope(), - Local::from(v8::undefined(cb.ctx.borrow_mut().scope())), - cb.args.v8(), + scope, + recv, + args.iter() + .map(|x| x.value) + .collect::>>() + .as_slice(), ); if let Some(value) = ret { - cb.ret = Ok(value); + Ok(V8Value { + context: Rc::clone(&self.ctx), + value, + }) } else { - cb.ret = - Err(Error::JS(JSError::Execution("failed to call a function".to_owned())).into()); - }; + Err(Error::JS(JSError::Execution( + "failed to call a function".to_owned())).into()) + } } } @@ -515,18 +545,110 @@ impl<'a> JSFunctionVariadic for V8FunctionVariadic<'a> { } } - fn call(&mut self, cb: &mut V8FunctionCallBackVariadic) { + fn call( + &mut self, + args: &[::Value], + ) -> Result<::Value> { + let scope = &mut v8::TryCatch::new(self.ctx.borrow_mut().scope()); + let recv = Local::from(v8::undefined(scope)); let ret = self.function.call( - cb.ctx.borrow_mut().scope(), - Local::from(v8::undefined(cb.ctx.borrow_mut().scope())), - cb.args.v8(), + scope, + recv, + args.iter() + .map(|x| x.value) + .collect::>>() + .as_slice(), ); if let Some(value) = ret { - cb.ret = Ok(value); + Ok(V8Value { + context: Rc::clone(&self.ctx), + value, + }) } else { - cb.ret = - Err(Error::JS(JSError::Execution("failed to call a function".to_owned())).into()); + Err(Error::JS(JSError::Execution( + "failed to call a function".to_owned())).into()) + } + } +} + +#[cfg(test)] +mod tests { + use crate::web_executor::js::v8::{V8Engine, V8Function, V8FunctionVariadic, V8Value}; + use crate::web_executor::js::{ + Args, JSContext, JSFunction, JSFunctionCallBack, JSFunctionVariadic, JSRuntime, JSValue, + ValueConversion, + }; + + use super::*; + + #[test] + fn function_test() { + let mut ctx = V8Engine::new().new_context().unwrap(); + + let mut function = { + let ctx = ctx.clone(); + V8Function::new(ctx.clone(), move |cb| { + let ctx = cb.context(); + assert_eq!(cb.len(), 3); + + let sum = cb + .args() + .as_vec(ctx.clone()) + .iter() + .fold(0, |acc, x| acc + x.as_number().unwrap() as i32); + + cb.ret(sum.to_js_value(ctx.clone()).unwrap()); + }) + .unwrap() }; + + let ret = function.call(&[ + 1.to_js_value(ctx.clone()).unwrap(), + 2.to_js_value(ctx.clone()).unwrap(), + 3.to_js_value(ctx.clone()).unwrap(), + ]); + + assert_eq!(ret.unwrap().as_number().unwrap(), 6.0); + } + + #[test] + fn function_variadic_test() { + let mut ctx = V8Engine::new().new_context().unwrap(); + + let mut function = { + let ctx = ctx.clone(); + V8FunctionVariadic::new(ctx.clone(), move |cb| { + let ctx = cb.context(); + let sum = cb.args().as_vec(ctx.clone()).iter().fold(0, |acc, x| { + acc + match x.as_number() { + Ok(x) => x as i32, + Err(e) => { + cb.error(e); + return 0; + } + } + }); + + let val = match sum.to_js_value(ctx.clone()) { + Ok(val) => val, + Err(e) => { + cb.error(e); + return; + } + }; + cb.ret(val); + }) + .unwrap() + }; + + let ret = function.call(&[ + 1.to_js_value(ctx.clone()).unwrap(), + 2.to_js_value(ctx.clone()).unwrap(), + 3.to_js_value(ctx.clone()).unwrap(), + 4.to_js_value(ctx.clone()).unwrap(), + ]); + + assert_eq!(ret.unwrap().as_number().unwrap(), 10.0); } } diff --git a/crates/gosub_webexecutor/src/js/v8/object.rs b/crates/gosub_webexecutor/src/js/v8/object.rs index d5075665f..7a3f834de 100644 --- a/crates/gosub_webexecutor/src/js/v8/object.rs +++ b/crates/gosub_webexecutor/src/js/v8/object.rs @@ -26,6 +26,14 @@ pub struct GetterCallback<'a, 'r> { ret: &'r mut V8Value<'a>, } +impl V8Object<'_> { + pub fn new(ctx: V8Context) -> Result { + let scope = ctx.borrow_mut().scope(); + let value = Object::new(scope); + Ok(V8Object { ctx, value }) + } +} + impl<'a> JSGetterCallback for GetterCallback<'a, '_> { type RT = V8Engine<'a>; @@ -107,9 +115,11 @@ impl<'a> JSObject for V8Object<'a> { let Some(name) = v8::String::new(self.ctx.borrow_mut().scope(), name) else { return Err(Error::JS(JSError::Generic("failed to create a string".to_owned())).into()); }; + + let scope = self.ctx.borrow_mut().scope(); self.value - .get(self.ctx.borrow_mut().scope(), name.into()) + .get(scope, name.into()) .ok_or_else(|| { Error::JS(JSError::Generic( "failed to get a property from an object".to_owned(), @@ -243,10 +253,10 @@ impl<'a> JSObject for V8Object<'a> { }; let gs = unsafe { &*(external.value() as *const GetterSetter) }; + + let isolate = gs.ctx.borrow().isolate; - let ctx = scope.get_current_context(); - - let ctx = match ctx_from(scope, gs.ctx.borrow().isolate) { + let ctx = match ctx_from(scope, isolate) { Ok(ctx) => ctx, Err((mut st, e)) => { let scope = st.get(); @@ -338,3 +348,130 @@ impl<'a> FromContext<'a, Local<'a, Object>> for V8Object<'a> { Self { ctx, value: object } } } + +#[cfg(test)] +mod tests { + use alloc::rc::Rc; + use std::cell::RefCell; + + use serde_json::to_string; + + use crate::web_executor::js::v8::V8FunctionCallBackVariadic; + use crate::web_executor::js::{ + JSFunction, JSFunctionCallBack, JSFunctionCallBackVariadic, JSFunctionVariadic, + ValueConversion, VariadicArgsInternal, + }; + + use super::*; + + #[test] + fn test_object() { + let mut engine = V8Engine::new(); + let mut ctx = engine.new_context().unwrap(); + + let obj = V8Object::new(ctx.clone()).unwrap(); + + let value = V8Value::new_string(ctx.clone(), "value").unwrap(); + obj.set_property("key", &value).unwrap(); + + let value = obj.get_property("key").unwrap(); + assert_eq!(value.as_string().unwrap(), "value"); + } + + #[test] + fn test_object_accessor() { + let mut engine = V8Engine::new(); + let mut ctx = engine.new_context().unwrap(); + + let mut string = Rc::new(RefCell::new("value".to_string())); + + let getter = { + let string = Rc::clone(&string); + Box::new(move |cb: &mut GetterCallback| { + let value = string.borrow().to_js_value(cb.context().clone()).unwrap(); + cb.ret(value); + }) + }; + + let setter = { + let string = Rc::clone(&string); + Box::new(move |cb: &mut SetterCallback| { + let value = cb.value().as_string().unwrap(); + *string.borrow_mut() = value; + }) + }; + + let obj = V8Object::new(ctx.clone()).unwrap(); + obj.set_property_accessor("key", getter, setter).unwrap(); + + let value = obj.get_property("key").unwrap(); + assert_eq!(value.as_string().unwrap(), "value"); + //TODO modify value and test + } + + #[test] + fn test_object_method() { + let mut engine = V8Engine::new(); + let mut ctx = engine.new_context().unwrap(); + + let obj = V8Object::new(ctx.clone()).unwrap(); + + let called = Rc::new(RefCell::new(false)); + let mut func = V8Function::new(ctx.clone(), |cb: &mut V8FunctionCallBack| { + let value = V8Value::new_string(cb.context().clone(), "value").unwrap(); + cb.ret(value); + }) + .unwrap(); + + func.call(&[]).unwrap(); + + obj.set_method("key", &func).unwrap(); + + let value = obj.call_method("key", &[]).unwrap(); + assert_eq!(value.as_string().unwrap(), "value"); + } + + #[test] + fn test_object_method_variadic() { + let mut engine = V8Engine::new(); + let mut ctx = engine.new_context().unwrap(); + + let obj = V8Object::new(ctx.clone()).unwrap(); + + let called = Rc::new(RefCell::new(false)); + let func = V8FunctionVariadic::new(ctx.clone(), |cb: &mut V8FunctionCallBackVariadic| { + let ctx = cb.context().clone(); + + let args_str = cb + .args() + .as_vec(ctx.clone()) + .iter() + .map(|v| v.as_string().unwrap()) + .collect::>(); + + let value = V8Value::new_string(ctx, &to_string(&args_str).unwrap()).unwrap(); + + cb.ret(value); + }) + .unwrap(); + + obj.set_method_variadic("key", &func).unwrap(); + + let value = obj + .call_method( + "key", + &[ + &V8Value::new_string(ctx.clone(), "value1").unwrap(), + &V8Value::new_string(ctx.clone(), "value2").unwrap(), + &V8Value::new_undefined(ctx.clone()).unwrap(), + &V8Value::new_null(ctx.clone()).unwrap(), + &V8Value::new_number(ctx.clone(), 42).unwrap(), + ], + ) + .unwrap(); + assert_eq!( + value.as_string().unwrap(), + "[\"value1\",\"value2\",\"undefined\",\"null\",\"42\"]" + ); + } +} diff --git a/crates/gosub_webexecutor/src/js/v8/value.rs b/crates/gosub_webexecutor/src/js/v8/value.rs index 8b08bfe43..cb3e19cf2 100644 --- a/crates/gosub_webexecutor/src/js/v8/value.rs +++ b/crates/gosub_webexecutor/src/js/v8/value.rs @@ -84,8 +84,6 @@ impl<'a> JSValue for V8Value<'a> { JSType::Number } else if self.is_bool() { JSType::Boolean - } else if self.is_object() { - JSType::Object } else if self.is_array() { JSType::Array } else if self.is_null() { @@ -94,6 +92,8 @@ impl<'a> JSValue for V8Value<'a> { JSType::Undefined } else if self.is_function() { JSType::Function + } else if self.is_object() { + JSType::Object } else { let ctx = self.context.borrow_mut().scope(); @@ -151,3 +151,300 @@ impl<'a> JSValue for V8Value<'a> { }) } } + +#[cfg(test)] +mod tests { + use crate::web_executor::js::JSContext; + + use super::*; + + #[test] + fn test_v8_value_string() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + "Hello World!" + "#, + ) + .unwrap(); + + assert!(value.is_string()); + assert_eq!(value.as_string().unwrap(), "Hello World!"); + } + + #[test] + fn test_v8_value_number() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + 1234 + "#, + ) + .unwrap(); + + assert!(value.is_number()); + assert_eq!(value.as_number().unwrap(), 1234.0); + } + + #[test] + fn test_v8_value_bool() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + true + "#, + ) + .unwrap(); + + assert!(value.is_bool()); + assert!(value.as_bool().unwrap()); + } + + #[test] + fn test_v8_value_null() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + null + "#, + ) + .unwrap(); + + assert!(value.is_null()); + } + + #[test] + fn test_v8_value_undefined() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + undefined + "#, + ) + .unwrap(); + + assert!(value.is_undefined()); + } + + #[test] + fn test_v8_value_object() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + obj = { "hello": "world" } + obj + "#, + ) + .unwrap(); + + assert!(value.is_object()); + } + + #[test] + fn test_v8_value_array() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + [1, 2, 3] + "#, + ) + .unwrap(); + + assert!(value.is_array()); + // assert_eq!(value.as_array().unwrap(), vec![1.0, 2.0, 3.0]); //TODO + assert_eq!(value.as_string().unwrap(), "1,2,3"); + } + + #[test] + fn test_v8_value_function() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = context + .run( + r#" + function hello() { + return "world"; + } + hello + "#, + ) + .unwrap(); + + assert!(value.is_function()); + } + + #[test] + fn test_v8_value_type_of() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + // Test String + { + let value = context + .run( + r#" + "Hello World!" + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::String); + } + + // Test Number + { + let value = context + .run( + r#" + 1234 + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Number); + } + + // Test Boolean + { + let value = context + .run( + r#" + true + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Boolean); + } + + // Test Object + { + let value = context + .run( + r#" + obj = {"key": "value"} + obj + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Object); + } + + // Test Array + { + let value = context + .run( + r#" + [1, 2, 3] + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Array); + } + + // Test Null + { + let value = context + .run( + r#" + null + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Null); + } + + // Test Undefined + { + let value = context + .run( + r#" + undefined + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Undefined); + } + + // Test Function + { + let value = context + .run( + r#" + function test() {} + + test + "#, + ) + .unwrap(); + assert_eq!(value.type_of(), JSType::Function); + } + } + + #[test] + fn test_v8_value_new_string() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = V8Value::new_string(context, "Hello World!").unwrap(); + assert!(value.is_string()); + assert_eq!(value.as_string().unwrap(), "Hello World!"); + } + + #[test] + fn test_v8_value_new_number() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = V8Value::new_number(context, 1234).unwrap(); + assert!(value.is_number()); + assert_eq!(value.as_number().unwrap(), 1234.0); + } + + #[test] + fn test_v8_value_new_bool() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = V8Value::new_bool(context, true).unwrap(); + assert!(value.is_bool()); + assert!(value.as_bool().unwrap()); + } + + #[test] + fn test_v8_value_new_null() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = V8Value::new_null(context).unwrap(); + assert!(value.is_null()); + } + + #[test] + fn test_v8_value_new_undefined() { + let mut engine = V8Engine::new(); + let mut context = engine.new_context().unwrap(); + + let value = V8Value::new_undefined(context).unwrap(); + assert!(value.is_undefined()); + } +} From 24a929589a0ee88c3caa08cc8fc1bfbf70971bcc Mon Sep 17 00:00:00 2001 From: Shark Date: Sun, 25 Feb 2024 17:15:36 +0100 Subject: [PATCH 3/3] fix merge / crate seperation issues --- Cargo.lock | 1 + crates/gosub_webexecutor/Cargo.toml | 5 +- crates/gosub_webexecutor/src/js.rs | 7 +- crates/gosub_webexecutor/src/js/compile.rs | 3 +- crates/gosub_webexecutor/src/js/context.rs | 3 +- crates/gosub_webexecutor/src/js/function.rs | 4 +- crates/gosub_webexecutor/src/js/interop.rs | 6 +- crates/gosub_webexecutor/src/js/object.rs | 4 +- crates/gosub_webexecutor/src/js/runtime.rs | 5 +- crates/gosub_webexecutor/src/js/v8.rs | 16 +- crates/gosub_webexecutor/src/js/v8/array.rs | 17 +- crates/gosub_webexecutor/src/js/v8/compile.rs | 10 +- crates/gosub_webexecutor/src/js/v8/context.rs | 5 +- .../gosub_webexecutor/src/js/v8/function.rs | 19 +-- crates/gosub_webexecutor/src/js/v8/object.rs | 13 +- crates/gosub_webexecutor/src/js/v8/value.rs | 5 +- crates/gosub_webexecutor/src/js/value.rs | 3 +- .../src/js/value_conversion.rs | 3 +- crates/gosub_webexecutor/src/test.rs | 146 ++++++++---------- 19 files changed, 131 insertions(+), 144 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6c9b7f2c..5ebfc1cc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -798,6 +798,7 @@ dependencies = [ "derive_more", "gosub_shared", "lazy_static", + "serde_json", "thiserror", "v8", ] diff --git a/crates/gosub_webexecutor/Cargo.toml b/crates/gosub_webexecutor/Cargo.toml index d7bf6e2e8..69d2f313d 100644 --- a/crates/gosub_webexecutor/Cargo.toml +++ b/crates/gosub_webexecutor/Cargo.toml @@ -12,4 +12,7 @@ derive_more = "0.99" lazy_static = "1.4" thiserror = "1.0.57" v8 = "0.84.0" -anyhow = "1.0.80" \ No newline at end of file +anyhow = "1.0.80" + +[dev-dependencies] +serde_json = "1.0.114" \ No newline at end of file diff --git a/crates/gosub_webexecutor/src/js.rs b/crates/gosub_webexecutor/src/js.rs index 49ccd31f5..6161b8999 100644 --- a/crates/gosub_webexecutor/src/js.rs +++ b/crates/gosub_webexecutor/src/js.rs @@ -1,18 +1,19 @@ -use lazy_static::lazy_static; use std::sync::Mutex; + +use lazy_static::lazy_static; use thiserror::Error; -use crate::js::v8::V8Engine; pub use compile::*; pub use context::*; pub use function::*; +use gosub_shared::types::Result; pub use interop::*; pub use object::*; pub use runtime::*; pub use value::*; pub use value_conversion::*; -use gosub_shared::types::Result; +use crate::js::v8::V8Engine; mod compile; mod context; diff --git a/crates/gosub_webexecutor/src/js/compile.rs b/crates/gosub_webexecutor/src/js/compile.rs index eb56460cf..2ea0b103a 100644 --- a/crates/gosub_webexecutor/src/js/compile.rs +++ b/crates/gosub_webexecutor/src/js/compile.rs @@ -1,6 +1,7 @@ -use crate::js::{JSContext, JSRuntime, JSValue}; use gosub_shared::types::Result; +use crate::js::{JSContext, JSRuntime, JSValue}; + //compiled code will be stored with this trait for later execution (e.g HTML parsing not done yet) pub trait JSCompiled { type RT: JSRuntime; diff --git a/crates/gosub_webexecutor/src/js/context.rs b/crates/gosub_webexecutor/src/js/context.rs index 84483cdec..0380c9891 100644 --- a/crates/gosub_webexecutor/src/js/context.rs +++ b/crates/gosub_webexecutor/src/js/context.rs @@ -1,6 +1,7 @@ -use crate::js::{JSArray, JSCompiled, JSFunction, JSObject, JSRuntime, JSValue}; use gosub_shared::types::Result; +use crate::js::{JSArray, JSCompiled, JSFunction, JSObject, JSRuntime, JSValue}; + //main trait for JS context (can be implemented for different JS engines like V8, SpiderMonkey, JSC, etc.) pub trait JSContext: Clone { type RT: JSRuntime; diff --git a/crates/gosub_webexecutor/src/js/function.rs b/crates/gosub_webexecutor/src/js/function.rs index fb34daa31..67cd5af64 100644 --- a/crates/gosub_webexecutor/src/js/function.rs +++ b/crates/gosub_webexecutor/src/js/function.rs @@ -1,7 +1,9 @@ -use crate::js::{JSContext, JSError, JSObject, JSRuntime, JSValue}; use core::fmt::Display; + use gosub_shared::types::Result; +use crate::js::{JSContext, JSObject, JSRuntime, JSValue}; + struct Function(pub T); //trait for JS functions (interop between JS and Rust) diff --git a/crates/gosub_webexecutor/src/js/interop.rs b/crates/gosub_webexecutor/src/js/interop.rs index d3c690c9c..90712ce5c 100644 --- a/crates/gosub_webexecutor/src/js/interop.rs +++ b/crates/gosub_webexecutor/src/js/interop.rs @@ -1,8 +1,10 @@ -use crate::js::JSRuntime; -use gosub_shared::types::Result; use std::cell::RefCell; use std::rc::Rc; +use gosub_shared::types::Result; + +use crate::js::JSRuntime; + pub trait JSInterop { fn implement(s: Rc>, ctx: RT::Context) -> Result<()>; } diff --git a/crates/gosub_webexecutor/src/js/object.rs b/crates/gosub_webexecutor/src/js/object.rs index 8ab5c631b..1d2c5ba85 100644 --- a/crates/gosub_webexecutor/src/js/object.rs +++ b/crates/gosub_webexecutor/src/js/object.rs @@ -1,7 +1,9 @@ -use crate::js::{JSContext, JSFunction, JSFunctionVariadic, JSRuntime, JSValue}; use core::fmt::Display; + use gosub_shared::types::Result; +use crate::js::{JSContext, JSFunction, JSFunctionVariadic, JSRuntime, JSValue}; + pub trait JSObject { type RT: JSRuntime; diff --git a/crates/gosub_webexecutor/src/js/runtime.rs b/crates/gosub_webexecutor/src/js/runtime.rs index 14be889cf..6100b8bb2 100644 --- a/crates/gosub_webexecutor/src/js/runtime.rs +++ b/crates/gosub_webexecutor/src/js/runtime.rs @@ -1,9 +1,10 @@ +use gosub_shared::types::Result; + use crate::js::{ Args, JSArray, JSCompiled, JSContext, JSFunction, JSFunctionCallBack, JSFunctionCallBackVariadic, JSFunctionVariadic, JSGetterCallback, JSObject, JSSetterCallback, - JSValue, ValueConversion, VariadicArgs, VariadicArgsInternal, + JSValue, VariadicArgs, VariadicArgsInternal, }; -use gosub_shared::types::Result; //trait around the main JS engine (e.g V8, SpiderMonkey, JSC, etc.) pub trait JSRuntime { diff --git a/crates/gosub_webexecutor/src/js/v8.rs b/crates/gosub_webexecutor/src/js/v8.rs index bfb7ee19a..5eea1acfb 100644 --- a/crates/gosub_webexecutor/src/js/v8.rs +++ b/crates/gosub_webexecutor/src/js/v8.rs @@ -9,11 +9,11 @@ pub use array::*; pub use compile::*; pub use context::*; pub use function::*; +use gosub_shared::types::Result; pub use object::*; pub use value::*; use crate::js::{JSArray, JSContext, JSFunction, JSObject, JSRuntime, JSValue, ValueConversion}; -use gosub_shared::types::Result; mod array; mod compile; @@ -111,15 +111,10 @@ impl<'a> JSRuntime for V8Engine<'a> { #[cfg(test)] mod tests { - use std::sync::atomic::Ordering; - use anyhow; - use colored::Colorize; use crate::js::v8::V8_INITIALIZED; - use crate::js::{JSContext, JSError, JSRuntime, JSValue}; - use crate::Error; - use crate::Error::JS; + use crate::js::{JSContext, JSRuntime, JSValue}; #[test] fn v8_engine_initialization() { @@ -147,6 +142,7 @@ mod tests { } #[test] + #[should_panic = "called `Result::unwrap()` on an `Err` value: js: compile error: SyntaxError: missing ) after argument list\n\nCaused by:\n compile error: SyntaxError: missing ) after argument list"] fn v8_run_invalid_syntax() { let mut engine = crate::js::v8::V8Engine::new(); @@ -160,11 +156,7 @@ mod tests { ); assert!(result.is_err()); - // This assertion fails because the error type is not correct - // assert!(matches!( - // result, - // Err(anyhow::Error::new(JSError::Compile(_))) - // )); + result.unwrap(); } #[test] diff --git a/crates/gosub_webexecutor/src/js/v8/array.rs b/crates/gosub_webexecutor/src/js/v8/array.rs index b8e3e1d84..0e013de82 100644 --- a/crates/gosub_webexecutor/src/js/v8/array.rs +++ b/crates/gosub_webexecutor/src/js/v8/array.rs @@ -1,9 +1,10 @@ use v8::{Array, Local}; +use gosub_shared::types::Result; + use crate::js::v8::{V8Context, V8Engine, V8Value}; use crate::js::{JSArray, JSError, JSRuntime}; use crate::Error; -use gosub_shared::types::Result; pub struct V8Array<'a> { value: Local<'a, Array>, @@ -25,10 +26,7 @@ impl<'a> JSArray for V8Array<'a> { type RT = V8Engine<'a>; fn get(&self, index: u32) -> Result<::Value> { - let Some(value) = self - .value - .get_index(self.ctx.borrow_mut().scope(), index) - else { + let Some(value) = self.value.get_index(self.ctx.borrow_mut().scope(), index) else { return Err(Error::JS(JSError::Generic( "failed to get a value from an array".to_owned(), )) @@ -111,8 +109,8 @@ impl<'a> JSArray for V8Array<'a> { #[cfg(test)] mod tests { - use crate::web_executor::js::v8::{V8Array, V8Engine}; - use crate::web_executor::js::{JSArray, JSRuntime, JSValue, ValueConversion}; + use crate::js::v8::{V8Array, V8Engine}; + use crate::js::{JSArray, JSRuntime, JSValue, ValueConversion}; #[test] fn set() { @@ -145,10 +143,7 @@ mod tests { .unwrap(); assert_eq!(array.get(0).unwrap().as_number().unwrap(), 1234.0); - assert_eq!( - array.get(1).unwrap().as_string().unwrap(), - "Hello World!" - ); + assert_eq!(array.get(1).unwrap().as_string().unwrap(), "Hello World!"); } #[test] diff --git a/crates/gosub_webexecutor/src/js/v8/compile.rs b/crates/gosub_webexecutor/src/js/v8/compile.rs index cc9c35270..3d406316d 100644 --- a/crates/gosub_webexecutor/src/js/v8/compile.rs +++ b/crates/gosub_webexecutor/src/js/v8/compile.rs @@ -1,8 +1,12 @@ -use crate::js::v8::{FromContext, V8Context, V8Ctx, V8Engine, V8Value}; -use crate::js::{JSCompiled, JSRuntime}; -use gosub_shared::types::Result; use std::rc::Rc; + use v8::{Local, Script}; + +use gosub_shared::types::Result; + +use crate::js::v8::{FromContext, V8Context, V8Ctx, V8Engine, V8Value}; +use crate::js::{JSCompiled, JSRuntime}; + pub struct V8Compiled<'a> { compiled: Local<'a, Script>, context: V8Context<'a>, diff --git a/crates/gosub_webexecutor/src/js/v8/context.rs b/crates/gosub_webexecutor/src/js/v8/context.rs index ee66043af..f4996468d 100644 --- a/crates/gosub_webexecutor/src/js/v8/context.rs +++ b/crates/gosub_webexecutor/src/js/v8/context.rs @@ -7,12 +7,13 @@ use v8::{ TryCatch, }; +use gosub_shared::types::Result; + use crate::js::compile::JSCompiled; use crate::js::v8::compile::V8Compiled; -use crate::js::v8::{FromContext, V8Context, V8Engine, V8Object, V8Value}; +use crate::js::v8::{FromContext, V8Context, V8Engine, V8Object}; use crate::js::{JSContext, JSError, JSRuntime}; use crate::Error; -use gosub_shared::types::Result; /// SAFETY: This is NOT thread safe, as the rest of the engine is not thread safe. /// This struct uses `NonNull` internally to store pointers to the V8Context "values" in one struct. diff --git a/crates/gosub_webexecutor/src/js/v8/function.rs b/crates/gosub_webexecutor/src/js/v8/function.rs index f293610d0..8ea65d47e 100644 --- a/crates/gosub_webexecutor/src/js/v8/function.rs +++ b/crates/gosub_webexecutor/src/js/v8/function.rs @@ -6,6 +6,8 @@ use v8::{ FunctionCallbackInfo, Local, ReturnValue, TryCatch, }; +use gosub_shared::types::Result; + use crate::js::function::{JSFunctionCallBack, JSFunctionCallBackVariadic}; use crate::js::v8::{ctx_from_function_callback_info, V8Context, V8Engine, V8Value}; use crate::js::{ @@ -13,7 +15,6 @@ use crate::js::{ VariadicArgsInternal, }; use crate::Error; -use gosub_shared::types::Result; pub struct V8Function<'a> { pub(super) ctx: V8Context<'a>, @@ -31,9 +32,7 @@ impl<'a> V8FunctionCallBack<'a> { Ok(Self { ctx, args, - ret: Err(Error::JS(JSError::Execution( - "function was not called".to_owned(), - ))), + ret: Err(Error::JS(JSError::Execution("function was not called".to_owned())).into()), }) } } @@ -283,8 +282,7 @@ impl<'a> JSFunction for V8Function<'a> { value, }) } else { - Err(Error::JS(JSError::Execution( - "failed to call a function".to_owned())).into()) + Err(Error::JS(JSError::Execution("failed to call a function".to_owned())).into()) } } } @@ -566,17 +564,16 @@ impl<'a> JSFunctionVariadic for V8FunctionVariadic<'a> { value, }) } else { - Err(Error::JS(JSError::Execution( - "failed to call a function".to_owned())).into()) + Err(Error::JS(JSError::Execution("failed to call a function".to_owned())).into()) } } } #[cfg(test)] mod tests { - use crate::web_executor::js::v8::{V8Engine, V8Function, V8FunctionVariadic, V8Value}; - use crate::web_executor::js::{ - Args, JSContext, JSFunction, JSFunctionCallBack, JSFunctionVariadic, JSRuntime, JSValue, + use crate::js::v8::{V8Engine, V8Function, V8FunctionVariadic}; + use crate::js::{ + Args, JSFunction, JSFunctionCallBack, JSFunctionVariadic, JSRuntime, JSValue, ValueConversion, }; diff --git a/crates/gosub_webexecutor/src/js/v8/object.rs b/crates/gosub_webexecutor/src/js/v8/object.rs index 7a3f834de..cd959ce29 100644 --- a/crates/gosub_webexecutor/src/js/v8/object.rs +++ b/crates/gosub_webexecutor/src/js/v8/object.rs @@ -6,6 +6,8 @@ use v8::{ ReturnValue, Value, }; +use gosub_shared::types::Result; + use crate::js::v8::{ ctx_from, FromContext, V8Context, V8Ctx, V8Engine, V8Function, V8FunctionCallBack, V8FunctionVariadic, V8Value, @@ -14,7 +16,6 @@ use crate::js::{ JSArray, JSError, JSGetterCallback, JSObject, JSRuntime, JSSetterCallback, JSValue, }; use crate::Error; -use gosub_shared::types::Result; pub struct V8Object<'a> { ctx: V8Context<'a>, @@ -115,7 +116,7 @@ impl<'a> JSObject for V8Object<'a> { let Some(name) = v8::String::new(self.ctx.borrow_mut().scope(), name) else { return Err(Error::JS(JSError::Generic("failed to create a string".to_owned())).into()); }; - + let scope = self.ctx.borrow_mut().scope(); self.value @@ -253,7 +254,7 @@ impl<'a> JSObject for V8Object<'a> { }; let gs = unsafe { &*(external.value() as *const GetterSetter) }; - + let isolate = gs.ctx.borrow().isolate; let ctx = match ctx_from(scope, isolate) { @@ -351,13 +352,13 @@ impl<'a> FromContext<'a, Local<'a, Object>> for V8Object<'a> { #[cfg(test)] mod tests { - use alloc::rc::Rc; use std::cell::RefCell; + use std::rc::Rc; use serde_json::to_string; - use crate::web_executor::js::v8::V8FunctionCallBackVariadic; - use crate::web_executor::js::{ + use crate::js::v8::V8FunctionCallBackVariadic; + use crate::js::{ JSFunction, JSFunctionCallBack, JSFunctionCallBackVariadic, JSFunctionVariadic, ValueConversion, VariadicArgsInternal, }; diff --git a/crates/gosub_webexecutor/src/js/v8/value.rs b/crates/gosub_webexecutor/src/js/v8/value.rs index cb3e19cf2..61a917bb0 100644 --- a/crates/gosub_webexecutor/src/js/v8/value.rs +++ b/crates/gosub_webexecutor/src/js/v8/value.rs @@ -2,10 +2,11 @@ use std::rc::Rc; use v8::{Local, Value}; +use gosub_shared::types::Result; + use crate::js::v8::{FromContext, V8Context, V8Engine, V8Object}; use crate::js::{JSError, JSRuntime, JSType, JSValue, ValueConversion}; use crate::Error; -use gosub_shared::types::Result; pub struct V8Value<'a> { pub(crate) context: V8Context<'a>, @@ -154,7 +155,7 @@ impl<'a> JSValue for V8Value<'a> { #[cfg(test)] mod tests { - use crate::web_executor::js::JSContext; + use crate::js::JSContext; use super::*; diff --git a/crates/gosub_webexecutor/src/js/value.rs b/crates/gosub_webexecutor/src/js/value.rs index af7fe3dbc..d9e98d90d 100644 --- a/crates/gosub_webexecutor/src/js/value.rs +++ b/crates/gosub_webexecutor/src/js/value.rs @@ -1,6 +1,7 @@ -use crate::js::{JSArray, JSContext, JSObject, JSRuntime, JSType}; use gosub_shared::types::Result; +use crate::js::{JSArray, JSContext, JSObject, JSRuntime, JSType}; + pub trait JSValue where Self: Sized, diff --git a/crates/gosub_webexecutor/src/js/value_conversion.rs b/crates/gosub_webexecutor/src/js/value_conversion.rs index 34210a7db..33230b3e0 100644 --- a/crates/gosub_webexecutor/src/js/value_conversion.rs +++ b/crates/gosub_webexecutor/src/js/value_conversion.rs @@ -1,6 +1,7 @@ -use crate::js::{JSContext, JSRuntime, JSValue}; use gosub_shared::types::Result; +use crate::js::{JSContext, JSRuntime, JSValue}; + //trait to easily convert Rust types to JS values (just call .to_js_value() on the type) pub trait ValueConversion { type Value: JSValue; diff --git a/crates/gosub_webexecutor/src/test.rs b/crates/gosub_webexecutor/src/test.rs index b42838725..4abae0f74 100644 --- a/crates/gosub_webexecutor/src/test.rs +++ b/crates/gosub_webexecutor/src/test.rs @@ -1,91 +1,79 @@ -//use webinterop::{web_fns, web_interop}; -use crate::js::v8::{V8Engine, V8Value}; use crate::js::{ Args, JSContext, JSFunction, JSFunctionCallBack, JSFunctionCallBackVariadic, JSFunctionVariadic, JSGetterCallback, JSInterop, JSObject, JSRuntime, JSSetterCallback, JSValue, ValueConversion, VariadicArgs, VariadicArgsInternal, }; +//use webinterop::{web_fns, web_interop}; +use crate::js::v8::V8Engine; use gosub_shared::types::Result; use std::cell::RefCell; -use std::collections::HashMap; -use std::ops::Add; use std::rc::Rc; //#[web_interop] -struct TestStruct { - //#[property] - field: i32, - - //#[property] - field2: HashMap, //should crash it -} - -//#[web_fns] -impl TestStruct { - fn add(&self, other: i32) -> i32 { - self.field + other - } - - fn add2(&mut self, other: i32) { - self.field += other - } - - fn add3(a: i32, b: i32) -> i32 { - a + b - } - fn variadic(_nums: T) {} - - fn v8_variadic(_nums: V8Value) {} -} - -// #[test] -// fn test() { -// let test = TestStruct { -// field: 3, -// field2: HashMap::new(), -// }; +// struct TestStruct { +// //#[property] +// field: i32, // -// let k = test.add(5); +// //#[property] +// field2: HashMap, //should crash it +// } +// +// //#[web_fns] +// impl TestStruct { +// fn add(&self, other: i32) -> i32 { +// self.field + other +// } +// +// fn add2(&mut self, other: i32) { +// self.field += other +// } +// +// fn add3(a: i32, b: i32) -> i32 { +// a + b +// } +// fn variadic(_nums: T) {} +// +// fn v8_variadic(_nums: V8Value) {} // } -//test, how we need to implement slices and vectors with refs -fn array_test() { - let mut test_vec = vec![1, 2, 3]; - - vec(test_vec.clone()); //clone only needed for the test - - ref_vec(&test_vec); - - mut_vec(&mut test_vec); - - ref_slice(&test_vec); - - mut_slice(&mut test_vec); - - size_slice(<[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test - - ref_size_slice(&<[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test - - mut_size_slice(&mut <[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test -} - -fn vec(_vec: Vec) {} - -#[allow(clippy::ptr_arg)] -fn ref_vec(_vec: &Vec) {} - -#[allow(clippy::ptr_arg)] -fn mut_vec(_vec: &mut Vec) {} - -fn ref_slice(_slice: &[i32]) {} - -fn mut_slice(_slice: &mut [i32]) {} - -fn size_slice(_array: [i32; 3]) {} - -fn ref_size_slice(_slice: &[i32; 3]) {} - -fn mut_size_slice(_slice: &mut [i32; 3]) {} +//test, how we need to implement slices and vectors with refs (deref things) +// fn array_test() { +// let mut test_vec = vec![1, 2, 3]; +// +// vec(test_vec.clone()); //clone only needed for the test +// +// ref_vec(&test_vec); +// +// mut_vec(&mut test_vec); +// +// ref_slice(&test_vec); +// +// mut_slice(&mut test_vec); +// +// size_slice(<[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test +// +// ref_size_slice(&<[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test +// +// mut_size_slice(&mut <[i32; 3]>::try_from(test_vec.clone()).unwrap()); //clone only needed for the test +// } +// +// fn vec(_vec: Vec) {} +// +// #[allow(clippy::ptr_arg)] +// fn ref_vec(_vec: &Vec) {} +// +// #[allow(clippy::ptr_arg)] +// fn mut_vec(_vec: &mut Vec) {} +// +// fn ref_slice(_slice: &[i32]) {} +// +// fn mut_slice(_slice: &mut [i32]) {} +// +// fn size_slice(_array: [i32; 3]) {} +// +// fn ref_size_slice(_slice: &[i32; 3]) {} +// +// fn mut_size_slice(_slice: &mut [i32; 3]) {} #[derive(Debug)] struct Test2 { @@ -144,7 +132,6 @@ impl JSInterop for Test2 { let setter = { let s = Rc::clone(&s); Box::new(move |cb: &mut RT::SetterCB| { - let _ctx = cb.context(); let value = cb.value(); let value = match value.as_number() { Ok(value) => value, @@ -185,7 +172,6 @@ impl JSInterop for Test2 { let setter = { let s = Rc::clone(&s); Box::new(move |cb: &mut RT::SetterCB| { - let _ctx = cb.context(); let value = cb.value(); let value = match value.as_string() { Ok(value) => value, @@ -240,8 +226,6 @@ impl JSInterop for Test2 { let ctx = cb.context(); - let _args = cb.args(); - let Some(arg0) = cb.args().get(0, ctx.clone()) else { cb.error("failed to get argument"); return; @@ -275,8 +259,6 @@ impl JSInterop for Test2 { let ctx = cb.context(); - let _args = cb.args(); - let Some(arg0) = cb.args().get(0, ctx.clone()) else { cb.error("failed to get argument"); return; @@ -305,8 +287,6 @@ impl JSInterop for Test2 { let ctx = cb.context(); - let _args = cb.args(); - let Some(arg0) = cb.args().get(0, ctx.clone()) else { cb.error("failed to get argument"); return;