From 544ec1a89953ebf0fcc3519137ab0156c4bcad89 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Fri, 14 Apr 2023 16:23:05 +0200 Subject: [PATCH 1/5] Restructure and rename. --- src/lib.rs | 115 +++++----- src/v8/{v8_context.rs => context.rs} | 30 +-- .../{v8_context_scope.rs => context_scope.rs} | 88 ++++---- src/v8/isolate.rs | 24 +-- src/v8/isolate_scope.rs | 114 +++++----- src/v8/mod.rs | 22 +- src/v8/{v8_array.rs => types/array.rs} | 44 ++-- .../array_buffer.rs} | 22 +- .../external_data.rs} | 14 +- src/v8/{v8_value.rs => types/mod.rs} | 204 ++++++++++++------ src/v8/{v8_module.rs => types/module.rs} | 66 +++--- .../native_function.rs} | 16 +- .../native_function_template.rs} | 68 +++--- src/v8/{v8_object.rs => types/object.rs} | 66 +++--- .../object_template.rs} | 55 +++-- src/v8/{v8_promise.rs => types/promise.rs} | 40 ++-- src/v8/{v8_resolver.rs => types/resolver.rs} | 28 +-- src/v8/{v8_script.rs => types/script.rs} | 38 ++-- src/v8/{v8_set.rs => types/set.rs} | 26 +-- src/v8/{v8_string.rs => types/string.rs} | 22 +- src/v8/{ => types}/try_catch.rs | 24 +-- src/v8/{v8_unlocker.rs => types/unlocker.rs} | 8 +- src/v8/{v8_utf8.rs => types/utf8.rs} | 18 +- v8-rs-derive/src/lib.rs | 2 +- 24 files changed, 602 insertions(+), 552 deletions(-) rename src/v8/{v8_context.rs => context.rs} (86%) rename src/v8/{v8_context_scope.rs => context_scope.rs} (73%) rename src/v8/{v8_array.rs => types/array.rs} (63%) rename src/v8/{v8_array_buffer.rs => types/array_buffer.rs} (60%) rename src/v8/{v8_external_data.rs => types/external_data.rs} (68%) rename src/v8/{v8_value.rs => types/mod.rs} (68%) rename src/v8/{v8_module.rs => types/module.rs} (68%) rename src/v8/{v8_native_function.rs => types/native_function.rs} (59%) rename src/v8/{v8_native_function_template.rs => types/native_function_template.rs} (67%) rename src/v8/{v8_object.rs => types/object.rs} (63%) rename src/v8/{v8_object_template.rs => types/object_template.rs} (71%) rename src/v8/{v8_promise.rs => types/promise.rs} (67%) rename src/v8/{v8_resolver.rs => types/resolver.rs} (62%) rename src/v8/{v8_script.rs => types/script.rs} (61%) rename src/v8/{v8_set.rs => types/set.rs} (52%) rename src/v8/{v8_string.rs => types/string.rs} (63%) rename src/v8/{ => types}/try_catch.rs (69%) rename src/v8/{v8_unlocker.rs => types/unlocker.rs} (60%) rename src/v8/{v8_utf8.rs => types/utf8.rs} (63%) diff --git a/src/lib.rs b/src/lib.rs index 930cd9f..8bff952 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,9 +57,8 @@ impl From for RawIndex { mod json_path_tests { use crate as v8_rs; use crate::v8::{ - isolate, isolate_scope, v8_array, v8_array_buffer, v8_context_scope, v8_init, - v8_native_function_template, v8_object, v8_set, v8_utf8, - v8_value::{self}, + context_scope, isolate, isolate_scope, types, types::array, types::array_buffer, + types::native_function_template, types::object, types::set, types::utf8, v8_init, }; use v8_derive::new_native_function; @@ -83,14 +82,14 @@ mod json_path_tests { #[test] fn test_simple_isolate_creation() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let _i_scope = isolate.enter(); } #[test] fn test_simple_string_creation() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let _s = isolate_scope.new_string("test"); } @@ -98,7 +97,7 @@ mod json_path_tests { #[test] fn test_simple_object_creation() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let _o = isolate_scope.new_object_template(); } @@ -106,7 +105,7 @@ mod json_path_tests { #[test] fn test_simple_native_function_creation() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let _o = isolate_scope.new_native_function_template(|_args, _isolate, _ctx_scope| { println!("test"); @@ -117,7 +116,7 @@ mod json_path_tests { #[test] fn test_native_function_args() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let native = isolate_scope.new_native_function_template(|args, _isolate_scope, _ctx_scope| { @@ -139,7 +138,7 @@ mod json_path_tests { #[test] fn test_native_function_call_js() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let foo1 = isolate_scope.new_native_function_template(|args, _isolate, ctx_scope| { @@ -173,7 +172,7 @@ mod json_path_tests { #[test] fn test_native_function_call_with_args() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let foo1 = isolate_scope.new_native_function_template(|args, isolate_scope, ctx_scope| { @@ -207,7 +206,7 @@ mod json_path_tests { #[test] fn test_native_function_raise_exception() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let native = isolate_scope.new_native_function_template(|_args, isolate, _ctx_scope| { @@ -231,7 +230,7 @@ mod json_path_tests { #[test] fn test_native_function_raise_exception_error() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope .new_string("function foo(){throw new Error('this is an error!');};foo();"); @@ -251,7 +250,7 @@ mod json_path_tests { #[test] fn test_simple_code_run() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope.new_string("1+1"); let ctx = isolate_scope.new_context(None); @@ -265,7 +264,7 @@ mod json_path_tests { #[test] fn test_simple_module_run() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let mut globals = isolate_scope.new_object_template(); @@ -296,14 +295,14 @@ mod json_path_tests { let res = res.as_promise(); assert_eq!( res.state(), - crate::v8::v8_promise::V8PromiseState::Fulfilled + crate::v8::types::promise::PromiseState::Fulfilled ); } #[test] fn test_async_function() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope.new_string("async function f(){return 1}; f"); let ctx = isolate_scope.new_context(None); @@ -316,7 +315,7 @@ mod json_path_tests { let promise = async_res.as_promise(); assert_eq!( promise.state(), - crate::v8::v8_promise::V8PromiseState::Fulfilled + crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); let res_utf8 = promise_res.to_utf8().unwrap(); @@ -326,7 +325,7 @@ mod json_path_tests { #[test] fn test_promise_resolver() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let mut globals = isolate_scope.new_object_template(); globals.add_native_function("foo", |_args, isolate_scope, ctx_scope| { @@ -346,7 +345,7 @@ mod json_path_tests { let promise = res.as_promise(); assert_eq!( promise.state(), - crate::v8::v8_promise::V8PromiseState::Fulfilled + crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); let res_utf8 = promise_res.to_utf8().unwrap(); @@ -356,7 +355,7 @@ mod json_path_tests { #[test] fn test_compilation_error() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope.new_string("foo("); let ctx = isolate_scope.new_context(None); @@ -373,7 +372,7 @@ mod json_path_tests { #[test] fn test_run_error() { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope.new_string("foo()"); let ctx = isolate_scope.new_context(None); @@ -390,17 +389,17 @@ mod json_path_tests { fn define_function_and_call< F: for<'d, 'e> Fn( - &v8_native_function_template::V8LocalNativeFunctionArgs<'d, 'e>, - &'d isolate_scope::V8IsolateScope<'e>, - &v8_context_scope::V8ContextScope<'d, 'e>, - ) -> Option>, + &types::native_function_template::LocalNativeFunctionArgs<'d, 'e>, + &'d isolate_scope::IsolateScope<'e>, + &context_scope::ContextScope<'d, 'e>, + ) -> Option>, >( code: &str, func_name: &str, f: F, ) -> Result<(), String> { initialize(); - let isolate = isolate::V8Isolate::new(); + let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let native = isolate_scope.new_native_function_template(f); let native_funciton_name = isolate_scope.new_string(func_name); @@ -493,7 +492,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -507,7 +506,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: f64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -522,7 +521,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); assert_eq!(arg3, "test"); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -537,7 +536,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); assert_eq!(arg3, true); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -548,9 +547,9 @@ mod json_path_tests { define_function_and_call( "test('test')", "test", - new_native_function!(|_isolate, _ctx_scope, arg1: v8_utf8::V8LocalUtf8| { + new_native_function!(|_isolate, _ctx_scope, arg1: types::utf8::LocalUtf8| { assert_eq!(arg1.as_str(), "test"); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -561,9 +560,9 @@ mod json_path_tests { define_function_and_call( "test('test')", "test", - new_native_function!(|_isolate, _ctx_scope, arg1: v8_value::V8LocalValue| { + new_native_function!(|_isolate, _ctx_scope, arg1: types::LocalValueGeneric| { assert_eq!(arg1.to_utf8().unwrap().as_str(), "test"); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -574,8 +573,8 @@ mod json_path_tests { define_function_and_call( "test(new Set())", "test", - new_native_function!(|_isolate, _ctx_scope, _arg1: v8_set::V8LocalSet| { - Result::, String>::Ok(None) + new_native_function!(|_isolate, _ctx_scope, _arg1: types::set::LocalSet| { + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -586,9 +585,9 @@ mod json_path_tests { define_function_and_call( "test([1, 2])", "test", - new_native_function!(|_isolate, _ctx_scope, arg1: v8_array::V8LocalArray| { + new_native_function!(|_isolate, _ctx_scope, arg1: types::array::LocalArray| { assert_eq!(arg1.len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -600,9 +599,9 @@ mod json_path_tests { "test(new Uint8Array([255, 255, 255, 255]).buffer)", "test", new_native_function!( - |_isolate, _ctx_scope, arg1: v8_array_buffer::V8LocalArrayBuffer| { + |_isolate, _ctx_scope, arg1: types::array_buffer::LocalArrayBuffer| { assert_eq!(arg1.data(), &[255, 255, 255, 255]); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -615,9 +614,9 @@ mod json_path_tests { "test({'foo':'bar'})", "test", new_native_function!( - |isolate_scope: &isolate_scope::V8IsolateScope, + |isolate_scope: &isolate_scope::IsolateScope, ctx_scope, - arg1: v8_object::V8LocalObject| { + arg1: types::object::LocalObject| { assert_eq!( arg1.get(ctx_scope, &isolate_scope.new_string("foo").to_value()) .unwrap() @@ -626,7 +625,7 @@ mod json_path_tests { .as_str(), "bar" ); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -641,7 +640,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -659,7 +658,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -682,7 +681,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3, None); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -705,7 +704,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3, Some(2.2)); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -725,11 +724,11 @@ mod json_path_tests { _ctx_scope, arg1: i64, arg2: i64, - arg3: Option| { + arg3: Option| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert!(arg3.is_none()); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -750,11 +749,11 @@ mod json_path_tests { _ctx_scope, arg1: i64, arg2: i64, - arg3: Option| { + arg3: Option| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3.unwrap().len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -775,11 +774,11 @@ mod json_path_tests { _ctx_scope, arg1: i64, arg2: i64, - arg3: Option| { + arg3: Option| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3.unwrap().is_array(), true); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -795,9 +794,9 @@ mod json_path_tests { define_function_and_call( "test(1, 'foo', [1, 2])", "test", - new_native_function!(|_isolate, _ctx_scope, arg: Vec| { + new_native_function!(|_isolate, _ctx_scope, arg: Vec| { assert_eq!(arg.len(), 3); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -809,10 +808,10 @@ mod json_path_tests { "test(1, 'foo', [1, 2])", "test", new_native_function!( - |_isolate, _ctx_scope, arg1: i64, arg2: Vec| { + |_isolate, _ctx_scope, arg1: i64, arg2: Vec| { assert_eq!(arg1, 1); assert_eq!(arg2.len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -827,7 +826,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: Vec| { assert_eq!(arg1, 1); assert_eq!(arg2.len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); diff --git a/src/v8/v8_context.rs b/src/v8/context.rs similarity index 86% rename from src/v8/v8_context.rs rename to src/v8/context.rs index dc522e4..5968d35 100644 --- a/src/v8/v8_context.rs +++ b/src/v8/context.rs @@ -14,10 +14,10 @@ use std::marker::PhantomData; use std::os::raw::c_void; use std::ptr; -use crate::v8::isolate::V8Isolate; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_object_template::V8LocalObjectTemplate; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate::Isolate; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::object_template::LocalObjectTemplate; /// An RAII data guard which resets the private data slot after going /// out of scope. @@ -25,12 +25,12 @@ pub struct V8ContextDataGuard<'context, 'data, T: 'data> { /// A raw index to reset after the guard goes out of scope. index: RawIndex, /// The context in which the guard should reset the variable. - context: &'context V8Context, + context: &'context Context, _phantom_data: PhantomData<&'data T>, } impl<'context, 'data, T: 'data> V8ContextDataGuard<'context, 'data, T> { /// Creates a new data guard with the provided index and context scope. - pub(crate) fn new>(index: I, context: &'context V8Context) -> Self { + pub(crate) fn new>(index: I, context: &'context Context) -> Self { let index = index.into(); Self { index, @@ -46,15 +46,15 @@ impl<'context, 'data, T: 'data> Drop for V8ContextDataGuard<'context, 'data, T> } } -pub struct V8Context { +pub struct Context { pub(crate) inner_ctx: *mut v8_context, } -unsafe impl Sync for V8Context {} -unsafe impl Send for V8Context {} +unsafe impl Sync for Context {} +unsafe impl Send for Context {} -impl V8Context { - pub(crate) fn new(isolate: &V8Isolate, globals: Option<&V8LocalObjectTemplate>) -> Self { +impl Context { + pub(crate) fn new(isolate: &Isolate, globals: Option<&LocalObjectTemplate>) -> Self { let inner_ctx = match globals { Some(g) => unsafe { v8_NewContext(isolate.inner_isolate, g.inner_obj) }, None => unsafe { v8_NewContext(isolate.inner_isolate, ptr::null_mut()) }, @@ -69,10 +69,10 @@ impl V8Context { #[must_use] pub fn enter<'isolate_scope, 'isolate>( &self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8ContextScope<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> ContextScope<'isolate_scope, 'isolate> { let inner_ctx_ref = unsafe { v8_ContextEnter(self.inner_ctx) }; - V8ContextScope { + ContextScope { inner_ctx_ref, exit_on_drop: true, isolate_scope, @@ -130,7 +130,7 @@ impl V8Context { } } -impl Drop for V8Context { +impl Drop for Context { fn drop(&mut self) { unsafe { v8_FreeContext(self.inner_ctx) } } diff --git a/src/v8/v8_context_scope.rs b/src/v8/context_scope.rs similarity index 73% rename from src/v8/v8_context_scope.rs rename to src/v8/context_scope.rs index 37c145e..23aadd3 100644 --- a/src/v8/v8_context_scope.rs +++ b/src/v8/context_scope.rs @@ -15,34 +15,34 @@ use crate::{RawIndex, UserIndex}; use std::marker::PhantomData; use std::os::raw::c_void; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_module::V8LocalModule; -use crate::v8::v8_native_function::V8LocalNativeFunction; -use crate::v8::v8_native_function_template::free_pd; -use crate::v8::v8_native_function_template::native_basic_function; -use crate::v8::v8_native_function_template::V8LocalNativeFunctionArgs; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_resolver::V8LocalResolver; -use crate::v8::v8_script::V8LocalScript; -use crate::v8::v8_string::V8LocalString; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::module::LocalModule; +use crate::v8::types::native_function::LocalNativeFunction; +use crate::v8::types::native_function_template::free_pd; +use crate::v8::types::native_function_template::native_basic_function; +use crate::v8::types::native_function_template::LocalNativeFunctionArgs; +use crate::v8::types::object::LocalObject; +use crate::v8::types::resolver::LocalResolver; +use crate::v8::types::script::LocalScript; +use crate::v8::types::string::LocalString; +use crate::v8::types::LocalValueGeneric; /// An RAII data guard which resets the private data slot after going /// out of scope. -pub struct V8ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> { +pub struct ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> { /// Raw Index to reset after the guard goes out of scope. index: RawIndex, /// The context scope in which the guard should reset the variable. - context_scope: &'context_scope V8ContextScope<'isolate_scope, 'isolate>, + context_scope: &'context_scope ContextScope<'isolate_scope, 'isolate>, _phantom_data: PhantomData<&'data T>, } impl<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> - V8ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> + ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> { /// Creates a new data guard with the provided index and context scope. pub(crate) fn new>( index: I, - context_scope: &'context_scope V8ContextScope<'isolate_scope, 'isolate>, + context_scope: &'context_scope ContextScope<'isolate_scope, 'isolate>, ) -> Self { let index = index.into(); Self { @@ -54,28 +54,28 @@ impl<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> } impl<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> Drop - for V8ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> + for ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> { fn drop(&mut self) { self.context_scope.reset_private_data_raw(self.index); } } -pub struct V8ContextScope<'isolate_scope, 'isolate> { +pub struct ContextScope<'isolate_scope, 'isolate> { pub(crate) inner_ctx_ref: *mut v8_context_ref, pub(crate) exit_on_drop: bool, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { /// Compile the given code into a script object. #[must_use] - pub fn compile(&self, s: &V8LocalString) -> Option> { + pub fn compile(&self, s: &LocalString) -> Option> { let inner_script = unsafe { v8_Compile(self.inner_ctx_ref, s.inner_string) }; if inner_script.is_null() { None } else { - Some(V8LocalScript { + Some(LocalScript { inner_script, isolate_scope: self.isolate_scope, }) @@ -83,9 +83,9 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { } #[must_use] - pub fn get_globals(&self) -> V8LocalObject<'isolate_scope, 'isolate> { + pub fn get_globals(&self) -> LocalObject<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_ContextRefGetGlobals(self.inner_ctx_ref) }; - V8LocalObject { + LocalObject { inner_obj, isolate_scope: self.isolate_scope, } @@ -95,10 +95,10 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { #[must_use] pub fn compile_as_module( &self, - name: &V8LocalString, - code: &V8LocalString, + name: &LocalString, + code: &LocalString, is_module: bool, - ) -> Option> { + ) -> Option> { let inner_module = unsafe { v8_CompileAsModule( self.inner_ctx_ref, @@ -110,7 +110,7 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { if inner_module.is_null() { None } else { - Some(V8LocalModule { + Some(LocalModule { inner_module, isolate_scope: self.isolate_scope, }) @@ -174,10 +174,10 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { &'context_scope self, index: I, data: &'data T, - ) -> V8ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> { + ) -> ContextScopeDataGuard<'context_scope, 'data, 'isolate_scope, 'isolate, T> { let index = index.into(); self.set_private_data_raw(index, data); - V8ContextScopeDataGuard::new(index, self) + ContextScopeDataGuard::new(index, self) } pub fn reset_private_data>(&self, index: I) { @@ -187,9 +187,9 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { /// Create a new resolver object #[must_use] - pub fn new_resolver(&self) -> V8LocalResolver<'isolate_scope, 'isolate> { + pub fn new_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { let inner_resolver = unsafe { v8_NewResolver(self.inner_ctx_ref) }; - V8LocalResolver { + LocalResolver { inner_resolver, isolate_scope: self.isolate_scope, } @@ -198,13 +198,13 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { #[must_use] pub fn new_object_from_json( &self, - val: &V8LocalString, - ) -> Option> { + val: &LocalString, + ) -> Option> { let inner_val = unsafe { v8_NewObjectFromJsonString(self.inner_ctx_ref, val.inner_string) }; if inner_val.is_null() { return None; } - Some(V8LocalValue { + Some(LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, }) @@ -213,13 +213,13 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { #[must_use] pub fn json_stringify( &self, - val: &V8LocalValue, - ) -> Option> { + val: &LocalValueGeneric, + ) -> Option> { let inner_string = unsafe { v8_JsonStringify(self.inner_ctx_ref, val.inner_val) }; if inner_string.is_null() { return None; } - Some(V8LocalString { + Some(LocalString { inner_string, isolate_scope: self.isolate_scope, }) @@ -228,14 +228,14 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { #[must_use] pub fn new_native_function< T: for<'d, 'c> Fn( - &V8LocalNativeFunctionArgs<'d, 'c>, - &'d V8IsolateScope<'c>, - &V8ContextScope<'d, 'c>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'c>, + &'d IsolateScope<'c>, + &ContextScope<'d, 'c>, + ) -> Option>, >( &self, func: T, - ) -> V8LocalNativeFunction<'isolate_scope, 'isolate> { + ) -> LocalNativeFunction<'isolate_scope, 'isolate> { let inner_func = unsafe { v8_NewNativeFunction( self.inner_ctx_ref, @@ -244,14 +244,14 @@ impl<'isolate_scope, 'isolate> V8ContextScope<'isolate_scope, 'isolate> { Some(free_pd::), ) }; - V8LocalNativeFunction { + LocalNativeFunction { inner_func, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8ContextScope<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for ContextScope<'isolate_scope, 'isolate> { fn drop(&mut self) { if self.exit_on_drop { unsafe { v8_ExitContextRef(self.inner_ctx_ref) } diff --git a/src/v8/isolate.rs b/src/v8/isolate.rs index 0ebe8b4..c7fd777 100644 --- a/src/v8/isolate.rs +++ b/src/v8/isolate.rs @@ -14,33 +14,33 @@ use crate::v8_c_raw::bindings::{ use std::os::raw::c_void; -use crate::v8::isolate_scope::V8IsolateScope; +use crate::v8::isolate_scope::IsolateScope; use std::ffi::CStr; use std::os::raw::{c_char, c_int}; /// An isolate rust wrapper object. /// The isolate will not be automatically freed. /// In order to free an isolate, one must call [`V8Isolate::free_isolate`]. -pub struct V8Isolate { +pub struct Isolate { pub(crate) inner_isolate: *mut v8_isolate, pub(crate) no_release: bool, } -unsafe impl Sync for V8Isolate {} -unsafe impl Send for V8Isolate {} +unsafe impl Sync for Isolate {} +unsafe impl Send for Isolate {} -pub(crate) extern "C" fn interrupt_callback( +pub(crate) extern "C" fn interrupt_callback( inner_isolate: *mut v8_isolate, data: *mut ::std::os::raw::c_void, ) { let func = unsafe { &*(data.cast::()) }; - func(&V8Isolate { + func(&Isolate { inner_isolate, no_release: true, }); } -impl Default for V8Isolate { +impl Default for Isolate { fn default() -> Self { Self::new() } @@ -77,7 +77,7 @@ extern "C" fn near_oom_callback_free_pd usize>(data: *mut } } -impl V8Isolate { +impl Isolate { /// Create a new v8 isolate with default heap size (up to 1G). #[must_use] pub fn new() -> Self { @@ -110,13 +110,13 @@ impl V8Isolate { } /// Enter the isolate for code invocation. - /// Return an `V8IsolateScope` object, when the returned + /// Return an [`IsolateScope`] object, when the returned /// object is destroy the code will exit the isolate. /// /// An isolate must be entered before running any JS code. #[must_use] - pub fn enter(&self) -> V8IsolateScope { - V8IsolateScope::new(self) + pub fn enter(&self) -> IsolateScope { + IsolateScope::new(self) } /// Sets an idle notification that the embedder is idle for longer @@ -232,7 +232,7 @@ impl V8Isolate { } } -impl Drop for V8Isolate { +impl Drop for Isolate { fn drop(&mut self) { if !self.no_release { unsafe { v8_FreeIsolate(self.inner_isolate) } diff --git a/src/v8/isolate_scope.rs b/src/v8/isolate_scope.rs index ce08569..5dbc818 100644 --- a/src/v8/isolate_scope.rs +++ b/src/v8/isolate_scope.rs @@ -12,27 +12,27 @@ use crate::v8_c_raw::bindings::{ v8_ValueFromLong, v8_handlers_scope, v8_isolate_scope, v8_local_value, }; -use crate::v8::isolate::V8Isolate; -use crate::v8::try_catch::V8TryCatch; -use crate::v8::v8_array::V8LocalArray; -use crate::v8::v8_array_buffer::V8LocalArrayBuffer; -use crate::v8::v8_context::V8Context; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_external_data::V8LocalExternalData; -use crate::v8::v8_native_function_template::{ - free_pd, native_basic_function, V8LocalNativeFunctionArgs, V8LocalNativeFunctionTemplate, +use crate::v8::context::Context; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate::Isolate; +use crate::v8::types::array::LocalArray; +use crate::v8::types::array_buffer::LocalArrayBuffer; +use crate::v8::types::external_data::LocalExternalData; +use crate::v8::types::native_function_template::{ + free_pd, native_basic_function, LocalNativeFunctionArgs, LocalNativeFunctionTemplate, }; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_object_template::V8LocalObjectTemplate; -use crate::v8::v8_set::V8LocalSet; -use crate::v8::v8_string::V8LocalString; -use crate::v8::v8_unlocker::V8Unlocker; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::types::object::LocalObject; +use crate::v8::types::object_template::LocalObjectTemplate; +use crate::v8::types::set::LocalSet; +use crate::v8::types::string::LocalString; +use crate::v8::types::try_catch::TryCatch; +use crate::v8::types::unlocker::Unlocker; +use crate::v8::types::LocalValueGeneric; use std::os::raw::{c_char, c_void}; -pub struct V8IsolateScope<'isolate> { - pub(crate) isolate: &'isolate V8Isolate, +pub struct IsolateScope<'isolate> { + pub(crate) isolate: &'isolate Isolate, inner_handlers_scope: *mut v8_handlers_scope, inner_isolate_scope: *mut v8_isolate_scope, } @@ -41,11 +41,11 @@ extern "C" fn free_external_data(arg1: *mut ::std::os::raw::c_void) { unsafe { Box::from_raw(arg1 as *mut T) }; } -impl<'isolate> V8IsolateScope<'isolate> { - pub(crate) fn new(isolate: &'isolate V8Isolate) -> V8IsolateScope<'isolate> { +impl<'isolate> IsolateScope<'isolate> { + pub(crate) fn new(isolate: &'isolate Isolate) -> IsolateScope<'isolate> { let inner_isolate_scope = unsafe { v8_IsolateEnter(isolate.inner_isolate) }; let inner_handlers_scope = unsafe { v8_NewHandlersScope(isolate.inner_isolate) }; - V8IsolateScope { + IsolateScope { isolate, inner_handlers_scope, inner_isolate_scope, @@ -54,12 +54,12 @@ impl<'isolate> V8IsolateScope<'isolate> { /// Creating a new context for JS code invocation. #[must_use] - pub fn new_context(&self, globals: Option<&V8LocalObjectTemplate>) -> V8Context { - V8Context::new(self.isolate, globals) + pub fn new_context(&self, globals: Option<&LocalObjectTemplate>) -> Context { + Context::new(self.isolate, globals) } /// Raise an exception with the given local generic value. - pub fn raise_exception(&self, exception: V8LocalValue) { + pub fn raise_exception(&self, exception: LocalValueGeneric) { unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, exception.inner_val) }; } @@ -81,9 +81,9 @@ impl<'isolate> V8IsolateScope<'isolate> { #[must_use] pub fn new_try_catch<'isolate_scope>( &'isolate_scope self, - ) -> V8TryCatch<'isolate_scope, 'isolate> { + ) -> TryCatch<'isolate_scope, 'isolate> { let inner_trycatch = unsafe { v8_NewTryCatch(self.isolate.inner_isolate) }; - V8TryCatch { + TryCatch { inner_trycatch, isolate_scope: self, } @@ -94,7 +94,7 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_string<'isolate_scope>( &'isolate_scope self, s: &str, - ) -> V8LocalString<'isolate_scope, 'isolate> { + ) -> LocalString<'isolate_scope, 'isolate> { let inner_string = unsafe { v8_NewString( self.isolate.inner_isolate, @@ -102,7 +102,7 @@ impl<'isolate> V8IsolateScope<'isolate> { s.len(), ) }; - V8LocalString { + LocalString { inner_string, isolate_scope: self, } @@ -112,15 +112,15 @@ impl<'isolate> V8IsolateScope<'isolate> { #[must_use] pub fn new_array<'isolate_scope>( &'isolate_scope self, - values: &[&V8LocalValue], - ) -> V8LocalArray<'isolate_scope, 'isolate> { + values: &[&LocalValueGeneric], + ) -> LocalArray<'isolate_scope, 'isolate> { let args = values .iter() .map(|v| v.inner_val) .collect::>(); let ptr = args.as_ptr(); let inner_array = unsafe { v8_NewArray(self.isolate.inner_isolate, ptr, values.len()) }; - V8LocalArray { + LocalArray { inner_array, isolate_scope: self, } @@ -130,7 +130,7 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_array_buffer<'isolate_scope>( &'isolate_scope self, buff: &[u8], - ) -> V8LocalArrayBuffer<'isolate_scope, 'isolate> { + ) -> LocalArrayBuffer<'isolate_scope, 'isolate> { let inner_array_buffer = unsafe { v8_NewArrayBuffer( self.isolate.inner_isolate, @@ -138,7 +138,7 @@ impl<'isolate> V8IsolateScope<'isolate> { buff.len(), ) }; - V8LocalArrayBuffer { + LocalArrayBuffer { inner_array_buffer, isolate_scope: self, } @@ -147,9 +147,9 @@ impl<'isolate> V8IsolateScope<'isolate> { #[must_use] pub fn new_object<'isolate_scope>( &'isolate_scope self, - ) -> V8LocalObject<'isolate_scope, 'isolate> { + ) -> LocalObject<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_NewObject(self.isolate.inner_isolate) }; - V8LocalObject { + LocalObject { inner_obj, isolate_scope: self, } @@ -159,7 +159,7 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_external_data<'isolate_scope, T>( &'isolate_scope self, data: T, - ) -> V8LocalExternalData<'isolate_scope, 'isolate> { + ) -> LocalExternalData<'isolate_scope, 'isolate> { let data = Box::into_raw(Box::new(data)); let inner_ext = unsafe { v8_NewExternalData( @@ -168,16 +168,16 @@ impl<'isolate> V8IsolateScope<'isolate> { Some(free_external_data::), ) }; - V8LocalExternalData { + LocalExternalData { inner_ext, isolate_scope: self, } } #[must_use] - pub fn new_set<'isolate_scope>(&'isolate_scope self) -> V8LocalSet<'isolate_scope, 'isolate> { + pub fn new_set<'isolate_scope>(&'isolate_scope self) -> LocalSet<'isolate_scope, 'isolate> { let inner_set = unsafe { v8_NewSet(self.isolate.inner_isolate) }; - V8LocalSet { + LocalSet { inner_set, isolate_scope: self, } @@ -187,9 +187,9 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_bool<'isolate_scope>( &'isolate_scope self, val: bool, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_NewBool(self.isolate.inner_isolate, val as i32) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self, } @@ -198,9 +198,9 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_long<'isolate_scope>( &'isolate_scope self, val: i64, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ValueFromLong(self.isolate.inner_isolate, val) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self, } @@ -209,9 +209,9 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_double<'isolate_scope>( &'isolate_scope self, val: f64, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ValueFromDouble(self.isolate.inner_isolate, val) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self, } @@ -219,9 +219,9 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_null<'isolate_scope>( &'isolate_scope self, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_NewNull(self.isolate.inner_isolate) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self, } @@ -231,9 +231,9 @@ impl<'isolate> V8IsolateScope<'isolate> { #[must_use] pub fn new_object_template<'isolate_scope>( &'isolate_scope self, - ) -> V8LocalObjectTemplate<'isolate_scope, 'isolate> { + ) -> LocalObjectTemplate<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_NewObjectTemplate(self.isolate.inner_isolate) }; - V8LocalObjectTemplate { + LocalObjectTemplate { inner_obj, isolate_scope: self, } @@ -243,14 +243,14 @@ impl<'isolate> V8IsolateScope<'isolate> { pub fn new_native_function_template< 'isolate_scope, T: for<'d, 'e> Fn( - &V8LocalNativeFunctionArgs<'d, 'e>, - &'d V8IsolateScope<'e>, - &V8ContextScope<'d, 'e>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'e>, + &'d IsolateScope<'e>, + &ContextScope<'d, 'e>, + ) -> Option>, >( &'isolate_scope self, func: T, - ) -> V8LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { + ) -> LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { let inner_func = unsafe { v8_NewNativeFunctionTemplate( self.isolate.inner_isolate, @@ -259,7 +259,7 @@ impl<'isolate> V8IsolateScope<'isolate> { Some(free_pd::), ) }; - V8LocalNativeFunctionTemplate { + LocalNativeFunctionTemplate { inner_func, isolate_scope: self, } @@ -270,16 +270,16 @@ impl<'isolate> V8IsolateScope<'isolate> { #[must_use] pub fn new_unlocker<'isolate_scope>( &'isolate_scope self, - ) -> V8Unlocker<'isolate_scope, 'isolate> { + ) -> Unlocker<'isolate_scope, 'isolate> { let inner_unlocker = unsafe { v8_NewUnlocker(self.isolate.inner_isolate) }; - V8Unlocker { + Unlocker { inner_unlocker, _isolate_scope: self, } } } -impl<'isolate> Drop for V8IsolateScope<'isolate> { +impl<'isolate> Drop for IsolateScope<'isolate> { fn drop(&mut self) { unsafe { v8_FreeHandlersScope(self.inner_handlers_scope); diff --git a/src/v8/mod.rs b/src/v8/mod.rs index 775244d..1c2e786 100644 --- a/src/v8/mod.rs +++ b/src/v8/mod.rs @@ -9,27 +9,11 @@ use crate::v8_c_raw::bindings::{v8_Dispose, v8_Initialize, v8_Version}; use std::ffi::CStr; use std::ptr; +pub mod context; +pub mod context_scope; pub mod isolate; pub mod isolate_scope; -pub mod try_catch; -pub mod v8_array; -pub mod v8_array_buffer; -pub mod v8_context; -pub mod v8_context_scope; -pub mod v8_external_data; -pub mod v8_module; -pub mod v8_native_function; -pub mod v8_native_function_template; -pub mod v8_object; -pub mod v8_object_template; -pub mod v8_promise; -pub mod v8_resolver; -pub mod v8_script; -pub mod v8_set; -pub mod v8_string; -pub mod v8_unlocker; -pub mod v8_utf8; -pub mod v8_value; +pub mod types; pub(crate) type FatalErrorCallback = dyn Fn(&str, &str); pub(crate) type OutOfMemoryErrorCallback = dyn Fn(&str, bool); diff --git a/src/v8/v8_array.rs b/src/v8/types/array.rs similarity index 63% rename from src/v8/v8_array.rs rename to src/v8/types/array.rs index 44efc5c..977925b 100644 --- a/src/v8/v8_array.rs +++ b/src/v8/types/array.rs @@ -8,17 +8,17 @@ use crate::v8_c_raw::bindings::{ v8_ArrayGet, v8_ArrayLen, v8_ArrayToValue, v8_FreeArray, v8_local_array, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// JS object -pub struct V8LocalArray<'isolate_scope, 'isolate> { +pub struct LocalArray<'isolate_scope, 'isolate> { pub(crate) inner_array: *mut v8_local_array, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalArray<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalArray<'isolate_scope, 'isolate> { /// Returns the length of the array. pub fn len(&self) -> usize { unsafe { v8_ArrayLen(self.inner_array) } @@ -32,7 +32,7 @@ impl<'isolate_scope, 'isolate> V8LocalArray<'isolate_scope, 'isolate> { /// Returns an iterator to the array's objects. pub fn iter<'array, 'context_scope>( &'array self, - context_scope: &'context_scope V8ContextScope<'isolate_scope, 'isolate>, + context_scope: &'context_scope ContextScope<'isolate_scope, 'isolate>, ) -> V8LocalArrayIterator<'context_scope, 'array, 'isolate_scope, 'isolate> { V8LocalArrayIterator { index: 0, @@ -44,30 +44,30 @@ impl<'isolate_scope, 'isolate> V8LocalArray<'isolate_scope, 'isolate> { /// Returns a single object stored within the array. pub fn get( &self, - ctx_scope: &V8ContextScope, + ctx_scope: &ContextScope, index: usize, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ArrayGet(ctx_scope.inner_ctx_ref, self.inner_array, index) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } /// Converts the array to a value object. - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ArrayToValue(self.inner_array) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> From> - for V8LocalValue<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> From> + for LocalValueGeneric<'isolate_scope, 'isolate> { - fn from(array: V8LocalArray<'isolate_scope, 'isolate>) -> Self { + fn from(array: LocalArray<'isolate_scope, 'isolate>) -> Self { array.to_value() } } @@ -75,14 +75,14 @@ impl<'isolate_scope, 'isolate> From> /// An iterator over the objects stored within the [`V8LocalArray`]. pub struct V8LocalArrayIterator<'context_scope, 'array, 'isolate_scope, 'isolate> { index: usize, - array: &'array V8LocalArray<'isolate_scope, 'isolate>, - context: &'context_scope V8ContextScope<'isolate_scope, 'isolate>, + array: &'array LocalArray<'isolate_scope, 'isolate>, + context: &'context_scope ContextScope<'isolate_scope, 'isolate>, } impl<'context_scope, 'array, 'isolate_scope, 'isolate> Iterator for V8LocalArrayIterator<'context_scope, 'array, 'isolate_scope, 'isolate> { - type Item = V8LocalValue<'isolate_scope, 'isolate>; + type Item = LocalValueGeneric<'isolate_scope, 'isolate>; fn next(&mut self) -> Option { if self.index >= self.array.len() { @@ -95,18 +95,18 @@ impl<'context_scope, 'array, 'isolate_scope, 'isolate> Iterator } } -impl<'isolate_scope, 'isolate> Drop for V8LocalArray<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalArray<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeArray(self.inner_array) } } } -impl<'isolate_scope, 'isolate> TryFrom> - for V8LocalArray<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> TryFrom> + for LocalArray<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_array() { return Err("Value is not an array"); } diff --git a/src/v8/v8_array_buffer.rs b/src/v8/types/array_buffer.rs similarity index 60% rename from src/v8/v8_array_buffer.rs rename to src/v8/types/array_buffer.rs index 6cf5eca..8c1c439 100644 --- a/src/v8/v8_array_buffer.rs +++ b/src/v8/types/array_buffer.rs @@ -8,16 +8,16 @@ use crate::v8_c_raw::bindings::{ v8_ArrayBufferGetData, v8_ArrayBufferToValue, v8_FreeArrayBuffer, v8_local_array_buff, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// JS object -pub struct V8LocalArrayBuffer<'isolate_scope, 'isolate> { +pub struct LocalArrayBuffer<'isolate_scope, 'isolate> { pub(crate) inner_array_buffer: *mut v8_local_array_buff, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalArrayBuffer<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalArrayBuffer<'isolate_scope, 'isolate> { pub fn data(&self) -> &[u8] { let mut size = 0; let data = @@ -25,26 +25,26 @@ impl<'isolate_scope, 'isolate> V8LocalArrayBuffer<'isolate_scope, 'isolate> { unsafe { std::slice::from_raw_parts(data.cast::(), size) } } - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ArrayBufferToValue(self.inner_array_buffer) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalArrayBuffer<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalArrayBuffer<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeArrayBuffer(self.inner_array_buffer) } } } -impl<'isolate_scope, 'isolate> TryFrom> - for V8LocalArrayBuffer<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> TryFrom> + for LocalArrayBuffer<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_array_buffer() { return Err("Value is not an array buffer"); } diff --git a/src/v8/v8_external_data.rs b/src/v8/types/external_data.rs similarity index 68% rename from src/v8/v8_external_data.rs rename to src/v8/types/external_data.rs index ab2fe7e..60ad495 100644 --- a/src/v8/v8_external_data.rs +++ b/src/v8/types/external_data.rs @@ -8,21 +8,21 @@ use crate::v8_c_raw::bindings::{ v8_ExternalDataGet, v8_ExternalDataToValue, v8_local_external_data, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// JS object -pub struct V8LocalExternalData<'isolate_scope, 'isolate> { +pub struct LocalExternalData<'isolate_scope, 'isolate> { pub(crate) inner_ext: *mut v8_local_external_data, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalExternalData<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalExternalData<'isolate_scope, 'isolate> { /// Convert the object into a generic JS value #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ExternalDataToValue(self.inner_ext) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } diff --git a/src/v8/v8_value.rs b/src/v8/types/mod.rs similarity index 68% rename from src/v8/v8_value.rs rename to src/v8/types/mod.rs index 455da86..f594dfe 100644 --- a/src/v8/v8_value.rs +++ b/src/v8/types/mod.rs @@ -16,42 +16,116 @@ use crate::v8_c_raw::bindings::{ use std::ptr; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_array::V8LocalArray; -use crate::v8::v8_array_buffer::V8LocalArrayBuffer; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_external_data::V8LocalExternalData; -use crate::v8::v8_native_function_template::V8LocalNativeFunctionArgsIter; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_promise::V8LocalPromise; -use crate::v8::v8_resolver::V8LocalResolver; -use crate::v8::v8_set::V8LocalSet; -use crate::v8::v8_string::V8LocalString; -use crate::v8::v8_utf8::V8LocalUtf8; +pub mod array; +pub mod array_buffer; +pub mod external_data; +pub mod module; +pub mod native_function; +pub mod native_function_template; +pub mod object; +pub mod object_template; +pub mod promise; +pub mod resolver; +pub mod script; +pub mod set; +pub mod string; +pub mod try_catch; +pub mod unlocker; +pub mod utf8; + +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; use crate::v8::OptionalTryFrom; +use array::LocalArray; +use array_buffer::LocalArrayBuffer; +use external_data::LocalExternalData; +use native_function_template::V8LocalNativeFunctionArgsIter; +use object::LocalObject; +use promise::LocalPromise; +use resolver::LocalResolver; +use set::LocalSet; +use string::LocalString; +use utf8::LocalUtf8; /// JS generic local value -pub struct V8LocalValue<'isolate_scope, 'isolate> { +pub struct LocalValueGeneric<'isolate_scope, 'isolate> { pub(crate) inner_val: *mut v8_local_value, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } +pub type LocalValue<'isolate_scope, 'isolate> = LocalValueGeneric<'isolate_scope, 'isolate>; + +// #[repr(transparent)] +// pub struct LocalArray<'isolate_scope, 'isolate> { +// value: LocalGeneric<'isolate_scope, 'isolate>, +// } +// impl<'isolate_scope, 'isolate> LocalArray<'isolate_scope, 'isolate> { +// /// Return string representation of the value or None on failure +// #[must_use] +// pub fn to_utf8(&self) -> Option> { +// let inner_val = unsafe { +// v8_ToUtf8( +// self.value.isolate_scope.isolate.inner_isolate, +// self.value.inner_val, +// ) +// }; +// if inner_val.is_null() { +// None +// } else { +// Some(LocalUtf8 { +// inner_val, +// _isolate_scope: self.value.isolate_scope, +// }) +// } +// } +// } + +// #[repr(transparent)] +// pub struct LocalValueString<'isolate_scope, 'isolate> { +// value: LocalGeneric<'isolate_scope, 'isolate>, +// } +// impl<'isolate_scope, 'isolate> LocalValueString<'isolate_scope, 'isolate> { +// /// Return string representation of the value or None on failure +// #[must_use] +// pub fn to_utf8(&self) -> Option> { +// let inner_val = unsafe { +// v8_ToUtf8( +// self.value.isolate_scope.isolate.inner_isolate, +// self.value.inner_val, +// ) +// }; +// if inner_val.is_null() { +// None +// } else { +// Some(LocalUtf8 { +// inner_val, +// _isolate_scope: self.value.isolate_scope, +// }) +// } +// } +// } + +// pub enum V8LocalValue<'isolate_scope, 'isolate> { +// Array(LocalArray<'isolate_scope, 'isolate>), +// String(LocalValueString<'isolate_scope, 'isolate>), +// Number(LocalGeneric<'isolate_scope, 'isolate>), +// } /// JS generic persisted value -pub struct V8PersistValue { +pub struct PersistValue { pub(crate) inner_val: *mut v8_persisted_value, forget: bool, } -impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalValueGeneric<'isolate_scope, 'isolate> { /// Return string representation of the value or None on failure #[must_use] - pub fn to_utf8(&self) -> Option> { + pub fn to_utf8(&self) -> Option> { let inner_val = unsafe { v8_ToUtf8(self.isolate_scope.isolate.inner_isolate, self.inner_val) }; if inner_val.is_null() { None } else { - Some(V8LocalUtf8 { + Some(LocalUtf8 { inner_val, _isolate_scope: self.isolate_scope, }) @@ -66,9 +140,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a string, applicable only if the value is string. #[must_use] - pub fn as_string(&self) -> V8LocalString<'isolate_scope, 'isolate> { + pub fn as_string(&self) -> LocalString<'isolate_scope, 'isolate> { let inner_str = unsafe { v8_ValueAsString(self.inner_val) }; - V8LocalString { + LocalString { inner_string: inner_str, isolate_scope: self.isolate_scope, } @@ -88,9 +162,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a string, applicable only if the value is string. #[must_use] - pub fn as_array(&self) -> V8LocalArray<'isolate_scope, 'isolate> { + pub fn as_array(&self) -> LocalArray<'isolate_scope, 'isolate> { let inner_array = unsafe { v8_ValueAsArray(self.inner_val) }; - V8LocalArray { + LocalArray { inner_array, isolate_scope: self.isolate_scope, } @@ -104,9 +178,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a string, applicable only if the value is string. #[must_use] - pub fn as_array_buffer(&self) -> V8LocalArrayBuffer<'isolate_scope, 'isolate> { + pub fn as_array_buffer(&self) -> LocalArrayBuffer<'isolate_scope, 'isolate> { let inner_array_buffer = unsafe { v8_ValueAsArrayBuffer(self.inner_val) }; - V8LocalArrayBuffer { + LocalArrayBuffer { inner_array_buffer, isolate_scope: self.isolate_scope, } @@ -168,9 +242,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a promise, applicable only if the object is promise. #[must_use] - pub fn as_promise(&self) -> V8LocalPromise<'isolate_scope, 'isolate> { + pub fn as_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { let inner_promise = unsafe { v8_ValueAsPromise(self.inner_val) }; - V8LocalPromise { + LocalPromise { inner_promise, isolate_scope: self.isolate_scope, } @@ -178,9 +252,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a resolver, applicable only if the object is resolver. #[must_use] - pub fn as_resolver(&self) -> V8LocalResolver<'isolate_scope, 'isolate> { + pub fn as_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { let inner_resolver = unsafe { v8_ValueAsResolver(self.inner_val) }; - V8LocalResolver { + LocalResolver { inner_resolver, isolate_scope: self.isolate_scope, } @@ -194,9 +268,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a promise, applicable only if the object is promise. #[must_use] - pub fn as_object(&self) -> V8LocalObject<'isolate_scope, 'isolate> { + pub fn as_object(&self) -> LocalObject<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_ValueAsObject(self.inner_val) }; - V8LocalObject { + LocalObject { inner_obj, isolate_scope: self.isolate_scope, } @@ -208,9 +282,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { } #[must_use] - pub fn as_external_data(&self) -> V8LocalExternalData<'isolate_scope, 'isolate> { + pub fn as_external_data(&self) -> LocalExternalData<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_ValueAsExternalData(self.inner_val) }; - V8LocalExternalData { + LocalExternalData { inner_ext: inner_obj, isolate_scope: self.isolate_scope, } @@ -224,9 +298,9 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Convert the object into a promise, applicable only if the object is promise. #[must_use] - pub fn as_set(&self) -> V8LocalSet<'isolate_scope, 'isolate> { + pub fn as_set(&self) -> LocalSet<'isolate_scope, 'isolate> { let inner_set = unsafe { v8_ValueAsSet(self.inner_val) }; - V8LocalSet { + LocalSet { inner_set, isolate_scope: self.isolate_scope, } @@ -234,10 +308,10 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Persist the local object so it can be saved beyond the current handlers scope. #[must_use] - pub fn persist(&self) -> V8PersistValue { + pub fn persist(&self) -> PersistValue { let inner_val = unsafe { v8_PersistValue(self.isolate_scope.isolate.inner_isolate, self.inner_val) }; - V8PersistValue { + PersistValue { inner_val, forget: false, } @@ -245,7 +319,7 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { /// Run the value, applicable only if the value is a function or async function. #[must_use] - pub fn call(&self, ctx: &V8ContextScope, args: Option<&[&Self]>) -> Option { + pub fn call(&self, ctx: &ContextScope, args: Option<&[&Self]>) -> Option { let res = match args { Some(args) => { let args = args @@ -269,18 +343,18 @@ impl<'isolate_scope, 'isolate> V8LocalValue<'isolate_scope, 'isolate> { } } -impl V8PersistValue { +impl PersistValue { /// Convert the persisted value back to local value. #[must_use] pub fn as_local<'isolate, 'isolate_scope>( &self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { assert!(!self.inner_val.is_null()); let inner_val = unsafe { v8_PersistedValueToLocal(isolate_scope.isolate.inner_isolate, self.inner_val) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope, } @@ -293,8 +367,8 @@ impl V8PersistValue { pub fn take_local<'isolate, 'isolate_scope>( &mut self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8LocalValue<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalValueGeneric<'isolate_scope, 'isolate> { let val = self.as_local(isolate_scope); unsafe { v8_FreePersistedValue(self.inner_val) } self.forget(); @@ -303,10 +377,10 @@ impl V8PersistValue { } } -unsafe impl Sync for V8PersistValue {} -unsafe impl Send for V8PersistValue {} +unsafe impl Sync for PersistValue {} +unsafe impl Send for PersistValue {} -impl<'isolate_scope, 'isolate> Drop for V8LocalValue<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalValueGeneric<'isolate_scope, 'isolate> { fn drop(&mut self) { if !self.inner_val.is_null() { unsafe { v8_FreeValue(self.inner_val) } @@ -314,7 +388,7 @@ impl<'isolate_scope, 'isolate> Drop for V8LocalValue<'isolate_scope, 'isolate> { } } -impl Drop for V8PersistValue { +impl Drop for PersistValue { fn drop(&mut self) { if self.forget { return; @@ -323,10 +397,10 @@ impl Drop for V8PersistValue { } } -impl<'isolate_scope, 'isolate> TryFrom> for i64 { +impl<'isolate_scope, 'isolate> TryFrom> for i64 { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_long() { return Err("Value is not long"); } @@ -335,10 +409,10 @@ impl<'isolate_scope, 'isolate> TryFrom> f } } -impl<'isolate_scope, 'isolate> TryFrom> for f64 { +impl<'isolate_scope, 'isolate> TryFrom> for f64 { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_number() { return Err("Value is not number"); } @@ -347,10 +421,10 @@ impl<'isolate_scope, 'isolate> TryFrom> f } } -impl<'isolate_scope, 'isolate> TryFrom> for String { +impl<'isolate_scope, 'isolate> TryFrom> for String { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_string() && !val.is_string_object() { return Err("Value is not string"); } @@ -363,10 +437,10 @@ impl<'isolate_scope, 'isolate> TryFrom> f } } -impl<'isolate_scope, 'isolate> TryFrom> for bool { +impl<'isolate_scope, 'isolate> TryFrom> for bool { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_boolean() { return Err("Value is not a boolean"); } @@ -406,15 +480,15 @@ from_iter_impl!(i64); from_iter_impl!(f64); from_iter_impl!(String); from_iter_impl!(bool); -from_iter_impl!(V8LocalArray<'isolate_scope, 'isolate>); -from_iter_impl!(V8LocalArrayBuffer<'isolate_scope, 'isolate>); -from_iter_impl!(V8LocalObject<'isolate_scope, 'isolate>); -from_iter_impl!(V8LocalSet<'isolate_scope, 'isolate>); -from_iter_impl!(V8LocalUtf8<'isolate_scope, 'isolate>); +from_iter_impl!(LocalArray<'isolate_scope, 'isolate>); +from_iter_impl!(LocalArrayBuffer<'isolate_scope, 'isolate>); +from_iter_impl!(LocalObject<'isolate_scope, 'isolate>); +from_iter_impl!(LocalSet<'isolate_scope, 'isolate>); +from_iter_impl!(LocalUtf8<'isolate_scope, 'isolate>); impl<'isolate_scope, 'isolate, 'a> TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for V8LocalValue<'isolate_scope, 'isolate> + for LocalValueGeneric<'isolate_scope, 'isolate> { type Error = &'static str; fn try_from( @@ -427,7 +501,7 @@ impl<'isolate_scope, 'isolate, 'a> impl<'isolate_scope, 'isolate, 'a, T> OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for T where - T: TryFrom, Error = &'static str>, + T: TryFrom, Error = &'static str>, { type Error = &'static str; fn optional_try_from( @@ -443,7 +517,7 @@ where impl<'isolate_scope, 'isolate, 'a> OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for V8LocalValue<'isolate_scope, 'isolate> + for LocalValueGeneric<'isolate_scope, 'isolate> { type Error = &'static str; fn optional_try_from( @@ -456,7 +530,7 @@ impl<'isolate_scope, 'isolate, 'a> impl<'isolate_scope, 'isolate, 'a, T> TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec where - T: TryFrom, Error = &'static str>, + T: TryFrom, Error = &'static str>, { type Error = &'static str; fn try_from( @@ -475,7 +549,7 @@ where impl<'isolate_scope, 'isolate, 'a> TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for Vec> + for Vec> { type Error = &'static str; fn try_from( diff --git a/src/v8/v8_module.rs b/src/v8/types/module.rs similarity index 68% rename from src/v8/v8_module.rs rename to src/v8/types/module.rs index 6279019..f1bbe17 100644 --- a/src/v8/v8_module.rs +++ b/src/v8/types/module.rs @@ -11,47 +11,47 @@ use crate::v8_c_raw::bindings::{ }; use crate::RawIndex; -use crate::v8::isolate::V8Isolate; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_string::V8LocalString; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate::Isolate; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalString; +use crate::v8::types::LocalValueGeneric; use std::os::raw::c_int; use std::ptr; /// JS script object -pub struct V8LocalModule<'isolate_scope, 'isolate> { +pub struct LocalModule<'isolate_scope, 'isolate> { pub(crate) inner_module: *mut v8_local_module, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -pub struct V8PersistedModule { +pub struct PersistedModule { pub(crate) inner_persisted_module: *mut v8_persisted_module, } pub(crate) extern "C" fn load_module< T: for<'isolate, 'isolate_scope, 'c> Fn( - &'isolate V8IsolateScope<'c>, - &'isolate V8ContextScope<'isolate_scope, 'c>, - &'isolate V8LocalString<'isolate_scope, 'c>, + &'isolate IsolateScope<'c>, + &'isolate ContextScope<'isolate_scope, 'c>, + &'isolate LocalString<'isolate_scope, 'c>, i64, - ) -> Option>, + ) -> Option>, >( v8_ctx_ref: *mut v8_context_ref, name: *mut v8_local_string, identity_hash: c_int, ) -> *mut v8_local_module { - let isolate = V8Isolate { + let isolate = Isolate { inner_isolate: unsafe { v8_ContextRefGetIsolate(v8_ctx_ref) }, no_release: true, }; - let isolate_scope = V8IsolateScope::new(&isolate); - let ctx_scope = V8ContextScope { + let isolate_scope = IsolateScope::new(&isolate); + let ctx_scope = ContextScope { inner_ctx_ref: v8_ctx_ref, exit_on_drop: false, isolate_scope: &isolate_scope, }; - let name_obj = V8LocalString { + let name_obj = LocalString { inner_string: name, isolate_scope: &isolate_scope, }; @@ -67,17 +67,17 @@ pub(crate) extern "C" fn load_module< } } -impl<'isolate_scope, 'isolate> V8LocalModule<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { pub fn initialize< T: for<'c, 'd, 'e> Fn( - &'c V8IsolateScope<'e>, - &'c V8ContextScope<'d, 'e>, - &'c V8LocalString<'d, 'e>, + &'c IsolateScope<'e>, + &'c ContextScope<'d, 'e>, + &'c LocalString<'d, 'e>, i64, - ) -> Option>, + ) -> Option>, >( &self, - ctx_scope: &V8ContextScope, + ctx_scope: &ContextScope, load_module_callback: T, ) -> bool { ctx_scope.set_private_data_raw(RawIndex(0), &load_module_callback); @@ -94,13 +94,13 @@ impl<'isolate_scope, 'isolate> V8LocalModule<'isolate_scope, 'isolate> { pub fn evaluate( &self, - ctx_scope: &V8ContextScope, - ) -> Option> { + ctx_scope: &ContextScope, + ) -> Option> { let res = unsafe { v8_EvaluateModule(self.inner_module, ctx_scope.inner_ctx_ref) }; if res.is_null() { None } else { - Some(V8LocalValue { + Some(LocalValueGeneric { inner_val: res, isolate_scope: self.isolate_scope, }) @@ -109,10 +109,10 @@ impl<'isolate_scope, 'isolate> V8LocalModule<'isolate_scope, 'isolate> { /// Convert the module into a generic JS value #[must_use] - pub fn persist(&self, isolate: &V8Isolate) -> V8PersistedModule { + pub fn persist(&self, isolate: &Isolate) -> PersistedModule { let inner_persisted_module = unsafe { v8_ModulePersist(isolate.inner_isolate, self.inner_module) }; - V8PersistedModule { + PersistedModule { inner_persisted_module, } } @@ -122,25 +122,25 @@ impl<'isolate_scope, 'isolate> V8LocalModule<'isolate_scope, 'isolate> { } } -impl V8PersistedModule { +impl PersistedModule { pub fn to_local<'isolate_scope, 'isolate>( &self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8LocalModule<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalModule<'isolate_scope, 'isolate> { let inner_module = unsafe { v8_ModuleToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_module, ) }; - V8LocalModule { + LocalModule { inner_module, isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalModule<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalModule<'isolate_scope, 'isolate> { fn drop(&mut self) { if !self.inner_module.is_null() { unsafe { v8_FreeModule(self.inner_module) } @@ -148,7 +148,7 @@ impl<'isolate_scope, 'isolate> Drop for V8LocalModule<'isolate_scope, 'isolate> } } -impl Drop for V8PersistedModule { +impl Drop for PersistedModule { fn drop(&mut self) { unsafe { v8_FreePersistedModule(self.inner_persisted_module) } } diff --git a/src/v8/v8_native_function.rs b/src/v8/types/native_function.rs similarity index 59% rename from src/v8/v8_native_function.rs rename to src/v8/types/native_function.rs index d1598e1..c3b09f5 100644 --- a/src/v8/v8_native_function.rs +++ b/src/v8/types/native_function.rs @@ -8,28 +8,28 @@ use crate::v8_c_raw::bindings::{ v8_FreeNativeFunction, v8_NativeFunctionToValue, v8_local_native_function, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// Native function object -pub struct V8LocalNativeFunction<'isolate_scope, 'isolate> { +pub struct LocalNativeFunction<'isolate_scope, 'isolate> { pub(crate) inner_func: *mut v8_local_native_function, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalNativeFunction<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalNativeFunction<'isolate_scope, 'isolate> { /// Convert the native function into a JS generic value #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_NativeFunctionToValue(self.inner_func) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalNativeFunction<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalNativeFunction<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeNativeFunction(self.inner_func) } } diff --git a/src/v8/v8_native_function_template.rs b/src/v8/types/native_function_template.rs similarity index 67% rename from src/v8/v8_native_function_template.rs rename to src/v8/types/native_function_template.rs index da348e3..a14f327 100644 --- a/src/v8/v8_native_function_template.rs +++ b/src/v8/types/native_function_template.rs @@ -13,32 +13,32 @@ use crate::v8_c_raw::bindings::{ use std::os::raw::c_void; use std::ptr; -use crate::v8::isolate::V8Isolate; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_native_function::V8LocalNativeFunction; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate::Isolate; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::native_function::LocalNativeFunction; +use crate::v8::types::LocalObject; +use crate::v8::types::LocalValueGeneric; /// Native function template object -pub struct V8LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { +pub struct LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { pub(crate) inner_func: *mut v8_local_native_function_template, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } /// Native function args -pub struct V8LocalNativeFunctionArgs<'isolate_scope, 'isolate> { +pub struct LocalNativeFunctionArgs<'isolate_scope, 'isolate> { pub(crate) inner_arr: *mut v8_local_value_arr, len: usize, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, } pub(crate) extern "C" fn free_pd< T: for<'d, 'c> Fn( - &V8LocalNativeFunctionArgs<'d, 'c>, - &'d V8IsolateScope<'c>, - &V8ContextScope<'d, 'c>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'c>, + &'d IsolateScope<'c>, + &ContextScope<'d, 'c>, + ) -> Option>, >( pd: *mut c_void, ) { @@ -49,10 +49,10 @@ pub(crate) extern "C" fn free_pd< pub(crate) extern "C" fn native_basic_function< T: for<'d, 'c> Fn( - &V8LocalNativeFunctionArgs<'d, 'c>, - &'d V8IsolateScope<'c>, - &V8ContextScope<'d, 'c>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'c>, + &'d IsolateScope<'c>, + &ContextScope<'d, 'c>, + ) -> Option>, >( args: *mut v8_local_value_arr, len: usize, @@ -61,21 +61,21 @@ pub(crate) extern "C" fn native_basic_function< let func = unsafe { &*(pd.cast::()) }; let inner_isolate = unsafe { v8_GetCurrentIsolate(args) }; - let isolate = V8Isolate { + let isolate = Isolate { inner_isolate, no_release: true, }; - let isolate_scope = V8IsolateScope::new(&isolate); + let isolate_scope = IsolateScope::new(&isolate); let inner_ctx_ref = unsafe { v8_GetCurrentCtxRef(inner_isolate) }; - let ctx_scope = V8ContextScope { + let ctx_scope = ContextScope { inner_ctx_ref, exit_on_drop: false, isolate_scope: &isolate_scope, }; - let args = V8LocalNativeFunctionArgs { + let args = LocalNativeFunctionArgs { inner_arr: args, len, isolate_scope: &isolate_scope, @@ -93,29 +93,29 @@ pub(crate) extern "C" fn native_basic_function< } } -impl<'isolate_scope, 'isolate> V8LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { pub fn to_function( &self, - ctx_scope: &V8ContextScope, - ) -> V8LocalNativeFunction<'isolate_scope, 'isolate> { + ctx_scope: &ContextScope, + ) -> LocalNativeFunction<'isolate_scope, 'isolate> { let inner_func = unsafe { v8_NativeFunctionTemplateToFunction(ctx_scope.inner_ctx_ref, self.inner_func) }; - V8LocalNativeFunction { + LocalNativeFunction { inner_func, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> V8LocalNativeFunctionArgs<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalNativeFunctionArgs<'isolate_scope, 'isolate> { /// Return the i-th argument from the native function args /// # Panics #[must_use] - pub fn get(&self, i: usize) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn get(&self, i: usize) -> LocalValueGeneric<'isolate_scope, 'isolate> { assert!(i <= self.len); let val = unsafe { v8_ArgsGet(self.inner_arr, i) }; - V8LocalValue { + LocalValueGeneric { inner_val: val, isolate_scope: self.isolate_scope, } @@ -135,9 +135,9 @@ impl<'isolate_scope, 'isolate> V8LocalNativeFunctionArgs<'isolate_scope, 'isolat /// Checks if the list of args is empty #[must_use] - pub fn get_self(&self) -> V8LocalObject<'isolate_scope, 'isolate> { + pub fn get_self(&self) -> LocalObject<'isolate_scope, 'isolate> { let val = unsafe { v8_ArgsGetSelf(self.inner_arr) }; - V8LocalObject { + LocalObject { inner_obj: val, isolate_scope: self.isolate_scope, } @@ -154,14 +154,14 @@ impl<'isolate_scope, 'isolate> V8LocalNativeFunctionArgs<'isolate_scope, 'isolat } pub struct V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { - args: &'a V8LocalNativeFunctionArgs<'isolate_scope, 'isolate>, + args: &'a LocalNativeFunctionArgs<'isolate_scope, 'isolate>, index: usize, } impl<'isolate_scope, 'isolate, 'a> Iterator for V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { - type Item = V8LocalValue<'isolate_scope, 'isolate>; + type Item = LocalValueGeneric<'isolate_scope, 'isolate>; fn next(&mut self) -> Option { if self.index >= self.args.len() { return None; @@ -172,7 +172,7 @@ impl<'isolate_scope, 'isolate, 'a> Iterator } } -impl<'isolate_scope, 'isolate> Drop for V8LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeNativeFunctionTemplate(self.inner_func) } } diff --git a/src/v8/v8_object.rs b/src/v8/types/object.rs similarity index 63% rename from src/v8/v8_object.rs rename to src/v8/types/object.rs index eabc86f..f477e59 100644 --- a/src/v8/v8_object.rs +++ b/src/v8/types/object.rs @@ -10,32 +10,32 @@ use crate::v8_c_raw::bindings::{ v8_ValueGetPropertyNames, v8_local_object, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_array::V8LocalArray; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_native_function_template::V8LocalNativeFunctionArgs; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::native_function_template::LocalNativeFunctionArgs; +use crate::v8::types::LocalArray; +use crate::v8::types::LocalValueGeneric; /// JS object -pub struct V8LocalObject<'isolate_scope, 'isolate> { +pub struct LocalObject<'isolate_scope, 'isolate> { pub(crate) inner_obj: *mut v8_local_object, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { /// Return the value of a given key #[must_use] pub fn get( &self, - ctx_scope: &V8ContextScope, - key: &V8LocalValue, - ) -> Option> { + ctx_scope: &ContextScope, + key: &LocalValueGeneric, + ) -> Option> { let inner_val = unsafe { v8_ObjectGet(ctx_scope.inner_ctx_ref, self.inner_obj, key.inner_val) }; if inner_val.is_null() { None } else { - Some(V8LocalValue { + Some(LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, }) @@ -46,14 +46,14 @@ impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { #[must_use] pub fn get_str_field( &self, - ctx_scope: &V8ContextScope, + ctx_scope: &ContextScope, key: &str, - ) -> Option> { + ) -> Option> { let key = self.isolate_scope.new_string(key); self.get(ctx_scope, &key.to_value()) } - pub fn set(&self, ctx_scope: &V8ContextScope, key: &V8LocalValue, val: &V8LocalValue) { + pub fn set(&self, ctx_scope: &ContextScope, key: &LocalValueGeneric, val: &LocalValueGeneric) { unsafe { v8_ObjectSet( ctx_scope.inner_ctx_ref, @@ -66,13 +66,13 @@ impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { pub fn set_native_function< T: for<'d, 'e> Fn( - &V8LocalNativeFunctionArgs<'d, 'e>, - &'d V8IsolateScope<'e>, - &V8ContextScope<'d, 'e>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'e>, + &'d IsolateScope<'e>, + &ContextScope<'d, 'e>, + ) -> Option>, >( &self, - ctx_scope: &V8ContextScope, + ctx_scope: &ContextScope, key: &str, func: T, ) { @@ -88,14 +88,14 @@ impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { }; } - pub fn set_internal_field(&self, index: usize, val: &V8LocalValue) { + pub fn set_internal_field(&self, index: usize, val: &LocalValueGeneric) { unsafe { v8_ObjectSetInternalField(self.inner_obj, index, val.inner_val) }; } #[must_use] - pub fn get_internal_field(&self, index: usize) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn get_internal_field(&self, index: usize) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ObjectGetInternalField(self.inner_obj, index) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } @@ -108,15 +108,15 @@ impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { /// Convert the object into a generic JS value #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ObjectToValue(self.inner_obj) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } - pub fn freeze(&self, ctx_scope: &V8ContextScope) { + pub fn freeze(&self, ctx_scope: &ContextScope) { unsafe { v8_ObjectFreeze(ctx_scope.inner_ctx_ref, self.inner_obj) }; } @@ -124,29 +124,29 @@ impl<'isolate_scope, 'isolate> V8LocalObject<'isolate_scope, 'isolate> { #[must_use] pub fn get_property_names( &self, - ctx_scope: &V8ContextScope, - ) -> V8LocalArray<'isolate_scope, 'isolate> { + ctx_scope: &ContextScope, + ) -> LocalArray<'isolate_scope, 'isolate> { let inner_array = unsafe { v8_ValueGetPropertyNames(ctx_scope.inner_ctx_ref, self.inner_obj) }; - V8LocalArray { + LocalArray { inner_array, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalObject<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalObject<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeObject(self.inner_obj) } } } -impl<'isolate_scope, 'isolate> TryFrom> - for V8LocalObject<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> TryFrom> + for LocalObject<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_object() { return Err("Value is not an object"); } diff --git a/src/v8/v8_object_template.rs b/src/v8/types/object_template.rs similarity index 71% rename from src/v8/v8_object_template.rs rename to src/v8/types/object_template.rs index 3594699..6a71403 100644 --- a/src/v8/v8_object_template.rs +++ b/src/v8/types/object_template.rs @@ -11,38 +11,34 @@ use crate::v8_c_raw::bindings::{ v8_local_object_template, v8_persisted_object_template, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_native_function_template::{ - V8LocalNativeFunctionArgs, V8LocalNativeFunctionTemplate, +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::native_function_template::{ + LocalNativeFunctionArgs, LocalNativeFunctionTemplate, }; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_string::V8LocalString; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::types::object::LocalObject; +use crate::v8::types::string::LocalString; +use crate::v8::types::LocalValueGeneric; /// JS object template -pub struct V8LocalObjectTemplate<'isolate_scope, 'isolate> { +pub struct LocalObjectTemplate<'isolate_scope, 'isolate> { pub(crate) inner_obj: *mut v8_local_object_template, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalObjectTemplate<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { /// Set a native function to the object template as a given key - pub fn set_native_function( - &mut self, - name: &V8LocalString, - func: &V8LocalNativeFunctionTemplate, - ) { + pub fn set_native_function(&mut self, name: &LocalString, func: &LocalNativeFunctionTemplate) { unsafe { v8_ObjectTemplateSetFunction(self.inner_obj, name.inner_string, func.inner_func) }; } /// Same as `set_native_function` but gets the key as &str and the native function as closure. pub fn add_native_function< T: for<'d, 'e> Fn( - &V8LocalNativeFunctionArgs<'d, 'e>, - &'d V8IsolateScope<'e>, - &V8ContextScope<'d, 'e>, - ) -> Option>, + &LocalNativeFunctionArgs<'d, 'e>, + &'d IsolateScope<'e>, + &ContextScope<'d, 'e>, + ) -> Option>, >( &mut self, name: &str, @@ -54,7 +50,7 @@ impl<'isolate_scope, 'isolate> V8LocalObjectTemplate<'isolate_scope, 'isolate> { } /// Set the given object to the object template on a given key - pub fn set_object(&mut self, name: &V8LocalString, obj: &Self) { + pub fn set_object(&mut self, name: &LocalString, obj: &Self) { unsafe { v8_ObjectTemplateSetObject(self.inner_obj, name.inner_string, obj.inner_obj) }; } @@ -69,25 +65,22 @@ impl<'isolate_scope, 'isolate> V8LocalObjectTemplate<'isolate_scope, 'isolate> { } /// Set a generic JS value into the object template as a given key - pub fn set_value(&mut self, name: &V8LocalString, obj: &V8LocalValue) { + pub fn set_value(&mut self, name: &LocalString, obj: &LocalValueGeneric) { unsafe { v8_ObjectTemplateSetValue(self.inner_obj, name.inner_string, obj.inner_val) }; } /// Same as `set_value` but gets the key as &str - pub fn add_value(&mut self, name: &str, obj: &V8LocalValue) { + pub fn add_value(&mut self, name: &str, obj: &LocalValueGeneric) { let val_name = self.isolate_scope.new_string(name); self.set_value(&val_name, obj); } /// Convert the object template into a generic JS value #[must_use] - pub fn new_instance( - &self, - ctx_scope: &V8ContextScope, - ) -> V8LocalObject<'isolate_scope, 'isolate> { + pub fn new_instance(&self, ctx_scope: &ContextScope) -> LocalObject<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_ObjectTemplateNewInstance(ctx_scope.inner_ctx_ref, self.inner_obj) }; - V8LocalObject { + LocalObject { inner_obj, isolate_scope: self.isolate_scope, } @@ -103,7 +96,7 @@ impl<'isolate_scope, 'isolate> V8LocalObjectTemplate<'isolate_scope, 'isolate> { } } -impl<'isolate_scope, 'isolate> Drop for V8LocalObjectTemplate<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalObjectTemplate<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeObjectTemplate(self.inner_obj) } } @@ -116,15 +109,15 @@ pub struct V8PersistedObjectTemplate { impl V8PersistedObjectTemplate { pub fn to_local<'isolate_scope, 'isolate>( &self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8LocalObjectTemplate<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalObjectTemplate<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_PersistedObjectTemplateToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_obj_template, ) }; - V8LocalObjectTemplate { + LocalObjectTemplate { inner_obj, isolate_scope, } diff --git a/src/v8/v8_promise.rs b/src/v8/types/promise.rs similarity index 67% rename from src/v8/v8_promise.rs rename to src/v8/types/promise.rs index c19306a..4b3fc2c 100644 --- a/src/v8/v8_promise.rs +++ b/src/v8/types/promise.rs @@ -10,31 +10,31 @@ use crate::v8_c_raw::bindings::{ v8_PromiseState_v8_PromiseState_Rejected, v8_PromiseThen, v8_PromiseToValue, v8_local_promise, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_native_function::V8LocalNativeFunction; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::native_function::LocalNativeFunction; +use crate::v8::types::LocalValueGeneric; -pub struct V8LocalPromise<'isolate_scope, 'isolate> { +pub struct LocalPromise<'isolate_scope, 'isolate> { pub(crate) inner_promise: *mut v8_local_promise, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } #[derive(Debug, PartialEq)] -pub enum V8PromiseState { +pub enum PromiseState { Fulfilled, Rejected, Pending, Unknown, } -impl<'isolate_scope, 'isolate> V8LocalPromise<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { /// Set resolve and reject callbacks pub fn then( &self, - ctx: &V8ContextScope, - resolve: &V8LocalNativeFunction, - reject: &V8LocalNativeFunction, + ctx: &ContextScope, + resolve: &LocalNativeFunction, + reject: &LocalNativeFunction, ) { unsafe { v8_PromiseThen( @@ -49,14 +49,14 @@ impl<'isolate_scope, 'isolate> V8LocalPromise<'isolate_scope, 'isolate> { /// Return the state on the promise object /// # Panics #[must_use] - pub fn state(&self) -> V8PromiseState { + pub fn state(&self) -> PromiseState { let inner_state = unsafe { v8_PromiseGetState(self.inner_promise) }; if inner_state == v8_PromiseState_v8_PromiseState_Fulfilled { - V8PromiseState::Fulfilled + PromiseState::Fulfilled } else if inner_state == v8_PromiseState_v8_PromiseState_Rejected { - V8PromiseState::Rejected + PromiseState::Rejected } else if inner_state == v8_PromiseState_v8_PromiseState_Pending { - V8PromiseState::Pending + PromiseState::Pending } else { panic!("bad promise state"); } @@ -65,9 +65,9 @@ impl<'isolate_scope, 'isolate> V8LocalPromise<'isolate_scope, 'isolate> { /// Return the result of the promise object. /// Only applicable if the promise object was resolved/rejected. #[must_use] - pub fn get_result(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn get_result(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_PromiseGetResult(self.inner_promise) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } @@ -75,16 +75,16 @@ impl<'isolate_scope, 'isolate> V8LocalPromise<'isolate_scope, 'isolate> { /// Convert the promise object into a generic JS value #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_PromiseToValue(self.inner_promise) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalPromise<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalPromise<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreePromise(self.inner_promise) } } diff --git a/src/v8/v8_resolver.rs b/src/v8/types/resolver.rs similarity index 62% rename from src/v8/v8_resolver.rs rename to src/v8/types/resolver.rs index 0e74e3e..6ecebfa 100644 --- a/src/v8/v8_resolver.rs +++ b/src/v8/types/resolver.rs @@ -9,50 +9,50 @@ use crate::v8_c_raw::bindings::{ v8_ResolverToValue, v8_local_resolver, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_promise::V8LocalPromise; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::promise::LocalPromise; +use crate::v8::types::LocalValueGeneric; /// JS resolver object -pub struct V8LocalResolver<'isolate_scope, 'isolate> { +pub struct LocalResolver<'isolate_scope, 'isolate> { pub(crate) inner_resolver: *mut v8_local_resolver, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalResolver<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalResolver<'isolate_scope, 'isolate> { /// Get the promise object assosiated with this resolver. #[must_use] - pub fn get_promise(&self) -> V8LocalPromise<'isolate_scope, 'isolate> { + pub fn get_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { let inner_promise = unsafe { v8_ResolverGetPromise(self.inner_resolver) }; - V8LocalPromise { + LocalPromise { inner_promise, isolate_scope: self.isolate_scope, } } /// Resolve the resolver with the given JS value. - pub fn resolve(&self, ctx_scope: &V8ContextScope, val: &V8LocalValue) { + pub fn resolve(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { unsafe { v8_ResolverResolve(ctx_scope.inner_ctx_ref, self.inner_resolver, val.inner_val) }; } /// Reject the resolver with the given JS value. - pub fn reject(&self, ctx_scope: &V8ContextScope, val: &V8LocalValue) { + pub fn reject(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { unsafe { v8_ResolverReject(ctx_scope.inner_ctx_ref, self.inner_resolver, val.inner_val) }; } /// Convert the resolver into a generic JS value. #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ResolverToValue(self.inner_resolver) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalResolver<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalResolver<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeResolver(self.inner_resolver) } } diff --git a/src/v8/v8_script.rs b/src/v8/types/script.rs similarity index 61% rename from src/v8/v8_script.rs rename to src/v8/types/script.rs index 88f4199..5cf643d 100644 --- a/src/v8/v8_script.rs +++ b/src/v8/types/script.rs @@ -9,73 +9,73 @@ use crate::v8_c_raw::bindings::{ v8_local_script, v8_persisted_script, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// JS script object -pub struct V8LocalScript<'isolate_scope, 'isolate> { +pub struct LocalScript<'isolate_scope, 'isolate> { pub(crate) inner_script: *mut v8_local_script, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -pub struct V8PersistedScript { +pub struct PersistedScript { pub(crate) inner_persisted_script: *mut v8_persisted_script, } -impl<'isolate_scope, 'isolate> V8LocalScript<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalScript<'isolate_scope, 'isolate> { /// Run the script #[must_use] - pub fn run(&self, ctx: &V8ContextScope) -> Option> { + pub fn run(&self, ctx: &ContextScope) -> Option> { let inner_val = unsafe { v8_Run(ctx.inner_ctx_ref, self.inner_script) }; if inner_val.is_null() { None } else { - Some(V8LocalValue { + Some(LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, }) } } - pub fn persist(&self) -> V8PersistedScript { + pub fn persist(&self) -> PersistedScript { let inner_persisted_script = unsafe { v8_ScriptPersist(self.isolate_scope.isolate.inner_isolate, self.inner_script) }; - V8PersistedScript { + PersistedScript { inner_persisted_script, } } } -impl V8PersistedScript { +impl PersistedScript { pub fn to_local<'isolate_scope, 'isolate>( &self, - isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, - ) -> V8LocalScript<'isolate_scope, 'isolate> { + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalScript<'isolate_scope, 'isolate> { let inner_script = unsafe { v8_PersistedScriptToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_script, ) }; - V8LocalScript { + LocalScript { inner_script, isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalScript<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalScript<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeScript(self.inner_script) } } } -unsafe impl Sync for V8PersistedScript {} -unsafe impl Send for V8PersistedScript {} +unsafe impl Sync for PersistedScript {} +unsafe impl Send for PersistedScript {} -impl Drop for V8PersistedScript { +impl Drop for PersistedScript { fn drop(&mut self) { unsafe { v8_FreePersistedScript(self.inner_persisted_script) } } diff --git a/src/v8/v8_set.rs b/src/v8/types/set.rs similarity index 52% rename from src/v8/v8_set.rs rename to src/v8/types/set.rs index 73b531a..484f954 100644 --- a/src/v8/v8_set.rs +++ b/src/v8/types/set.rs @@ -6,44 +6,44 @@ use crate::v8_c_raw::bindings::{v8_FreeSet, v8_SetAdd, v8_SetToValue, v8_local_set}; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// JS object -pub struct V8LocalSet<'isolate_scope, 'isolate> { +pub struct LocalSet<'isolate_scope, 'isolate> { pub(crate) inner_set: *mut v8_local_set, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalSet<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalSet<'isolate_scope, 'isolate> { /// Convert the object into a generic JS value #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_SetToValue(self.inner_set) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } } - pub fn add(&self, ctx_scope: &V8ContextScope, val: &V8LocalValue) { + pub fn add(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { unsafe { v8_SetAdd(ctx_scope.inner_ctx_ref, self.inner_set, val.inner_val) }; } } -impl<'isolate_scope, 'isolate> Drop for V8LocalSet<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalSet<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeSet(self.inner_set) } } } -impl<'isolate_scope, 'isolate> TryFrom> - for V8LocalSet<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> TryFrom> + for LocalSet<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_set() { return Err("Value is not a set"); } diff --git a/src/v8/v8_string.rs b/src/v8/types/string.rs similarity index 63% rename from src/v8/v8_string.rs rename to src/v8/types/string.rs index 902e75d..50cdf57 100644 --- a/src/v8/v8_string.rs +++ b/src/v8/types/string.rs @@ -8,22 +8,22 @@ use crate::v8_c_raw::bindings::{ v8_FreeString, v8_StringToStringObject, v8_StringToValue, v8_local_string, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_object::V8LocalObject; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::object::LocalObject; +use crate::v8::types::LocalValueGeneric; /// JS string object -pub struct V8LocalString<'isolate_scope, 'isolate> { +pub struct LocalString<'isolate_scope, 'isolate> { pub(crate) inner_string: *mut v8_local_string, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalString<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalString<'isolate_scope, 'isolate> { /// Convert the string object into a generic JS object. #[must_use] - pub fn to_value(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_StringToValue(self.inner_string) }; - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } @@ -31,18 +31,18 @@ impl<'isolate_scope, 'isolate> V8LocalString<'isolate_scope, 'isolate> { /// Same as writing 'new String(...)'. #[must_use] - pub fn to_string_object(&self) -> V8LocalObject<'isolate_scope, 'isolate> { + pub fn to_string_object(&self) -> LocalObject<'isolate_scope, 'isolate> { let inner_obj = unsafe { v8_StringToStringObject(self.isolate_scope.isolate.inner_isolate, self.inner_string) }; - V8LocalObject { + LocalObject { inner_obj, isolate_scope: self.isolate_scope, } } } -impl<'isolate_scope, 'isolate> Drop for V8LocalString<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalString<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeString(self.inner_string) } } diff --git a/src/v8/try_catch.rs b/src/v8/types/try_catch.rs similarity index 69% rename from src/v8/try_catch.rs rename to src/v8/types/try_catch.rs index 45b2c76..3bab275 100644 --- a/src/v8/try_catch.rs +++ b/src/v8/types/try_catch.rs @@ -9,24 +9,24 @@ use crate::v8_c_raw::bindings::{ v8_trycatch, }; -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_context_scope::V8ContextScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::context_scope::ContextScope; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; /// An object that responsible to catch any exception which raised /// during the JS code invocation. -pub struct V8TryCatch<'isolate_scope, 'isolate> { +pub struct TryCatch<'isolate_scope, 'isolate> { pub(crate) inner_trycatch: *mut v8_trycatch, - pub(crate) isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8TryCatch<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> TryCatch<'isolate_scope, 'isolate> { /// Return the exception that was raise during the JS code invocation. #[must_use] - pub fn get_exception(&self) -> V8LocalValue<'isolate_scope, 'isolate> { + pub fn get_exception(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_TryCatchGetException(self.inner_trycatch) }; assert!(!inner_val.is_null()); - V8LocalValue { + LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, } @@ -36,14 +36,14 @@ impl<'isolate_scope, 'isolate> V8TryCatch<'isolate_scope, 'isolate> { #[must_use] pub fn get_trace( &self, - ctx_scope: &V8ContextScope, - ) -> Option> { + ctx_scope: &ContextScope, + ) -> Option> { let inner_val = unsafe { v8_TryCatchGetTrace(self.inner_trycatch, ctx_scope.inner_ctx_ref) }; if inner_val.is_null() { return None; } - Some(V8LocalValue { + Some(LocalValueGeneric { inner_val, isolate_scope: self.isolate_scope, }) @@ -56,7 +56,7 @@ impl<'isolate_scope, 'isolate> V8TryCatch<'isolate_scope, 'isolate> { } } -impl<'isolate_scope, 'isolate> Drop for V8TryCatch<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for TryCatch<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeTryCatch(self.inner_trycatch) } } diff --git a/src/v8/v8_unlocker.rs b/src/v8/types/unlocker.rs similarity index 60% rename from src/v8/v8_unlocker.rs rename to src/v8/types/unlocker.rs index fb4af9c..08e2545 100644 --- a/src/v8/v8_unlocker.rs +++ b/src/v8/types/unlocker.rs @@ -4,15 +4,15 @@ * the Server Side Public License v1 (SSPLv1). */ -use crate::v8::isolate_scope::V8IsolateScope; +use crate::v8::isolate_scope::IsolateScope; use crate::v8_c_raw::bindings::{v8_FreeUnlocker, v8_unlocker}; -pub struct V8Unlocker<'isolate_scope, 'isolate> { +pub struct Unlocker<'isolate_scope, 'isolate> { pub(crate) inner_unlocker: *mut v8_unlocker, - pub(crate) _isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) _isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> Drop for V8Unlocker<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for Unlocker<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeUnlocker(self.inner_unlocker) }; } diff --git a/src/v8/v8_utf8.rs b/src/v8/types/utf8.rs similarity index 63% rename from src/v8/v8_utf8.rs rename to src/v8/types/utf8.rs index 07d79b3..38577d0 100644 --- a/src/v8/v8_utf8.rs +++ b/src/v8/types/utf8.rs @@ -4,20 +4,20 @@ * the Server Side Public License v1 (SSPLv1). */ -use crate::v8::isolate_scope::V8IsolateScope; -use crate::v8::v8_value::V8LocalValue; +use crate::v8::isolate_scope::IsolateScope; +use crate::v8::types::LocalValueGeneric; use crate::v8_c_raw::bindings::{v8_FreeUtf8, v8_Utf8PtrLen, v8_utf8_value}; use std::slice; use std::str; /// JS utf8 object -pub struct V8LocalUtf8<'isolate_scope, 'isolate> { +pub struct LocalUtf8<'isolate_scope, 'isolate> { pub(crate) inner_val: *mut v8_utf8_value, - pub(crate) _isolate_scope: &'isolate_scope V8IsolateScope<'isolate>, + pub(crate) _isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -impl<'isolate_scope, 'isolate> V8LocalUtf8<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalUtf8<'isolate_scope, 'isolate> { /// Get &str from the utf8 object /// # Panics #[must_use] @@ -29,18 +29,18 @@ impl<'isolate_scope, 'isolate> V8LocalUtf8<'isolate_scope, 'isolate> { } } -impl<'isolate_scope, 'isolate> Drop for V8LocalUtf8<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalUtf8<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeUtf8(self.inner_val) } } } -impl<'isolate_scope, 'isolate> TryFrom> - for V8LocalUtf8<'isolate_scope, 'isolate> +impl<'isolate_scope, 'isolate> TryFrom> + for LocalUtf8<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { if !val.is_string() && !val.is_string_object() { return Err("Value is not string"); } diff --git a/v8-rs-derive/src/lib.rs b/v8-rs-derive/src/lib.rs index f968862..9ab1d7f 100644 --- a/v8-rs-derive/src/lib.rs +++ b/v8-rs-derive/src/lib.rs @@ -209,7 +209,7 @@ pub fn new_native_function(item: TokenStream) -> TokenStream { fn __create_closure__(f: F) -> F where - F: for<'i_s, 'i> Fn(&'i_s v8_rs::v8::isolate_scope::V8IsolateScope<'i>, &v8_rs::v8::v8_context_scope::V8ContextScope<'i_s, 'i>, #(#types_for_closure, )*) -> Result>, E>, + F: for<'i_s, 'i> Fn(&'i_s v8_rs::v8::isolate_scope::IsolateScope<'i>, &v8_rs::v8::context_scope::ContextScope<'i_s, 'i>, #(#types_for_closure, )*) -> Result>, E>, E: std::fmt::Display, { f From 0549ab945fed52f0774b7c267beb13bc400d9a62 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Fri, 21 Apr 2023 10:18:05 +0200 Subject: [PATCH 2/5] Move to the strict types. --- Cargo.toml | 2 +- src/lib.rs | 403 +++++++----- src/v8/context.rs | 2 +- src/v8/context_scope.rs | 100 ++- src/v8/isolate.rs | 1 + src/v8/isolate_scope.rs | 233 ++----- src/v8/types/any.rs | 427 +++++++++++++ src/v8/types/array.rs | 88 ++- src/v8/types/array_buffer.rs | 78 ++- src/v8/types/external_data.rs | 68 +- src/v8/types/mod.rs | 780 +++++++++++++---------- src/v8/types/module.rs | 59 +- src/v8/types/native_function.rs | 45 +- src/v8/types/native_function_template.rs | 82 ++- src/v8/types/object.rs | 155 +++-- src/v8/types/object_template.rs | 83 ++- src/v8/types/persistent.rs | 92 +++ src/v8/types/promise.rs | 73 ++- src/v8/types/resolver.rs | 55 +- src/v8/types/script.rs | 39 +- src/v8/types/set.rs | 68 +- src/v8/types/string.rs | 89 ++- src/v8/types/try_catch.rs | 60 +- src/v8/types/unlocker.rs | 24 +- src/v8/types/utf8.rs | 76 ++- v8-rs-derive/Cargo.toml | 6 +- v8-rs-derive/src/lib.rs | 2 +- 27 files changed, 2074 insertions(+), 1116 deletions(-) create mode 100644 src/v8/types/any.rs create mode 100644 src/v8/types/persistent.rs diff --git a/Cargo.toml b/Cargo.toml index f46ef74..37881d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "Redis Source Available License 2.0 (RSALv2) or the Server Side Public [dependencies] [build-dependencies] -bindgen = "0.59.2" +bindgen = "0.59" vergen = { version = "8", features = ["git", "gitcl"] } lazy_static = "1" diff --git a/src/lib.rs b/src/lib.rs index 8bff952..896b72c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,6 +56,14 @@ impl From for RawIndex { #[cfg(test)] mod json_path_tests { use crate as v8_rs; + use crate::v8::types::any::LocalValueAny; + use crate::v8::types::native_function::LocalNativeFunction; + use crate::v8::types::native_function_template::LocalNativeFunctionTemplate; + use crate::v8::types::object_template::LocalObjectTemplate; + use crate::v8::types::promise::LocalPromise; + use crate::v8::types::try_catch::TryCatch; + use crate::v8::types::utf8::LocalUtf8; + use crate::v8::types::Value; use crate::v8::{ context_scope, isolate, isolate_scope, types, types::array, types::array_buffer, types::native_function_template, types::object, types::set, types::utf8, v8_init, @@ -91,7 +99,7 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let _s = isolate_scope.new_string("test"); + let _s = isolate_scope.create_string("test"); } #[test] @@ -99,7 +107,7 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let _o = isolate_scope.new_object_template(); + let _o = isolate_scope.create_object_template(); } #[test] @@ -107,7 +115,7 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let _o = isolate_scope.new_native_function_template(|_args, _isolate, _ctx_scope| { + let _o = isolate_scope.create_native_function_template(|_args, _isolate, _ctx_scope| { println!("test"); None }); @@ -118,18 +126,21 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let native = - isolate_scope.new_native_function_template(|args, _isolate_scope, _ctx_scope| { + let native = isolate_scope + .create_native_function_template(|args, _isolate_scope, _ctx_scope| { let v = args.get(0); - let s = v.to_utf8().unwrap(); + let s: LocalUtf8 = v.try_into().unwrap(); assert_eq!(s.as_str(), "2"); None - }); - let native_funciton_name = isolate_scope.new_string("foo"); - let mut globals = isolate_scope.new_object_template(); + }) + .try_into() + .unwrap(); + let native_funciton_name = isolate_scope.create_string("foo").try_into().unwrap(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.set_native_function(&native_funciton_name, &native); - let code_str = isolate_scope.new_string("foo(2)"); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_str = isolate_scope.create_string("foo(2)").try_into().unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); script.run(&ctx_scope).unwrap(); @@ -141,29 +152,38 @@ mod json_path_tests { let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let foo1 = isolate_scope.new_native_function_template(|args, _isolate, ctx_scope| { - let v = args.get(0); - let _res = v.call(ctx_scope, None); - None - }); - let foo1_name = isolate_scope.new_string("foo1"); + let foo1 = isolate_scope + .create_native_function_template(|args, _isolate, ctx_scope| { + let v: LocalValueAny = args.get(0).try_into().unwrap(); + let _res = v.call(ctx_scope, None); + None + }) + .try_into() + .unwrap(); + let foo1_name = isolate_scope.create_string("foo1").try_into().unwrap(); - let foo2 = - isolate_scope.new_native_function_template(|args, _isolate_scope, _ctx_scope| { + let foo2 = isolate_scope + .create_native_function_template(|args, _isolate_scope, _ctx_scope| { let v = args.get(0); - let s = v.to_utf8().unwrap(); + let s: LocalUtf8 = v.try_into().unwrap(); assert_eq!(s.as_str(), "2"); None - }); - let foo2_name = isolate_scope.new_string("foo2"); + }) + .try_into() + .unwrap(); + let foo2_name = isolate_scope.create_string("foo2").try_into().unwrap(); - let mut globals = isolate_scope.new_object_template(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.set_native_function(&foo1_name, &foo1); globals.set_native_function(&foo2_name, &foo2); - let code_str = isolate_scope.new_string("foo1(()=>{foo2(2)})"); + let code_str = isolate_scope + .create_string("foo1(()=>{foo2(2)})") + .try_into() + .unwrap(); let i_scope = isolate.enter(); - let ctx = i_scope.new_context(Some(&globals)); + let ctx = i_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); script.run(&ctx_scope).unwrap(); @@ -175,29 +195,38 @@ mod json_path_tests { let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let foo1 = isolate_scope.new_native_function_template(|args, isolate_scope, ctx_scope| { - let foo = isolate_scope.new_string("foo"); - let v = args.get(0); - let _res = v.call(ctx_scope, Some(&[&foo.to_value()])); - None - }); - let foo1_name = isolate_scope.new_string("foo1"); + let foo1 = isolate_scope + .create_native_function_template(|args, isolate_scope, ctx_scope| { + let foo: LocalValueAny = isolate_scope.create_string("foo").try_into().unwrap(); + let v: LocalValueAny = args.get(0).try_into().unwrap(); + let _res = v.call(ctx_scope, Some(&[&foo.into()])); + None + }) + .try_into() + .unwrap(); + let foo1_name = isolate_scope.create_string("foo1").try_into().unwrap(); - let foo2 = - isolate_scope.new_native_function_template(|args, _isolate_scope, _ctx_scope| { + let foo2 = isolate_scope + .create_native_function_template(|args, _isolate_scope, _ctx_scope| { let v = args.get(0); - let s = v.to_utf8().unwrap(); + let s: LocalUtf8 = v.try_into().unwrap(); assert_eq!(s.as_str(), "foo"); None - }); - let foo2_name = isolate_scope.new_string("foo2"); + }) + .try_into() + .unwrap(); + let foo2_name = isolate_scope.create_string("foo2").try_into().unwrap(); - let mut globals = isolate_scope.new_object_template(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.set_native_function(&foo1_name, &foo1); globals.set_native_function(&foo2_name, &foo2); - let code_str = isolate_scope.new_string("foo1((a)=>{foo2(a)})"); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_str = isolate_scope + .create_string("foo1((a)=>{foo2(a)})") + .try_into() + .unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); script.run(&ctx_scope).unwrap(); @@ -209,21 +238,25 @@ mod json_path_tests { let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let native = isolate_scope.new_native_function_template(|_args, isolate, _ctx_scope| { - isolate.raise_exception_str("this is an error"); - None - }); - let native_funciton_name = isolate_scope.new_string("foo"); - let mut globals = isolate_scope.new_object_template(); + let native = isolate_scope + .create_native_function_template(|_args, isolate, _ctx_scope| { + isolate.raise_exception_str("this is an error"); + None + }) + .try_into() + .unwrap(); + let native_funciton_name = isolate_scope.create_string("foo").try_into().unwrap(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.set_native_function(&native_funciton_name, &native); - let code_str = isolate_scope.new_string("foo(2)"); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_str = isolate_scope.create_string("foo(2)").try_into().unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); - let trycatch = isolate_scope.new_try_catch(); + let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); assert!(script.run(&ctx_scope).is_none()); let exception = trycatch.get_exception(); - let exception_msg = exception.to_utf8().unwrap(); + let exception_msg = exception.into_utf8().unwrap(); assert_eq!(exception_msg.as_str(), "this is an error"); } @@ -233,17 +266,19 @@ mod json_path_tests { let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); let code_str = isolate_scope - .new_string("function foo(){throw new Error('this is an error!');};foo();"); - let ctx = isolate_scope.new_context(None); + .create_string("function foo(){throw new Error('this is an error!');};foo();") + .try_into() + .unwrap(); + let ctx = isolate_scope.create_context(None); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); - let trycatch = isolate_scope.new_try_catch(); + let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); assert!(script.run(&ctx_scope).is_none()); let exception = trycatch.get_exception(); - let exception_msg = exception.to_utf8().unwrap(); + let exception_msg = exception.into_utf8().unwrap(); assert_eq!(exception_msg.as_str(), "Error: this is an error!"); let trace = trycatch.get_trace(&ctx_scope); - let trace_str = trace.unwrap().to_utf8().unwrap(); + let trace_str = trace.unwrap().into_utf8().unwrap(); assert!(trace_str.as_str().contains("at foo")); } @@ -252,12 +287,12 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let code_str = isolate_scope.new_string("1+1"); - let ctx = isolate_scope.new_context(None); + let code_str = isolate_scope.create_string("1+1").try_into().unwrap(); + let ctx = isolate_scope.create_context(None); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); let res = script.run(&ctx_scope).unwrap(); - let res_utf8 = res.to_utf8().unwrap(); + let res_utf8: LocalUtf8 = res.try_into().unwrap(); assert_eq!(res_utf8.as_str(), "2"); } @@ -267,18 +302,25 @@ mod json_path_tests { let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let mut globals = isolate_scope.new_object_template(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.add_native_function("log", |args, _isolate_scope, _ctx_scope| { assert_eq!(args.len(), 1); let v = args.get(0); - let res_utf8 = v.to_utf8().unwrap(); + let res_utf8: LocalUtf8 = v.try_into().unwrap(); assert_eq!(res_utf8.as_str(), "foo"); None }); - let code_name = isolate_scope.new_string("base_module"); - let code_str = isolate_scope.new_string("import {msg} from \"foo\"; log(msg);"); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_name = isolate_scope + .create_string("base_module") + .try_into() + .unwrap(); + let code_str = isolate_scope + .create_string("import {msg} from \"foo\"; log(msg);") + .try_into() + .unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let module = ctx_scope @@ -287,12 +329,15 @@ mod json_path_tests { module.initialize( &ctx_scope, |isolate_scope, ctx_scope, name_to_load, _identity_hash| { - let code_str = isolate_scope.new_string("export let msg = \"foo\";"); + let code_str = isolate_scope + .create_string("export let msg = \"foo\";") + .try_into() + .unwrap(); ctx_scope.compile_as_module(name_to_load, &code_str, true) }, ); let res = module.evaluate(&ctx_scope).unwrap(); - let res = res.as_promise(); + let res: LocalPromise = res.try_into().unwrap(); assert_eq!( res.state(), crate::v8::types::promise::PromiseState::Fulfilled @@ -304,21 +349,24 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let code_str = isolate_scope.new_string("async function f(){return 1}; f"); - let ctx = isolate_scope.new_context(None); + let code_str = isolate_scope + .create_string("async function f(){return 1}; f") + .try_into() + .unwrap(); + let ctx = isolate_scope.create_context(None); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); let res = script.run(&ctx_scope).unwrap(); + let res: LocalValueAny = res.try_into().unwrap(); assert!(res.is_async_function()); let async_res = res.call(&ctx_scope, None).unwrap(); - assert!(async_res.is_promise()); - let promise = async_res.as_promise(); + let promise: LocalPromise = async_res.try_into().unwrap(); assert_eq!( promise.state(), crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); - let res_utf8 = promise_res.to_utf8().unwrap(); + let res_utf8 = promise_res.into_utf8().unwrap(); assert_eq!(res_utf8.as_str(), "1"); } @@ -327,28 +375,34 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let mut globals = isolate_scope.new_object_template(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.add_native_function("foo", |_args, isolate_scope, ctx_scope| { - let resolver = ctx_scope.new_resolver(); - resolver.resolve(&ctx_scope, &isolate_scope.new_string("foo").to_value()); + let resolver = ctx_scope.create_resolver(); + resolver.resolve( + &ctx_scope, + &isolate_scope.create_string("foo").try_into().unwrap(), + ); let promise = resolver.get_promise(); - let promise_val = promise.to_value(); - Some(promise_val) + // let promise_val = promise.to_value(); + Some(promise.try_into().unwrap()) }); - let code_str = isolate_scope.new_string("foo()"); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_str = isolate_scope.create_string("foo()").try_into().unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); - let script = ctx_scope.compile(&code_str).unwrap(); + let script = ctx_scope + .compile(&code_str) + .expect("Couldn't compile script"); let res = script.run(&ctx_scope).unwrap(); - println!("{}", res.to_utf8().unwrap().as_str()); - assert!(res.is_promise()); - let promise = res.as_promise(); + let s: LocalUtf8 = res.clone().try_into().unwrap(); + println!("{}", s.as_str()); + let promise: LocalPromise = res.try_into().unwrap(); assert_eq!( promise.state(), crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); - let res_utf8 = promise_res.to_utf8().unwrap(); + let res_utf8 = promise_res.into_utf8().unwrap(); assert_eq!(res_utf8.as_str(), "foo"); } @@ -357,14 +411,14 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let code_str = isolate_scope.new_string("foo("); - let ctx = isolate_scope.new_context(None); + let code_str = isolate_scope.create_string("foo(").try_into().unwrap(); + let ctx = isolate_scope.create_context(None); let ctx_scope = ctx.enter(&isolate_scope); - let trycatch = isolate_scope.new_try_catch(); + let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); let script = ctx_scope.compile(&code_str); assert!(script.is_none()); assert_eq!( - trycatch.get_exception().to_utf8().unwrap().as_str(), + trycatch.get_exception().into_utf8().unwrap().as_str(), "SyntaxError: Unexpected end of input" ); } @@ -374,15 +428,15 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let code_str = isolate_scope.new_string("foo()"); - let ctx = isolate_scope.new_context(None); + let code_str = isolate_scope.create_string("foo()").try_into().unwrap(); + let ctx = isolate_scope.create_context(None); let ctx_scope = ctx.enter(&isolate_scope); - let trycatch = isolate_scope.new_try_catch(); + let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); let script = ctx_scope.compile(&code_str).unwrap(); let res = script.run(&ctx_scope); assert!(res.is_none()); assert_eq!( - trycatch.get_exception().to_utf8().unwrap().as_str(), + trycatch.get_exception().into_utf8().unwrap().as_str(), "ReferenceError: foo is not defined" ); } @@ -392,7 +446,7 @@ mod json_path_tests { &types::native_function_template::LocalNativeFunctionArgs<'d, 'e>, &'d isolate_scope::IsolateScope<'e>, &context_scope::ContextScope<'d, 'e>, - ) -> Option>, + ) -> Option>, >( code: &str, func_name: &str, @@ -401,20 +455,24 @@ mod json_path_tests { initialize(); let isolate = isolate::Isolate::new(); let isolate_scope = isolate.enter(); - let native = isolate_scope.new_native_function_template(f); - let native_funciton_name = isolate_scope.new_string(func_name); - let mut globals = isolate_scope.new_object_template(); + let native: LocalNativeFunctionTemplate = isolate_scope + .create_native_function_template(f) + .try_into() + .unwrap(); + let native_funciton_name = isolate_scope.create_string(func_name).try_into().unwrap(); + let mut globals: LocalObjectTemplate = + isolate_scope.create_object_template().try_into().unwrap(); globals.set_native_function(&native_funciton_name, &native); - let code_str = isolate_scope.new_string(code); - let ctx = isolate_scope.new_context(Some(&globals)); + let code_str = isolate_scope.create_string(code).try_into().unwrap(); + let ctx = isolate_scope.create_context(Some(&globals)); let ctx_scope = ctx.enter(&isolate_scope); let script = ctx_scope.compile(&code_str).unwrap(); - let trycatch = isolate_scope.new_try_catch(); + let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); let res = match script.run(&ctx_scope) { Some(_res) => Ok(()), None => Err(trycatch .get_exception() - .to_utf8() + .into_utf8() .unwrap() .as_str() .to_string()), @@ -425,7 +483,11 @@ mod json_path_tests { #[test] fn test_value_is_object() { define_function_and_call("foo({})", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_object()); + if let Value::Object(_) = args.get(0) { + assert!(true); + } else { + assert!(false, "The value should have been an object!"); + } None }) .expect("Got error on function run"); @@ -434,7 +496,11 @@ mod json_path_tests { #[test] fn test_value_is_function() { define_function_and_call("foo(()=>{})", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_function()); + if let Value::Other(any) = args.get(0) { + assert!(any.is_function()); + } else { + assert!(false, "The value should have been an object!"); + } None }) .expect("Got error on function run"); @@ -446,7 +512,11 @@ mod json_path_tests { "foo(async function(){})", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_async_function()); + if let Value::Other(any) = args.get(0) { + assert!(any.is_async_function()); + } else { + assert!(false, "The value should have been an object!"); + } None }, ) @@ -456,7 +526,11 @@ mod json_path_tests { #[test] fn test_value_is_string() { define_function_and_call("foo(\"foo\")", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_string()); + if let Value::String(_) = args.get(0) { + assert!(true); + } else { + assert!(false, "The value should have been a string!"); + } None }) .expect("Got error on function run"); @@ -465,7 +539,11 @@ mod json_path_tests { #[test] fn test_value_is_number() { define_function_and_call("foo(1)", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_number()); + if let Value::Double(_) = args.get(0) { + assert!(true); + } else { + assert!(false, "The value should have been a number!"); + } None }) .expect("Got error on function run"); @@ -477,7 +555,11 @@ mod json_path_tests { "foo(async function(){}())", "foo", |args, _isolate, _ctx_scope| { - assert!(args.get(0).is_promise()); + if let Value::Other(any) = args.get(0) { + assert!(any.is_promise()); + } else { + assert!(false, "The value should have been a number!"); + } None }, ) @@ -492,7 +574,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -506,7 +588,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: f64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -521,7 +603,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); assert_eq!(arg3, "test"); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -536,7 +618,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); assert_eq!(arg3, true); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -549,7 +631,7 @@ mod json_path_tests { "test", new_native_function!(|_isolate, _ctx_scope, arg1: types::utf8::LocalUtf8| { assert_eq!(arg1.as_str(), "test"); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -560,9 +642,10 @@ mod json_path_tests { define_function_and_call( "test('test')", "test", - new_native_function!(|_isolate, _ctx_scope, arg1: types::LocalValueGeneric| { - assert_eq!(arg1.to_utf8().unwrap().as_str(), "test"); - Result::, String>::Ok(None) + new_native_function!(|_isolate, _ctx_scope, arg1: Value| { + let utf8 = LocalUtf8::try_from(arg1).unwrap(); + assert_eq!(utf8.as_ref(), "test"); + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -574,7 +657,7 @@ mod json_path_tests { "test(new Set())", "test", new_native_function!(|_isolate, _ctx_scope, _arg1: types::set::LocalSet| { - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -587,7 +670,7 @@ mod json_path_tests { "test", new_native_function!(|_isolate, _ctx_scope, arg1: types::array::LocalArray| { assert_eq!(arg1.len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -601,7 +684,7 @@ mod json_path_tests { new_native_function!( |_isolate, _ctx_scope, arg1: types::array_buffer::LocalArrayBuffer| { assert_eq!(arg1.data(), &[255, 255, 255, 255]); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -617,15 +700,15 @@ mod json_path_tests { |isolate_scope: &isolate_scope::IsolateScope, ctx_scope, arg1: types::object::LocalObject| { - assert_eq!( - arg1.get(ctx_scope, &isolate_scope.new_string("foo").to_value()) - .unwrap() - .to_utf8() - .unwrap() - .as_str(), - "bar" - ); - Result::, String>::Ok(None) + let value = arg1 + .get( + ctx_scope, + &isolate_scope.create_string("foo").try_into().unwrap(), + ) + .unwrap(); + let string = String::try_from(value).unwrap(); + assert_eq!(&string, "bar"); + Result::, String>::Ok(None) } ), ) @@ -640,7 +723,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -658,7 +741,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: i64| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -681,7 +764,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3, None); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -704,7 +787,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert_eq!(arg3, Some(2.2)); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); @@ -728,7 +811,7 @@ mod json_path_tests { assert_eq!(arg1, 1); assert_eq!(arg2, 2); assert!(arg3.is_none()); - Result::, String>::Ok(None) + Result::, String>::Ok(None) } ), ) @@ -752,8 +835,13 @@ mod json_path_tests { arg3: Option| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - assert_eq!(arg3.unwrap().len(), 2); - Result::, String>::Ok(None) + if let Some(array) = arg3 { + assert_eq!(array.len(), 2); + assert!(true); + } else { + assert!(false, "Should have been an array."); + } + Result::, String>::Ok(None) } ), ) @@ -766,23 +854,24 @@ mod json_path_tests { #[test] fn test_native_function_macro_optional_arguments_value() { - let err = define_function_and_call( - "test(1, 'foo', [1, 2])", - "test", - new_native_function!( - |_isolate, - _ctx_scope, - arg1: i64, - arg2: i64, - arg3: Option| { - assert_eq!(arg1, 1); - assert_eq!(arg2, 2); - assert_eq!(arg3.unwrap().is_array(), true); - Result::, String>::Ok(None) - } - ), - ) - .expect_err("Did not get error when suppose to."); + let err = + define_function_and_call( + "test(1, 'foo', [1, 2])", + "test", + new_native_function!( + |_isolate, _ctx_scope, arg1: i64, arg2: i64, arg3: Option| { + assert_eq!(arg1, 1); + assert_eq!(arg2, 2); + if let Some(Value::Array(_)) = arg3 { + assert!(true); + } else { + assert!(false, "Should have been an array."); + } + Result::, String>::Ok(None) + } + ), + ) + .expect_err("Did not get error when suppose to."); assert_eq!( err, "Can not convert value at position 1 into i64. Value is not long." @@ -794,9 +883,9 @@ mod json_path_tests { define_function_and_call( "test(1, 'foo', [1, 2])", "test", - new_native_function!(|_isolate, _ctx_scope, arg: Vec| { + new_native_function!(|_isolate, _ctx_scope, arg: Vec| { assert_eq!(arg.len(), 3); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect("Got error on function run"); @@ -807,13 +896,11 @@ mod json_path_tests { define_function_and_call( "test(1, 'foo', [1, 2])", "test", - new_native_function!( - |_isolate, _ctx_scope, arg1: i64, arg2: Vec| { - assert_eq!(arg1, 1); - assert_eq!(arg2.len(), 2); - Result::, String>::Ok(None) - } - ), + new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: Vec| { + assert_eq!(arg1, 1); + assert_eq!(arg2.len(), 2); + Result::, String>::Ok(None) + }), ) .expect("Got error on function run"); } @@ -826,7 +913,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: Vec| { assert_eq!(arg1, 1); assert_eq!(arg2.len(), 2); - Result::, String>::Ok(None) + Result::, String>::Ok(None) }), ) .expect_err("Did not get error when suppose to."); diff --git a/src/v8/context.rs b/src/v8/context.rs index 5968d35..7e7c7b4 100644 --- a/src/v8/context.rs +++ b/src/v8/context.rs @@ -56,7 +56,7 @@ unsafe impl Send for Context {} impl Context { pub(crate) fn new(isolate: &Isolate, globals: Option<&LocalObjectTemplate>) -> Self { let inner_ctx = match globals { - Some(g) => unsafe { v8_NewContext(isolate.inner_isolate, g.inner_obj) }, + Some(g) => unsafe { v8_NewContext(isolate.inner_isolate, g.0.inner_val) }, None => unsafe { v8_NewContext(isolate.inner_isolate, ptr::null_mut()) }, }; Self { inner_ctx } diff --git a/src/v8/context_scope.rs b/src/v8/context_scope.rs index 23aadd3..c5a71df 100644 --- a/src/v8/context_scope.rs +++ b/src/v8/context_scope.rs @@ -14,6 +14,7 @@ use crate::{RawIndex, UserIndex}; use std::marker::PhantomData; use std::os::raw::c_void; +use std::ptr::NonNull; use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::module::LocalModule; @@ -25,7 +26,10 @@ use crate::v8::types::object::LocalObject; use crate::v8::types::resolver::LocalResolver; use crate::v8::types::script::LocalScript; use crate::v8::types::string::LocalString; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::types::any::LocalValueAny; +use super::types::Value; /// An RAII data guard which resets the private data slot after going /// out of scope. @@ -69,51 +73,45 @@ pub struct ContextScope<'isolate_scope, 'isolate> { impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { /// Compile the given code into a script object. - #[must_use] pub fn compile(&self, s: &LocalString) -> Option> { - let inner_script = unsafe { v8_Compile(self.inner_ctx_ref, s.inner_string) }; - if inner_script.is_null() { - None - } else { - Some(LocalScript { - inner_script, + NonNull::new(unsafe { v8_Compile(self.inner_ctx_ref, s.0.inner_val) }).map(|ptr| { + LocalScript(ScopedValue { + inner_val: ptr.as_ptr(), isolate_scope: self.isolate_scope, }) - } + }) } - #[must_use] pub fn get_globals(&self) -> LocalObject<'isolate_scope, 'isolate> { - let inner_obj = unsafe { v8_ContextRefGetGlobals(self.inner_ctx_ref) }; - LocalObject { - inner_obj, + let inner_val = unsafe { v8_ContextRefGetGlobals(self.inner_ctx_ref) }; + LocalObject(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - } + }) } /// Compile the given code as a module. - #[must_use] pub fn compile_as_module( &self, name: &LocalString, code: &LocalString, is_module: bool, ) -> Option> { - let inner_module = unsafe { + let inner_val = unsafe { v8_CompileAsModule( self.inner_ctx_ref, - name.inner_string, - code.inner_string, + name.0.inner_val, + code.0.inner_val, i32::from(is_module), ) }; - if inner_module.is_null() { + if inner_val.is_null() { None } else { - Some(LocalModule { - inner_module, + Some(LocalModule(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - }) + })) } } @@ -141,14 +139,12 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { } /// Return the private data that was set on the context - #[must_use] pub fn get_private_data>(&self, index: I) -> Option<&T> { let index = index.into(); self.get_private_data_raw(index) } /// Return the private data that was set on the context as a mut reference - #[must_use] pub fn get_private_data_mut>(&self, index: I) -> Option<&mut T> { let index = index.into(); self.get_private_data_mut_raw(index) @@ -169,7 +165,6 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { /// Sets the private data at the specified index (V8 data slot). /// Returns an RAII guard that takes care of resetting the data /// at the specified index. - #[must_use] pub fn set_private_data<'context_scope, 'data, T, I: Into>( &'context_scope self, index: I, @@ -186,57 +181,56 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { } /// Create a new resolver object - #[must_use] - pub fn new_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { - let inner_resolver = unsafe { v8_NewResolver(self.inner_ctx_ref) }; - LocalResolver { - inner_resolver, + pub fn create_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_NewResolver(self.inner_ctx_ref) }; + LocalResolver(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - } + }) } - #[must_use] - pub fn new_object_from_json( + pub fn create_object_from_json( &self, val: &LocalString, - ) -> Option> { - let inner_val = unsafe { v8_NewObjectFromJsonString(self.inner_ctx_ref, val.inner_string) }; + ) -> Option> { + let inner_val = unsafe { v8_NewObjectFromJsonString(self.inner_ctx_ref, val.0.inner_val) }; if inner_val.is_null() { return None; } - Some(LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - }) + Some( + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: self.isolate_scope, + }) + .into(), + ) } - #[must_use] pub fn json_stringify( &self, - val: &LocalValueGeneric, + val: &LocalValueAny, ) -> Option> { - let inner_string = unsafe { v8_JsonStringify(self.inner_ctx_ref, val.inner_val) }; - if inner_string.is_null() { + let inner_val = unsafe { v8_JsonStringify(self.inner_ctx_ref, val.0.inner_val) }; + if inner_val.is_null() { return None; } - Some(LocalString { - inner_string, + Some(LocalString(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - }) + })) } - #[must_use] - pub fn new_native_function< + pub fn create_native_function< T: for<'d, 'c> Fn( &LocalNativeFunctionArgs<'d, 'c>, &'d IsolateScope<'c>, &ContextScope<'d, 'c>, - ) -> Option>, + ) -> Option>, >( &self, func: T, ) -> LocalNativeFunction<'isolate_scope, 'isolate> { - let inner_func = unsafe { + let inner_val = unsafe { v8_NewNativeFunction( self.inner_ctx_ref, Some(native_basic_function::), @@ -244,10 +238,10 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { Some(free_pd::), ) }; - LocalNativeFunction { - inner_func, + LocalNativeFunction(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - } + }) } } diff --git a/src/v8/isolate.rs b/src/v8/isolate.rs index c7fd777..cdf74cb 100644 --- a/src/v8/isolate.rs +++ b/src/v8/isolate.rs @@ -21,6 +21,7 @@ use std::os::raw::{c_char, c_int}; /// An isolate rust wrapper object. /// The isolate will not be automatically freed. /// In order to free an isolate, one must call [`V8Isolate::free_isolate`]. +#[derive(Debug)] pub struct Isolate { pub(crate) inner_isolate: *mut v8_isolate, pub(crate) no_release: bool, diff --git a/src/v8/isolate_scope.rs b/src/v8/isolate_scope.rs index 5dbc818..ea64459 100644 --- a/src/v8/isolate_scope.rs +++ b/src/v8/isolate_scope.rs @@ -5,42 +5,27 @@ */ use crate::v8_c_raw::bindings::{ - v8_FreeHandlersScope, v8_IsolateEnter, v8_IsolateExit, v8_IsolateRaiseException, v8_NewArray, - v8_NewArrayBuffer, v8_NewBool, v8_NewExternalData, v8_NewHandlersScope, - v8_NewNativeFunctionTemplate, v8_NewNull, v8_NewObject, v8_NewObjectTemplate, v8_NewSet, - v8_NewString, v8_NewTryCatch, v8_NewUnlocker, v8_StringToValue, v8_ValueFromDouble, - v8_ValueFromLong, v8_handlers_scope, v8_isolate_scope, v8_local_value, + v8_FreeHandlersScope, v8_IsolateEnter, v8_IsolateExit, v8_IsolateRaiseException, + v8_NewHandlersScope, v8_handlers_scope, v8_isolate_scope, }; use crate::v8::context::Context; -use crate::v8::context_scope::ContextScope; use crate::v8::isolate::Isolate; -use crate::v8::types::array::LocalArray; -use crate::v8::types::array_buffer::LocalArrayBuffer; -use crate::v8::types::external_data::LocalExternalData; -use crate::v8::types::native_function_template::{ - free_pd, native_basic_function, LocalNativeFunctionArgs, LocalNativeFunctionTemplate, -}; -use crate::v8::types::object::LocalObject; use crate::v8::types::object_template::LocalObjectTemplate; -use crate::v8::types::set::LocalSet; use crate::v8::types::string::LocalString; -use crate::v8::types::try_catch::TryCatch; -use crate::v8::types::unlocker::Unlocker; -use crate::v8::types::LocalValueGeneric; -use std::os::raw::{c_char, c_void}; +use super::context_scope::ContextScope; +use super::types::any::LocalValueAny; +use super::types::native_function_template::LocalNativeFunctionArgs; +use super::types::Value; +#[derive(Debug)] pub struct IsolateScope<'isolate> { pub(crate) isolate: &'isolate Isolate, inner_handlers_scope: *mut v8_handlers_scope, inner_isolate_scope: *mut v8_isolate_scope, } -extern "C" fn free_external_data(arg1: *mut ::std::os::raw::c_void) { - unsafe { Box::from_raw(arg1 as *mut T) }; -} - impl<'isolate> IsolateScope<'isolate> { pub(crate) fn new(isolate: &'isolate Isolate) -> IsolateScope<'isolate> { let inner_isolate_scope = unsafe { v8_IsolateEnter(isolate.inner_isolate) }; @@ -54,228 +39,130 @@ impl<'isolate> IsolateScope<'isolate> { /// Creating a new context for JS code invocation. #[must_use] - pub fn new_context(&self, globals: Option<&LocalObjectTemplate>) -> Context { + pub fn create_context(&self, globals: Option<&LocalObjectTemplate>) -> Context { Context::new(self.isolate, globals) } /// Raise an exception with the given local generic value. - pub fn raise_exception(&self, exception: LocalValueGeneric) { - unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, exception.inner_val) }; + pub fn raise_exception(&self, exception: LocalValueAny) { + unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, exception.0.inner_val) }; } /// Same as `raise_exception` but raise exception with the given massage. pub fn raise_exception_str(&self, msg: &str) { - let inner_string = unsafe { - v8_NewString( - self.isolate.inner_isolate, - msg.as_ptr().cast::(), - msg.len(), - ) - }; - let inner_val = unsafe { v8_StringToValue(inner_string) }; - unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, inner_val) }; + let value = LocalValueAny::from(LocalString::new(msg, self)); + unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, value.0.inner_val) }; } /// Return a new try catch object. The object will catch any exception that was /// raised during the JS code invocation. #[must_use] - pub fn new_try_catch<'isolate_scope>( + pub fn create_try_catch<'isolate_scope>( &'isolate_scope self, - ) -> TryCatch<'isolate_scope, 'isolate> { - let inner_trycatch = unsafe { v8_NewTryCatch(self.isolate.inner_isolate) }; - TryCatch { - inner_trycatch, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::new_try_catch(self) } /// Create a new string object. #[must_use] - pub fn new_string<'isolate_scope>( + pub fn create_string<'isolate_scope>( &'isolate_scope self, s: &str, - ) -> LocalString<'isolate_scope, 'isolate> { - let inner_string = unsafe { - v8_NewString( - self.isolate.inner_isolate, - s.as_ptr().cast::(), - s.len(), - ) - }; - LocalString { - inner_string, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::new_string(s, self) } - /// Create a new string object. + /// Create a new array object. #[must_use] - pub fn new_array<'isolate_scope>( + pub fn create_array<'isolate_scope>( &'isolate_scope self, - values: &[&LocalValueGeneric], - ) -> LocalArray<'isolate_scope, 'isolate> { - let args = values - .iter() - .map(|v| v.inner_val) - .collect::>(); - let ptr = args.as_ptr(); - let inner_array = unsafe { v8_NewArray(self.isolate.inner_isolate, ptr, values.len()) }; - LocalArray { - inner_array, - isolate_scope: self, - } + values: &[&LocalValueAny], + ) -> Value<'isolate_scope, 'isolate> { + Value::new_array(values, self) } #[must_use] - pub fn new_array_buffer<'isolate_scope>( + pub fn create_array_buffer<'isolate_scope>( &'isolate_scope self, - buff: &[u8], - ) -> LocalArrayBuffer<'isolate_scope, 'isolate> { - let inner_array_buffer = unsafe { - v8_NewArrayBuffer( - self.isolate.inner_isolate, - buff.as_ptr() as *const c_char, - buff.len(), - ) - }; - LocalArrayBuffer { - inner_array_buffer, - isolate_scope: self, - } + bytes: &[u8], + ) -> Value<'isolate_scope, 'isolate> { + Value::new_array_buffer(bytes, self) } #[must_use] - pub fn new_object<'isolate_scope>( - &'isolate_scope self, - ) -> LocalObject<'isolate_scope, 'isolate> { - let inner_obj = unsafe { v8_NewObject(self.isolate.inner_isolate) }; - LocalObject { - inner_obj, - isolate_scope: self, - } + pub fn create_object<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { + Value::new_object(self) } #[must_use] - pub fn new_external_data<'isolate_scope, T>( + pub fn create_external_data<'isolate_scope, T>( &'isolate_scope self, data: T, - ) -> LocalExternalData<'isolate_scope, 'isolate> { - let data = Box::into_raw(Box::new(data)); - let inner_ext = unsafe { - v8_NewExternalData( - self.isolate.inner_isolate, - data as *mut c_void, - Some(free_external_data::), - ) - }; - LocalExternalData { - inner_ext, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::new_external_data(data, self) } #[must_use] - pub fn new_set<'isolate_scope>(&'isolate_scope self) -> LocalSet<'isolate_scope, 'isolate> { - let inner_set = unsafe { v8_NewSet(self.isolate.inner_isolate) }; - LocalSet { - inner_set, - isolate_scope: self, - } + pub fn create_set<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { + Value::new_set(self) } #[must_use] - pub fn new_bool<'isolate_scope>( + pub fn create_bool<'isolate_scope>( &'isolate_scope self, val: bool, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_NewBool(self.isolate.inner_isolate, val as i32) }; - LocalValueGeneric { - inner_val, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::from_bool(val, self) } - pub fn new_long<'isolate_scope>( + pub fn create_long<'isolate_scope>( &'isolate_scope self, val: i64, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ValueFromLong(self.isolate.inner_isolate, val) }; - LocalValueGeneric { - inner_val, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::from_i64(val, self) } - pub fn new_double<'isolate_scope>( + pub fn create_double<'isolate_scope>( &'isolate_scope self, val: f64, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ValueFromDouble(self.isolate.inner_isolate, val) }; - LocalValueGeneric { - inner_val, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::from_f64(val, self) } - pub fn new_null<'isolate_scope>( - &'isolate_scope self, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_NewNull(self.isolate.inner_isolate) }; - LocalValueGeneric { - inner_val, - isolate_scope: self, - } + pub fn create_null<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { + Value::new_null(self) } /// Create a new JS object template. #[must_use] - pub fn new_object_template<'isolate_scope>( + pub fn create_object_template<'isolate_scope>( &'isolate_scope self, - ) -> LocalObjectTemplate<'isolate_scope, 'isolate> { - let inner_obj = unsafe { v8_NewObjectTemplate(self.isolate.inner_isolate) }; - LocalObjectTemplate { - inner_obj, - isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::new_object_template(self) } /// Create a new native function template. - pub fn new_native_function_template< + pub fn create_native_function_template< 'isolate_scope, - T: for<'d, 'e> Fn( - &LocalNativeFunctionArgs<'d, 'e>, - &'d IsolateScope<'e>, - &ContextScope<'d, 'e>, - ) -> Option>, + T: for<'d, 'c> Fn( + &LocalNativeFunctionArgs<'d, 'c>, + &'d IsolateScope<'c>, + &ContextScope<'d, 'c>, + ) -> Option>, >( &'isolate_scope self, - func: T, - ) -> LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { - let inner_func = unsafe { - v8_NewNativeFunctionTemplate( - self.isolate.inner_isolate, - Some(native_basic_function::), - Box::into_raw(Box::new(func)).cast::(), - Some(free_pd::), - ) - }; - LocalNativeFunctionTemplate { - inner_func, - isolate_scope: self, - } + function: T, + ) -> Value<'isolate_scope, 'isolate> { + Value::new_native_function_template(function, self) } /// Create a new unlocker object that releases the isolate global lock. /// The lock will be re-aquire when the unlocker will be released. #[must_use] - pub fn new_unlocker<'isolate_scope>( + pub fn create_unlocker<'isolate_scope>( &'isolate_scope self, - ) -> Unlocker<'isolate_scope, 'isolate> { - let inner_unlocker = unsafe { v8_NewUnlocker(self.isolate.inner_isolate) }; - Unlocker { - inner_unlocker, - _isolate_scope: self, - } + ) -> Value<'isolate_scope, 'isolate> { + Value::new_unlocker(self) } } diff --git a/src/v8/types/any.rs b/src/v8/types/any.rs new file mode 100644 index 0000000..818eb4e --- /dev/null +++ b/src/v8/types/any.rs @@ -0,0 +1,427 @@ +/* + * Copyright Redis Ltd. 2022 - present + * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or + * the Server Side Public License v1 (SSPLv1). + */ +//! This is an abstraction over a scoped V8 value type. +//! As this is a fully abstract class in V8, the objects it can hold +//! can be of any javascript type. Hence it is generic. + +use std::ptr::NonNull; + +use crate::{ + v8::context_scope::ContextScope, + v8_c_raw::bindings::{ + v8_FreeValue, v8_FunctionCall, v8_GetBigInt, v8_GetBool, v8_GetNumber, v8_PersistValue, + v8_ValueAsArray, v8_ValueAsArrayBuffer, v8_ValueAsExternalData, v8_ValueAsObject, + v8_ValueAsPromise, v8_ValueAsResolver, v8_ValueAsSet, v8_ValueAsString, v8_ValueIsArray, + v8_ValueIsArrayBuffer, v8_ValueIsAsyncFunction, v8_ValueIsBigInt, v8_ValueIsBool, + v8_ValueIsExternalData, v8_ValueIsFunction, v8_ValueIsNull, v8_ValueIsNumber, + v8_ValueIsObject, v8_ValueIsPromise, v8_ValueIsSet, v8_ValueIsString, + v8_ValueIsStringObject, v8_local_value, + }, +}; + +use super::{ + array::LocalArray, array_buffer::LocalArrayBuffer, external_data::LocalExternalData, + object::LocalObject, persistent::PersistValue, promise::LocalPromise, resolver::LocalResolver, + set::LocalSet, string::LocalString, utf8::LocalUtf8, ScopedValue, +}; + +/// A type the objects of [LocalValueAny] can hold. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Type { + Integer, + Double, + Boolean, + Null, + Set, + ExternalData, + Object, + Resolver, + Promise, + Function, + AsyncFunction, + Array, + ArrayBuffer, + String, + StringObject, + Utf8, +} + +/// A local value for which there is no type information available. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalValueAny<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_value>, +); + +impl<'isolate_scope, 'isolate> LocalValueAny<'isolate_scope, 'isolate> { + /// Returns the type of the value hold if it the valid, [`None`] + /// otherwise. + pub fn get_type(&self) -> Option { + Some(if self.is_array() { + Type::Array + } else if self.is_array_buffer() { + Type::ArrayBuffer + } else if self.is_async_function() { + Type::AsyncFunction + } else if self.is_boolean() { + Type::Boolean + } else if self.is_external_data() { + Type::ExternalData + } else if self.is_function() { + Type::Function + } else if self.is_long() { + Type::Integer + } else if self.is_null() { + Type::Null + } else if self.is_number() { + Type::Double + } else if self.is_object() { + Type::Object + } else if self.is_promise() { + Type::Promise + } else if self.is_set() { + Type::Set + } else if self.is_string() { + Type::String + } else if self.is_string_object() { + Type::StringObject + } else { + return None; + }) + } + + /// Return string representation of the value or None on failure + #[deprecated = "Use [LocalUtf8::try_from] instead."] + pub fn into_utf8(self) -> Option> { + LocalUtf8::try_from(self).ok() + } + + /// Return true if the value is string and false otherwise. + pub fn is_string(&self) -> bool { + (unsafe { v8_ValueIsString(self.0.inner_val) } != 0) + } + + /// Convert the object into a string, applicable only if the value is string. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_string(&self) -> LocalString<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsString(self.0.inner_val) }; + LocalString(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Return true if the value is string object and false otherwise. + pub fn is_string_object(&self) -> bool { + (unsafe { v8_ValueIsStringObject(self.0.inner_val) } != 0) + } + + /// Return true if the value is string and false otherwise. + pub fn is_array(&self) -> bool { + (unsafe { v8_ValueIsArray(self.0.inner_val) } != 0) + } + + /// Convert the object into a string, applicable only if the value is string. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_array(&self) -> LocalArray<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsArray(self.0.inner_val) }; + LocalArray(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Return true if the value is string and false otherwise. + pub fn is_array_buffer(&self) -> bool { + (unsafe { v8_ValueIsArrayBuffer(self.0.inner_val) } != 0) + } + + /// Convert the object into a string, applicable only if the value is string. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_array_buffer(&self) -> LocalArrayBuffer<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsArrayBuffer(self.0.inner_val) }; + LocalArrayBuffer(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Return true if the value is null and false otherwise. + pub fn is_null(&self) -> bool { + (unsafe { v8_ValueIsNull(self.0.inner_val) } != 0) + } + + /// Return true if the value is function and false otherwise. + pub fn is_function(&self) -> bool { + (unsafe { v8_ValueIsFunction(self.0.inner_val) } != 0) + } + + /// Return true if the value is async function and false otherwise. + pub fn is_async_function(&self) -> bool { + (unsafe { v8_ValueIsAsyncFunction(self.0.inner_val) } != 0) + } + + /// Return true if the value is number and false otherwise. + pub fn is_number(&self) -> bool { + (unsafe { v8_ValueIsNumber(self.0.inner_val) } != 0) + } + + /// Returns an [f64] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn get_number(&self) -> f64 { + unsafe { v8_GetNumber(self.0.inner_val) } + } + + /// Return true if the value is number and false otherwise. + pub fn is_long(&self) -> bool { + (unsafe { v8_ValueIsBigInt(self.0.inner_val) } != 0) + } + + /// Returns an [i64] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn get_long(&self) -> i64 { + unsafe { v8_GetBigInt(self.0.inner_val) } + } + + /// Return true if the value is boolean and false otherwise. + pub fn is_boolean(&self) -> bool { + (unsafe { v8_ValueIsBool(self.0.inner_val) } != 0) + } + + /// Returns a [bool] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn get_boolean(&self) -> bool { + (unsafe { v8_GetBool(self.0.inner_val) } != 0) + } + + /// Return true if the value is promise and false otherwise. + pub fn is_promise(&self) -> bool { + (unsafe { v8_ValueIsPromise(self.0.inner_val) } != 0) + } + + /// Returns a [LocalPromise] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsPromise(self.0.inner_val) }; + LocalPromise(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Returns a [LocalResolver] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsResolver(self.0.inner_val) }; + LocalResolver(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Return true if the value is object and false otherwise. + pub fn is_object(&self) -> bool { + (unsafe { v8_ValueIsObject(self.0.inner_val) } != 0) + } + + /// Returns a [LocalObject] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_object(&self) -> LocalObject<'isolate_scope, 'isolate> { + let inner_obj = unsafe { v8_ValueAsObject(self.0.inner_val) }; + LocalObject(ScopedValue { + inner_val: inner_obj, + isolate_scope: self.0.isolate_scope, + }) + } + + pub fn is_external_data(&self) -> bool { + (unsafe { v8_ValueIsExternalData(self.0.inner_val) } != 0) + } + + /// Returns a [LocalExternalData] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_external_data(&self) -> LocalExternalData<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsExternalData(self.0.inner_val) }; + LocalExternalData(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Return true if the value is set and false otherwise. + pub fn is_set(&self) -> bool { + (unsafe { v8_ValueIsSet(self.0.inner_val) } != 0) + } + + /// Returns a [LocalSet] value. + /// + /// # Safety + /// + /// The function doesn't perform checks for the value being actually + /// of the target type. And doesn't panic if this is not the case. + /// If a fallible conversion is preferred, use [`TryFrom`]. + /// + /// In case the target type is not checked before this function is + /// invoked and the value is not of this target type, the results + /// are unknown. + pub unsafe fn as_set(&self) -> LocalSet<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ValueAsSet(self.0.inner_val) }; + LocalSet(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + } + + /// Persist the local object so it can be saved beyond the current handlers scope. + /// TODO move to `From` impl. + pub fn persist(&self) -> PersistValue { + let inner_val = unsafe { + v8_PersistValue(self.0.isolate_scope.isolate.inner_isolate, self.0.inner_val) + }; + PersistValue::from(inner_val) + } + + /// Run the value, applicable only if the value is a function or async function. + pub fn call(&self, ctx: &ContextScope, args: Option<&[&Self]>) -> Option { + NonNull::new(match args { + Some(args) => { + let args = args + .iter() + .map(|v| v.0.inner_val) + .collect::>(); + let ptr = args.as_ptr(); + unsafe { v8_FunctionCall(ctx.inner_ctx_ref, self.0.inner_val, args.len(), ptr) } + } + None => unsafe { + v8_FunctionCall(ctx.inner_ctx_ref, self.0.inner_val, 0, std::ptr::null()) + }, + }) + .map(|ptr| { + Self(ScopedValue { + inner_val: ptr.as_ptr(), + isolate_scope: self.0.isolate_scope, + }) + }) + } +} + +impl<'isolate_scope, 'isolate> Drop for LocalValueAny<'isolate_scope, 'isolate> { + fn drop(&mut self) { + if !self.0.inner_val.is_null() { + unsafe { v8_FreeValue(self.0.inner_val) } + } + } +} + +impl<'isolate_scope, 'isolate> TryFrom> for String { + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + LocalUtf8::try_from(val).map(|ls| ls.as_str().to_owned()) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> for bool { + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_boolean() { + return Err("Value is not a boolean"); + } + + Ok(unsafe { val.get_boolean() }) + } +} diff --git a/src/v8/types/array.rs b/src/v8/types/array.rs index 977925b..322733a 100644 --- a/src/v8/types/array.rs +++ b/src/v8/types/array.rs @@ -5,23 +5,44 @@ */ use crate::v8_c_raw::bindings::{ - v8_ArrayGet, v8_ArrayLen, v8_ArrayToValue, v8_FreeArray, v8_local_array, + v8_ArrayGet, v8_ArrayLen, v8_ArrayToValue, v8_FreeArray, v8_NewArray, v8_local_array, }; use crate::v8::context_scope::ContextScope; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object -pub struct LocalArray<'isolate_scope, 'isolate> { - pub(crate) inner_array: *mut v8_local_array, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::any::LocalValueAny; +use super::Value; + +/// JS array. +#[derive(Debug, Clone)] +pub struct LocalArray<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_array>, +); impl<'isolate_scope, 'isolate> LocalArray<'isolate_scope, 'isolate> { + /// Creates a new array within the provided [IsolateScope]. + pub fn new( + values: &[&LocalValueAny], + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + let args = values + .iter() + .map(|v| v.0.inner_val) + .collect::>(); + let ptr = args.as_ptr(); + let inner_val = + unsafe { v8_NewArray(isolate_scope.isolate.inner_isolate, ptr, values.len()) }; + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } + /// Returns the length of the array. pub fn len(&self) -> usize { - unsafe { v8_ArrayLen(self.inner_array) } + unsafe { v8_ArrayLen(self.0.inner_val) } } /// Returns true if the array is empty. @@ -46,29 +67,24 @@ impl<'isolate_scope, 'isolate> LocalArray<'isolate_scope, 'isolate> { &self, ctx_scope: &ContextScope, index: usize, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ArrayGet(ctx_scope.inner_ctx_ref, self.inner_array, index) }; - LocalValueGeneric { + ) -> LocalValueAny<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ArrayGet(ctx_scope.inner_ctx_ref, self.0.inner_val, index) }; + LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } - } - - /// Converts the array to a value object. - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ArrayToValue(self.inner_array) }; - LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: self.0.isolate_scope, + }) } } impl<'isolate_scope, 'isolate> From> - for LocalValueGeneric<'isolate_scope, 'isolate> + for LocalValueAny<'isolate_scope, 'isolate> { fn from(array: LocalArray<'isolate_scope, 'isolate>) -> Self { - array.to_value() + let inner_val = unsafe { v8_ArrayToValue(array.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: array.0.isolate_scope, + }) } } @@ -82,7 +98,7 @@ pub struct V8LocalArrayIterator<'context_scope, 'array, 'isolate_scope, 'isolate impl<'context_scope, 'array, 'isolate_scope, 'isolate> Iterator for V8LocalArrayIterator<'context_scope, 'array, 'isolate_scope, 'isolate> { - type Item = LocalValueGeneric<'isolate_scope, 'isolate>; + type Item = LocalValueAny<'isolate_scope, 'isolate>; fn next(&mut self) -> Option { if self.index >= self.array.len() { @@ -97,20 +113,34 @@ impl<'context_scope, 'array, 'isolate_scope, 'isolate> Iterator impl<'isolate_scope, 'isolate> Drop for LocalArray<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeArray(self.inner_array) } + unsafe { v8_FreeArray(self.0.inner_val) } } } -impl<'isolate_scope, 'isolate> TryFrom> +impl<'isolate_scope, 'isolate> TryFrom> for LocalArray<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { if !val.is_array() { return Err("Value is not an array"); } - Ok(val.as_array()) + Ok(unsafe { val.as_array() }) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalArray<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::Array(array) => Ok(array), + Value::Other(any) => any.try_into(), + _ => Err("Value is not an array"), + } } } diff --git a/src/v8/types/array_buffer.rs b/src/v8/types/array_buffer.rs index 8c1c439..09d8f75 100644 --- a/src/v8/types/array_buffer.rs +++ b/src/v8/types/array_buffer.rs @@ -5,50 +5,86 @@ */ use crate::v8_c_raw::bindings::{ - v8_ArrayBufferGetData, v8_ArrayBufferToValue, v8_FreeArrayBuffer, v8_local_array_buff, + v8_ArrayBufferGetData, v8_ArrayBufferToValue, v8_FreeArrayBuffer, v8_NewArrayBuffer, + v8_local_array_buff, }; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object -pub struct LocalArrayBuffer<'isolate_scope, 'isolate> { - pub(crate) inner_array_buffer: *mut v8_local_array_buff, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::any::LocalValueAny; +use super::Value; + +/// JavaScript array buffer. +#[derive(Debug, Clone)] +pub struct LocalArrayBuffer<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_array_buff>, +); impl<'isolate_scope, 'isolate> LocalArrayBuffer<'isolate_scope, 'isolate> { + /// Creates a new local array buffer within the provided [IsolateScope]. + pub fn new(bytes: &[u8], isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { + v8_NewArrayBuffer( + isolate_scope.isolate.inner_isolate, + bytes.as_ptr() as *const _, + bytes.len(), + ) + }; + + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } + pub fn data(&self) -> &[u8] { let mut size = 0; - let data = - unsafe { v8_ArrayBufferGetData(self.inner_array_buffer, &mut size as *mut usize) }; + let data = unsafe { v8_ArrayBufferGetData(self.0.inner_val, &mut size as *mut usize) }; unsafe { std::slice::from_raw_parts(data.cast::(), size) } } - - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ArrayBufferToValue(self.inner_array_buffer) }; - LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - } - } } impl<'isolate_scope, 'isolate> Drop for LocalArrayBuffer<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeArrayBuffer(self.inner_array_buffer) } + unsafe { v8_FreeArrayBuffer(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalArrayBuffer<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_ArrayBufferToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> TryFrom> +impl<'isolate_scope, 'isolate> TryFrom> for LocalArrayBuffer<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { if !val.is_array_buffer() { return Err("Value is not an array buffer"); } - Ok(val.as_array_buffer()) + Ok(unsafe { val.as_array_buffer() }) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalArrayBuffer<'isolate_scope, 'isolate> +{ + type Error = &'static str; + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::ArrayBuffer(array_buffer) => Ok(array_buffer), + Value::Other(any) => any.try_into(), + _ => Err("Value is not an array buffer"), + } } } diff --git a/src/v8/types/external_data.rs b/src/v8/types/external_data.rs index 60ad495..046c7e2 100644 --- a/src/v8/types/external_data.rs +++ b/src/v8/types/external_data.rs @@ -5,34 +5,72 @@ */ use crate::v8_c_raw::bindings::{ - v8_ExternalDataGet, v8_ExternalDataToValue, v8_local_external_data, + v8_ExternalDataGet, v8_ExternalDataToValue, v8_NewExternalData, v8_local_external_data, }; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object -pub struct LocalExternalData<'isolate_scope, 'isolate> { - pub(crate) inner_ext: *mut v8_local_external_data, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, +use super::any::LocalValueAny; + +extern "C" fn free_external_data(arg1: *mut ::std::os::raw::c_void) { + unsafe { Box::from_raw(arg1 as *mut T) }; } +/// TODO a proper comment. +#[derive(Debug, Clone)] +pub struct LocalExternalData<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_external_data>, +); + impl<'isolate_scope, 'isolate> LocalExternalData<'isolate_scope, 'isolate> { - /// Convert the object into a generic JS value - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ExternalDataToValue(self.inner_ext) }; - LocalValueGeneric { + /// Creates a new local external data object within the passed [IsolateScope]. + pub fn new(data: T, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let data = Box::into_raw(Box::new(data)); + let inner_val = unsafe { + v8_NewExternalData( + isolate_scope.isolate.inner_isolate, + data as *mut _, + Some(free_external_data::), + ) + }; + Self(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope, + }) } pub fn get_data(&self) -> &'isolate_scope T { - unsafe { &*(v8_ExternalDataGet(self.inner_ext) as *const T) } + unsafe { &*(v8_ExternalDataGet(self.0.inner_val) as *const T) } } pub fn get_data_mut(&mut self) -> &mut T { - unsafe { &mut *(v8_ExternalDataGet(self.inner_ext) as *mut T) } + unsafe { &mut *(v8_ExternalDataGet(self.0.inner_val) as *mut T) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalExternalData<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_ExternalDataToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalExternalData<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_external_data() { + return Err("Value is not a string"); + } + + Ok(unsafe { val.as_external_data() }) } } diff --git a/src/v8/types/mod.rs b/src/v8/types/mod.rs index f594dfe..200b631 100644 --- a/src/v8/types/mod.rs +++ b/src/v8/types/mod.rs @@ -4,18 +4,9 @@ * the Server Side Public License v1 (SSPLv1). */ -use crate::v8_c_raw::bindings::{ - v8_FreePersistedValue, v8_FreeValue, v8_FunctionCall, v8_GetBigInt, v8_GetBool, v8_GetNumber, - v8_PersistValue, v8_PersistedValueToLocal, v8_ToUtf8, v8_ValueAsArray, v8_ValueAsArrayBuffer, - v8_ValueAsExternalData, v8_ValueAsObject, v8_ValueAsPromise, v8_ValueAsResolver, v8_ValueAsSet, - v8_ValueAsString, v8_ValueIsArray, v8_ValueIsArrayBuffer, v8_ValueIsAsyncFunction, - v8_ValueIsBigInt, v8_ValueIsBool, v8_ValueIsExternalData, v8_ValueIsFunction, v8_ValueIsNull, - v8_ValueIsNumber, v8_ValueIsObject, v8_ValueIsPromise, v8_ValueIsSet, v8_ValueIsString, - v8_ValueIsStringObject, v8_local_value, v8_persisted_value, -}; - -use std::ptr; +use crate::v8_c_raw::bindings::{v8_NewBool, v8_NewNull, v8_ValueFromDouble, v8_ValueFromLong}; +pub mod any; pub mod array; pub mod array_buffer; pub mod external_data; @@ -24,6 +15,7 @@ pub mod native_function; pub mod native_function_template; pub mod object; pub mod object_template; +pub mod persistent; pub mod promise; pub mod resolver; pub mod script; @@ -42,421 +34,523 @@ use external_data::LocalExternalData; use native_function_template::V8LocalNativeFunctionArgsIter; use object::LocalObject; use promise::LocalPromise; -use resolver::LocalResolver; use set::LocalSet; use string::LocalString; use utf8::LocalUtf8; -/// JS generic local value -pub struct LocalValueGeneric<'isolate_scope, 'isolate> { - pub(crate) inner_val: *mut v8_local_value, +use self::any::{LocalValueAny, Type}; +use self::native_function_template::{LocalNativeFunctionArgs, LocalNativeFunctionTemplate}; +use self::object_template::LocalObjectTemplate; +use self::try_catch::TryCatch; +use self::unlocker::Unlocker; + +/// A generic, isolate-scoped JavaScript value. +#[derive(Debug, Copy, Clone)] +pub struct ScopedValue<'isolate_scope, 'isolate, BindingType: std::fmt::Debug> { + pub(crate) inner_val: *mut BindingType, pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -pub type LocalValue<'isolate_scope, 'isolate> = LocalValueGeneric<'isolate_scope, 'isolate>; -// #[repr(transparent)] -// pub struct LocalArray<'isolate_scope, 'isolate> { -// value: LocalGeneric<'isolate_scope, 'isolate>, -// } -// impl<'isolate_scope, 'isolate> LocalArray<'isolate_scope, 'isolate> { -// /// Return string representation of the value or None on failure -// #[must_use] -// pub fn to_utf8(&self) -> Option> { -// let inner_val = unsafe { -// v8_ToUtf8( -// self.value.isolate_scope.isolate.inner_isolate, -// self.value.inner_val, -// ) -// }; -// if inner_val.is_null() { -// None -// } else { -// Some(LocalUtf8 { -// inner_val, -// _isolate_scope: self.value.isolate_scope, -// }) -// } -// } -// } +/// An isolate-scoped [f64] local value in JavaScript. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalValueDouble<'isolate_scope, 'isolate>( + pub(crate) LocalValueAny<'isolate_scope, 'isolate>, +); + +impl<'isolate_scope, 'isolate> LocalValueDouble<'isolate_scope, 'isolate> { + fn new(value: f64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_ValueFromDouble(isolate_scope.isolate.inner_isolate, value) }; + Self(LocalValueAny(ScopedValue { + inner_val, + isolate_scope, + })) + } +} -// #[repr(transparent)] -// pub struct LocalValueString<'isolate_scope, 'isolate> { -// value: LocalGeneric<'isolate_scope, 'isolate>, -// } -// impl<'isolate_scope, 'isolate> LocalValueString<'isolate_scope, 'isolate> { -// /// Return string representation of the value or None on failure -// #[must_use] -// pub fn to_utf8(&self) -> Option> { -// let inner_val = unsafe { -// v8_ToUtf8( -// self.value.isolate_scope.isolate.inner_isolate, -// self.value.inner_val, -// ) -// }; -// if inner_val.is_null() { -// None -// } else { -// Some(LocalUtf8 { -// inner_val, -// _isolate_scope: self.value.isolate_scope, -// }) -// } -// } -// } +impl<'isolate_scope, 'isolate> From> for f64 { + fn from(value: LocalValueDouble<'isolate_scope, 'isolate>) -> Self { + unsafe { value.0.get_number() } + } +} -// pub enum V8LocalValue<'isolate_scope, 'isolate> { -// Array(LocalArray<'isolate_scope, 'isolate>), -// String(LocalValueString<'isolate_scope, 'isolate>), -// Number(LocalGeneric<'isolate_scope, 'isolate>), -// } +impl<'isolate_scope, 'isolate> TryFrom> for f64 { + type Error = &'static str; -/// JS generic persisted value -pub struct PersistValue { - pub(crate) inner_val: *mut v8_persisted_value, - forget: bool, + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + Ok(LocalValueDouble::try_from(val)?.into()) + } } -impl<'isolate_scope, 'isolate> LocalValueGeneric<'isolate_scope, 'isolate> { - /// Return string representation of the value or None on failure - #[must_use] - pub fn to_utf8(&self) -> Option> { - let inner_val = - unsafe { v8_ToUtf8(self.isolate_scope.isolate.inner_isolate, self.inner_val) }; - if inner_val.is_null() { - None - } else { - Some(LocalUtf8 { - inner_val, - _isolate_scope: self.isolate_scope, - }) +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueDouble<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_number() { + return Err("Value is not a number"); } - } - /// Return true if the value is string and false otherwise. - #[must_use] - pub fn is_string(&self) -> bool { - (unsafe { v8_ValueIsString(self.inner_val) } != 0) + Ok(Self(val)) } +} - /// Convert the object into a string, applicable only if the value is string. - #[must_use] - pub fn as_string(&self) -> LocalString<'isolate_scope, 'isolate> { - let inner_str = unsafe { v8_ValueAsString(self.inner_val) }; - LocalString { - inner_string: inner_str, - isolate_scope: self.isolate_scope, - } +/// An isolate-scoped [i64] local value in JavaScript. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalValueInteger<'isolate_scope, 'isolate>( + pub(crate) LocalValueAny<'isolate_scope, 'isolate>, +); + +impl<'isolate_scope, 'isolate> LocalValueInteger<'isolate_scope, 'isolate> { + fn new(value: i64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_ValueFromLong(isolate_scope.isolate.inner_isolate, value) }; + Self(LocalValueAny(ScopedValue { + inner_val, + isolate_scope, + })) } +} - /// Return true if the value is string object and false otherwise. - #[must_use] - pub fn is_string_object(&self) -> bool { - (unsafe { v8_ValueIsStringObject(self.inner_val) } != 0) +impl<'isolate_scope, 'isolate> From> for i64 { + fn from(value: LocalValueInteger<'isolate_scope, 'isolate>) -> Self { + unsafe { value.0.get_long() } } +} - /// Return true if the value is string and false otherwise. - #[must_use] - pub fn is_array(&self) -> bool { - (unsafe { v8_ValueIsArray(self.inner_val) } != 0) - } +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueInteger<'isolate_scope, 'isolate> +{ + type Error = &'static str; - /// Convert the object into a string, applicable only if the value is string. - #[must_use] - pub fn as_array(&self) -> LocalArray<'isolate_scope, 'isolate> { - let inner_array = unsafe { v8_ValueAsArray(self.inner_val) }; - LocalArray { - inner_array, - isolate_scope: self.isolate_scope, + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_long() { + return Err("Value is not a long"); } + + Ok(Self(val)) } +} - /// Return true if the value is string and false otherwise. - #[must_use] - pub fn is_array_buffer(&self) -> bool { - (unsafe { v8_ValueIsArrayBuffer(self.inner_val) } != 0) +/// An isolate-scoped [bool] local value in JavaScript. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalValueBoolean<'isolate_scope, 'isolate>( + pub(crate) LocalValueAny<'isolate_scope, 'isolate>, +); + +impl<'isolate_scope, 'isolate> LocalValueBoolean<'isolate_scope, 'isolate> { + fn new(value: bool, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewBool(isolate_scope.isolate.inner_isolate, value as i32) }; + Self(LocalValueAny(ScopedValue { + inner_val, + isolate_scope, + })) } +} - /// Convert the object into a string, applicable only if the value is string. - #[must_use] - pub fn as_array_buffer(&self) -> LocalArrayBuffer<'isolate_scope, 'isolate> { - let inner_array_buffer = unsafe { v8_ValueAsArrayBuffer(self.inner_val) }; - LocalArrayBuffer { - inner_array_buffer, - isolate_scope: self.isolate_scope, - } +impl<'isolate_scope, 'isolate> From> for bool { + fn from(value: LocalValueBoolean<'isolate_scope, 'isolate>) -> Self { + unsafe { value.0.get_boolean() } } +} - /// Return true if the value is null and false otherwise. - #[must_use] - pub fn is_null(&self) -> bool { - (unsafe { v8_ValueIsNull(self.inner_val) } != 0) +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueBoolean<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_boolean() { + return Err("Value is not a boolean"); + } + + Ok(Self(val)) } +} - /// Return true if the value is function and false otherwise. - #[must_use] - pub fn is_function(&self) -> bool { - (unsafe { v8_ValueIsFunction(self.inner_val) } != 0) +/// An isolate-scoped `null` local value in JavaScript. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalValueNull<'isolate_scope, 'isolate>( + pub(crate) LocalValueAny<'isolate_scope, 'isolate>, +); + +impl<'isolate_scope, 'isolate> LocalValueNull<'isolate_scope, 'isolate> { + fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewNull(isolate_scope.isolate.inner_isolate) }; + Self(LocalValueAny(ScopedValue { + inner_val, + isolate_scope, + })) } +} - /// Return true if the value is async function and false otherwise. - #[must_use] - pub fn is_async_function(&self) -> bool { - (unsafe { v8_ValueIsAsyncFunction(self.inner_val) } != 0) +impl<'isolate_scope, 'isolate> From<&'isolate_scope IsolateScope<'isolate>> + for LocalValueNull<'isolate_scope, 'isolate> +{ + fn from(value: &'isolate_scope IsolateScope<'isolate>) -> Self { + Self::new(value) } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueNull<'isolate_scope, 'isolate> +{ + type Error = &'static str; - /// Return true if the value is number and false otherwise. - #[must_use] - pub fn is_number(&self) -> bool { - (unsafe { v8_ValueIsNumber(self.inner_val) } != 0) + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_null() { + return Err("Value is not a null"); + } + + Ok(Self(val)) } +} + +/// All the possible values a JavaScript may have with which it is +/// possible to work. +#[derive(Debug, Clone)] +pub enum Value<'isolate_scope, 'isolate> { + /// See [LocalString]. + String(LocalString<'isolate_scope, 'isolate>), + /// See [LocalValueBoolean]. + Boolean(LocalValueBoolean<'isolate_scope, 'isolate>), + /// See [LocalValueInteger]. + Integer(LocalValueInteger<'isolate_scope, 'isolate>), + /// See [LocalValueDouble]. + Double(LocalValueDouble<'isolate_scope, 'isolate>), + /// See [LocalArrayBuffer]. + ArrayBuffer(LocalArrayBuffer<'isolate_scope, 'isolate>), + /// See [LocalArray]. + Array(LocalArray<'isolate_scope, 'isolate>), + /// See [LocalSet]. + Set(LocalSet<'isolate_scope, 'isolate>), + /// See [LocalObject]. + Object(LocalObject<'isolate_scope, 'isolate>), + /// See [LocalObjectTemplate]. + ObjectTemplate(LocalObjectTemplate<'isolate_scope, 'isolate>), + /// See [TryCatch]. + TryCatch(TryCatch<'isolate_scope, 'isolate>), + /// See [Unlocker]. + Unlocker(Unlocker<'isolate_scope, 'isolate>), + /// See [LocalNativeFunctionTemplate]. + NativeFunctionTemplate(LocalNativeFunctionTemplate<'isolate_scope, 'isolate>), + /// See [LocalValueNull]. + Null(LocalValueNull<'isolate_scope, 'isolate>), + /// See [LocalExternalData]. + ExternalData(LocalExternalData<'isolate_scope, 'isolate>), + /// See [LocalValueAny]. + Other(LocalValueAny<'isolate_scope, 'isolate>), +} - pub fn get_number(&self) -> f64 { - unsafe { v8_GetNumber(self.inner_val) } +impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { + /// Creates a new double local value from [f64] for the passed [IsolateScope]. + pub fn from_f64(value: f64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Double(LocalValueDouble::new(value, isolate_scope)) } - /// Return true if the value is number and false otherwise. - #[must_use] - pub fn is_long(&self) -> bool { - (unsafe { v8_ValueIsBigInt(self.inner_val) } != 0) + /// Creates a new integer local value from [i64] for the passed [IsolateScope]. + pub fn from_i64(value: i64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Integer(LocalValueInteger::new(value, isolate_scope)) } - pub fn get_long(&self) -> i64 { - unsafe { v8_GetBigInt(self.inner_val) } + /// Creates a new boolean local value from [bool] for the passed [IsolateScope]. + pub fn from_bool(value: bool, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Boolean(LocalValueBoolean::new(value, isolate_scope)) } - /// Return true if the value is boolean and false otherwise. - #[must_use] - pub fn is_boolean(&self) -> bool { - (unsafe { v8_ValueIsBool(self.inner_val) } != 0) + /// Creates a new local object for the passed [IsolateScope]. + pub fn new_object(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Object(LocalObject::new(isolate_scope)) } - pub fn get_boolean(&self) -> bool { - (unsafe { v8_GetBool(self.inner_val) } != 0) + /// Creates a new local object template for the passed [IsolateScope]. + pub fn new_object_template(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::ObjectTemplate(LocalObjectTemplate::new(isolate_scope)) } - /// Return true if the value is promise and false otherwise. - #[must_use] - pub fn is_promise(&self) -> bool { - (unsafe { v8_ValueIsPromise(self.inner_val) } != 0) + /// Creates a new null local object for the passed [IsolateScope]. + pub fn new_null(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Null(LocalValueNull::new(isolate_scope)) } - /// Convert the object into a promise, applicable only if the object is promise. - #[must_use] - pub fn as_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { - let inner_promise = unsafe { v8_ValueAsPromise(self.inner_val) }; - LocalPromise { - inner_promise, - isolate_scope: self.isolate_scope, - } + /// Creates a new local set for the passed [IsolateScope]. + pub fn new_set(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Set(LocalSet::new(isolate_scope)) } - /// Convert the object into a resolver, applicable only if the object is resolver. - #[must_use] - pub fn as_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { - let inner_resolver = unsafe { v8_ValueAsResolver(self.inner_val) }; - LocalResolver { - inner_resolver, - isolate_scope: self.isolate_scope, - } + /// Creates a new local string for the passed [IsolateScope]. + pub fn new_string(s: &str, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::String(LocalString::new(s, isolate_scope)) } - /// Return true if the value is object and false otherwise. - #[must_use] - pub fn is_object(&self) -> bool { - (unsafe { v8_ValueIsObject(self.inner_val) } != 0) + /// Creates a new local try catch for the passed [IsolateScope]. + pub fn new_try_catch(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::TryCatch(TryCatch::new(isolate_scope)) } - /// Convert the object into a promise, applicable only if the object is promise. - #[must_use] - pub fn as_object(&self) -> LocalObject<'isolate_scope, 'isolate> { - let inner_obj = unsafe { v8_ValueAsObject(self.inner_val) }; - LocalObject { - inner_obj, - isolate_scope: self.isolate_scope, - } + /// Creates a new local array buffer for the passed [IsolateScope]. + pub fn new_array_buffer( + bytes: &[u8], + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + Value::ArrayBuffer(LocalArrayBuffer::new(bytes, isolate_scope)) } - #[must_use] - pub fn is_external(&self) -> bool { - (unsafe { v8_ValueIsExternalData(self.inner_val) } != 0) + /// Creates a new local array for the passed [IsolateScope]. + pub fn new_array( + values: &[&LocalValueAny], + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + Value::Array(LocalArray::new(values, isolate_scope)) } - #[must_use] - pub fn as_external_data(&self) -> LocalExternalData<'isolate_scope, 'isolate> { - let inner_obj = unsafe { v8_ValueAsExternalData(self.inner_val) }; - LocalExternalData { - inner_ext: inner_obj, - isolate_scope: self.isolate_scope, - } + /// Creates a new unlocker for the passed [IsolateScope]. + pub fn new_unlocker(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + Value::Unlocker(Unlocker::new(isolate_scope)) } - /// Return true if the value is set and false otherwise. - #[must_use] - pub fn is_set(&self) -> bool { - (unsafe { v8_ValueIsSet(self.inner_val) } != 0) + /// Creates a new external data object for the passed [IsolateScope]. + pub fn new_external_data( + data: T, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + Value::ExternalData(LocalExternalData::new(data, isolate_scope)) + } + + /// Creates a new native function object for the passed [IsolateScope]. + pub fn new_native_function_template< + T: for<'d, 'c> Fn( + &LocalNativeFunctionArgs<'d, 'c>, + &'d IsolateScope<'c>, + &ContextScope<'d, 'c>, + ) -> Option>, + >( + function: T, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + Value::NativeFunctionTemplate(LocalNativeFunctionTemplate::new(function, isolate_scope)) } +} - /// Convert the object into a promise, applicable only if the object is promise. - #[must_use] - pub fn as_set(&self) -> LocalSet<'isolate_scope, 'isolate> { - let inner_set = unsafe { v8_ValueAsSet(self.inner_val) }; - LocalSet { - inner_set, - isolate_scope: self.isolate_scope, +impl<'isolate_scope, 'isolate> From> + for Value<'isolate_scope, 'isolate> +{ + fn from(value: LocalValueAny<'isolate_scope, 'isolate>) -> Self { + // TODO rewrite better than this. + match value.get_type() { + Some(Type::Array) => { + Self::Array(LocalArray::try_from(value).expect("Conversion error")) + } + Some(Type::ArrayBuffer) => { + Self::ArrayBuffer(LocalArrayBuffer::try_from(value).expect("Conversion error")) + } + Some(Type::String) => { + Self::String(LocalString::try_from(value).expect("Conversion error")) + } + Some(Type::Integer) => { + Self::Integer(LocalValueInteger::try_from(value).expect("Conversion error")) + } + Some(Type::Double) => { + Self::Double(LocalValueDouble::try_from(value).expect("Conversion error")) + } + Some(Type::Set) => Self::Set(LocalSet::try_from(value).expect("Conversion error")), + Some(Type::Object) => { + Self::Object(LocalObject::try_from(value).expect("Conversion error")) + } + Some(Type::Null) => { + Self::Null(LocalValueNull::try_from(value).expect("Conversion error")) + } + Some(Type::ExternalData) => { + Self::ExternalData(LocalExternalData::try_from(value).expect("Conversion error")) + } + _ => Self::Other(value), } } +} - /// Persist the local object so it can be saved beyond the current handlers scope. - #[must_use] - pub fn persist(&self) -> PersistValue { - let inner_val = - unsafe { v8_PersistValue(self.isolate_scope.isolate.inner_isolate, self.inner_val) }; - PersistValue { - inner_val, - forget: false, +impl<'isolate_scope, 'isolate> TryFrom> + for LocalString<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::String(ls) => Ok(ls), + Value::Other(any) => any.try_into(), + _ => Err("Value is not a string."), } } +} - /// Run the value, applicable only if the value is a function or async function. - #[must_use] - pub fn call(&self, ctx: &ContextScope, args: Option<&[&Self]>) -> Option { - let res = match args { - Some(args) => { - let args = args - .iter() - .map(|v| v.inner_val) - .collect::>(); - let ptr = args.as_ptr(); - unsafe { v8_FunctionCall(ctx.inner_ctx_ref, self.inner_val, args.len(), ptr) } - } - None => unsafe { v8_FunctionCall(ctx.inner_ctx_ref, self.inner_val, 0, ptr::null()) }, - }; +impl<'isolate_scope, 'isolate> TryFrom> + for LocalUtf8<'isolate_scope, 'isolate> +{ + type Error = &'static str; - if res.is_null() { - None - } else { - Some(Self { - inner_val: res, - isolate_scope: self.isolate_scope, - }) + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::String(s) => LocalValueAny::from(s).try_into(), + Value::Other(any) => any.try_into(), + _ => Err("Value is not string"), } } } -impl PersistValue { - /// Convert the persisted value back to local value. - #[must_use] - pub fn as_local<'isolate, 'isolate_scope>( - &self, - isolate_scope: &'isolate_scope IsolateScope<'isolate>, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - assert!(!self.inner_val.is_null()); - let inner_val = unsafe { - v8_PersistedValueToLocal(isolate_scope.isolate.inner_isolate, self.inner_val) - }; - LocalValueGeneric { - inner_val, - isolate_scope, +impl<'isolate_scope, 'isolate> TryFrom> + for LocalPromise<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + if let Value::Other(any) = val { + if any.is_promise() { + return Ok(unsafe { any.as_promise() }); + } } + Err("Value is not a promise") } +} - pub fn forget(&mut self) { - assert!(!self.inner_val.is_null()); - self.forget = true; - } +impl<'isolate_scope, 'isolate> TryFrom> + for LocalObjectTemplate<'isolate_scope, 'isolate> +{ + type Error = &'static str; - pub fn take_local<'isolate, 'isolate_scope>( - &mut self, - isolate_scope: &'isolate_scope IsolateScope<'isolate>, - ) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let val = self.as_local(isolate_scope); - unsafe { v8_FreePersistedValue(self.inner_val) } - self.forget(); - self.inner_val = ptr::null_mut(); - val + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + if let Value::ObjectTemplate(object_template) = val { + Ok(object_template) + } else { + Err("Value is not a promise") + } } } -unsafe impl Sync for PersistValue {} -unsafe impl Send for PersistValue {} +impl<'isolate_scope, 'isolate> TryFrom> + for TryCatch<'isolate_scope, 'isolate> +{ + type Error = &'static str; -impl<'isolate_scope, 'isolate> Drop for LocalValueGeneric<'isolate_scope, 'isolate> { - fn drop(&mut self) { - if !self.inner_val.is_null() { - unsafe { v8_FreeValue(self.inner_val) } + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + if let Value::TryCatch(tc) = val { + Ok(tc) + } else { + Err("Value is not a try catch") } } } -impl Drop for PersistValue { - fn drop(&mut self) { - if self.forget { - return; +impl<'isolate_scope, 'isolate> TryFrom> + for LocalNativeFunctionTemplate<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + if let Value::NativeFunctionTemplate(t) = val { + Ok(t) + } else { + Err("Value is not a local function template") } - unsafe { v8_FreePersistedValue(self.inner_val) } } } -impl<'isolate_scope, 'isolate> TryFrom> for i64 { +impl<'isolate_scope, 'isolate> TryFrom> for bool { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { - if !val.is_long() { - return Err("Value is not long"); - } + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + Ok(match val { + Value::Boolean(b) => b.into(), + Value::Other(any) => { + if !any.is_boolean() { + return Err("Value is not a boolean."); + } - Ok(val.get_long()) + unsafe { any.get_boolean() } + } + _ => return Err("Value is not a long."), + }) } } -impl<'isolate_scope, 'isolate> TryFrom> for f64 { +impl<'isolate_scope, 'isolate> TryFrom> for i64 { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { - if !val.is_number() { - return Err("Value is not number"); - } + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + Ok(match val { + Value::Integer(i) => i.into(), + Value::Other(any) => { + if !any.is_long() { + return Err("Value is not a long."); + } - Ok(val.get_number()) + unsafe { any.get_long() } + } + _ => return Err("Value is not a long."), + }) } } -impl<'isolate_scope, 'isolate> TryFrom> for String { +impl<'isolate_scope, 'isolate> TryFrom> for f64 { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { - if !val.is_string() && !val.is_string_object() { - return Err("Value is not string"); - } + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + Ok(match val { + Value::Double(f) => f.into(), + Value::Other(any) => { + if !any.is_number() { + return Err("Value is not a number"); + } - let v8_utf8 = match val.to_utf8() { - Some(val) => val, - None => return Err("Failed converting to utf8"), - }; - Ok(v8_utf8.as_str().to_string()) + unsafe { any.get_number() } + } + _ => return Err("Value is not a number."), + }) } } -impl<'isolate_scope, 'isolate> TryFrom> for bool { +impl<'isolate_scope, 'isolate> TryFrom> for String { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { - if !val.is_boolean() { - return Err("Value is not a boolean"); + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::String(ls) => Ok(LocalUtf8::from(ls).into()), + // Value::Object(o) => String::try_from(o), + Value::Other(any) => String::try_from(any), + _ => Err("Value is not a string."), } - - Ok(val.get_boolean()) } } -// impl<'isolate_scope, 'isolate> TryFrom> for V8LocalValue<'isolate_scope, 'isolate> -// { -// type Error = &'static str; +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueAny<'isolate_scope, 'isolate> +{ + type Error = &'static str; -// fn try_from(val: V8LocalValue<'isolate_scope, 'isolate>) -> Result { -// Ok(val) -// } -// } + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::Array(array) => Ok(array.into()), + Value::ArrayBuffer(array_buffer) => Ok(array_buffer.into()), + Value::Boolean(boolean) => Ok(boolean.0), + Value::Integer(integer) => Ok(integer.0), + Value::Double(double) => Ok(double.0), + Value::Null(null) => Ok(null.0), + Value::String(string) => Ok(string.into()), + Value::Set(set) => Ok(set.into()), + Value::Object(object) => Ok(object.into()), + // LocalValue::ObjectTemplate(object_template) => Ok(object_template.into()), + // LocalValue::TryCatch(try_catch) => Ok(try_catch.into()), + // LocalValue::Unlocker(unlocker) => Ok(unlocker.into()), + // LocalValue::NativeFunctionTemplate(native_function_template) => { + // Ok(native_function_template.into()) + // } + Value::ExternalData(external_data) => Ok(external_data.into()), + Value::Other(any) => Ok(any), + _ => Err("Couldn't convert to any"), + } + } +} macro_rules! from_iter_impl { ( $x:ty ) => { @@ -464,11 +558,12 @@ macro_rules! from_iter_impl { TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for $x { type Error = &'static str; + fn try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { match val.next() { - Some(val) => val.try_into(), + Some(val) => std::convert::TryInto::<$x>::try_into(val), None => Err("Wrong number of arguments given".into()), } } @@ -488,9 +583,10 @@ from_iter_impl!(LocalUtf8<'isolate_scope, 'isolate>); impl<'isolate_scope, 'isolate, 'a> TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for LocalValueGeneric<'isolate_scope, 'isolate> + for Value<'isolate_scope, 'isolate> { type Error = &'static str; + fn try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { @@ -501,9 +597,10 @@ impl<'isolate_scope, 'isolate, 'a> impl<'isolate_scope, 'isolate, 'a, T> OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for T where - T: TryFrom, Error = &'static str>, + T: TryFrom, Error = &'static str>, { type Error = &'static str; + fn optional_try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result, Self::Error> { @@ -511,15 +608,18 @@ where Some(v) => v, None => return Ok(None), }; - val.try_into().map(|v| Some(v)) + let val = LocalValueAny::try_from(val)?; + let val = val.try_into()?; + Ok(Some(val)) } } impl<'isolate_scope, 'isolate, 'a> OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for LocalValueGeneric<'isolate_scope, 'isolate> + for Value<'isolate_scope, 'isolate> { type Error = &'static str; + fn optional_try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result, Self::Error> { @@ -527,34 +627,48 @@ impl<'isolate_scope, 'isolate, 'a> } } -impl<'isolate_scope, 'isolate, 'a, T> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec -where - T: TryFrom, Error = &'static str>, +// impl<'isolate_scope, 'isolate, 'a, T> +// TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec +// where +// T: TryFrom, Error = &'static str>, +// { +// type Error = &'static str; + +// fn try_from( +// val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, +// ) -> Result { +// let mut res = Self::new(); +// for v in val { +// let v = LocalValueAny::try_from(v)?.try_into()?; +// res.push(v); +// } +// Ok(res) +// } +// } + +impl<'isolate_scope, 'isolate, 'a> + TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> + for Vec> { type Error = &'static str; + fn try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { - let mut res = Self::new(); - for v in val { - match v.try_into() { - Ok(v) => res.push(v), - Err(e) => return Err(e), - } - } - Ok(res) + Ok(val.collect()) } } -impl<'isolate_scope, 'isolate, 'a> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> - for Vec> +impl<'isolate_scope, 'isolate, 'a, T> + TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec +where + T: TryFrom, Error = &'static str>, { type Error = &'static str; + fn try_from( val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { - Ok(val.collect()) + Ok(val.map(|v| T::try_from(v).unwrap()).collect()) } } diff --git a/src/v8/types/module.rs b/src/v8/types/module.rs index f1bbe17..9cbab3f 100644 --- a/src/v8/types/module.rs +++ b/src/v8/types/module.rs @@ -15,15 +15,17 @@ use crate::v8::context_scope::ContextScope; use crate::v8::isolate::Isolate; use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::LocalString; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; use std::os::raw::c_int; use std::ptr; +use super::any::LocalValueAny; +use super::Value; + /// JS script object -pub struct LocalModule<'isolate_scope, 'isolate> { - pub(crate) inner_module: *mut v8_local_module, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +pub struct LocalModule<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_module>, +); pub struct PersistedModule { pub(crate) inner_persisted_module: *mut v8_persisted_module, @@ -51,16 +53,16 @@ pub(crate) extern "C" fn load_module< exit_on_drop: false, isolate_scope: &isolate_scope, }; - let name_obj = LocalString { - inner_string: name, + let name_obj = LocalString(ScopedValue { + inner_val: name, isolate_scope: &isolate_scope, - }; + }); let load_callback: &T = ctx_scope.get_private_data_mut_raw(RawIndex(0)).unwrap(); let res = load_callback(&isolate_scope, &ctx_scope, &name_obj, identity_hash as i64); match res { Some(mut r) => { - let inner_module = r.inner_module; - r.inner_module = ptr::null_mut(); + let inner_module = r.0.inner_val; + r.0.inner_val = ptr::null_mut(); inner_module } None => ptr::null_mut(), @@ -83,7 +85,7 @@ impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { ctx_scope.set_private_data_raw(RawIndex(0), &load_module_callback); let res = unsafe { v8_InitiateModule( - self.inner_module, + self.0.inner_val, ctx_scope.inner_ctx_ref, Some(load_module::), ) @@ -92,33 +94,32 @@ impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { res != 0 } - pub fn evaluate( - &self, - ctx_scope: &ContextScope, - ) -> Option> { - let res = unsafe { v8_EvaluateModule(self.inner_module, ctx_scope.inner_ctx_ref) }; + pub fn evaluate(&self, ctx_scope: &ContextScope) -> Option> { + let res = unsafe { v8_EvaluateModule(self.0.inner_val, ctx_scope.inner_ctx_ref) }; if res.is_null() { None } else { - Some(LocalValueGeneric { - inner_val: res, - isolate_scope: self.isolate_scope, - }) + Some( + LocalValueAny(ScopedValue { + inner_val: res, + isolate_scope: self.0.isolate_scope, + }) + .into(), + ) } } /// Convert the module into a generic JS value - #[must_use] pub fn persist(&self, isolate: &Isolate) -> PersistedModule { let inner_persisted_module = - unsafe { v8_ModulePersist(isolate.inner_isolate, self.inner_module) }; + unsafe { v8_ModulePersist(isolate.inner_isolate, self.0.inner_val) }; PersistedModule { inner_persisted_module, } } pub fn get_identity_hash(&self) -> i64 { - unsafe { v8_ModuleGetIdentityHash(self.inner_module) as i64 } + unsafe { v8_ModuleGetIdentityHash(self.0.inner_val) as i64 } } } @@ -127,23 +128,23 @@ impl PersistedModule { &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> LocalModule<'isolate_scope, 'isolate> { - let inner_module = unsafe { + let inner_val = unsafe { v8_ModuleToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_module, ) }; - LocalModule { - inner_module, + LocalModule(ScopedValue { + inner_val, isolate_scope, - } + }) } } impl<'isolate_scope, 'isolate> Drop for LocalModule<'isolate_scope, 'isolate> { fn drop(&mut self) { - if !self.inner_module.is_null() { - unsafe { v8_FreeModule(self.inner_module) } + if !self.0.inner_val.is_null() { + unsafe { v8_FreeModule(self.0.inner_val) } } } } diff --git a/src/v8/types/native_function.rs b/src/v8/types/native_function.rs index c3b09f5..9159cee 100644 --- a/src/v8/types/native_function.rs +++ b/src/v8/types/native_function.rs @@ -8,29 +8,42 @@ use crate::v8_c_raw::bindings::{ v8_FreeNativeFunction, v8_NativeFunctionToValue, v8_local_native_function, }; -use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::any::LocalValueAny; +use super::Value; /// Native function object -pub struct LocalNativeFunction<'isolate_scope, 'isolate> { - pub(crate) inner_func: *mut v8_local_native_function, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, +pub struct LocalNativeFunction<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_native_function>, +); + +impl<'isolate_scope, 'isolate> Drop for LocalNativeFunction<'isolate_scope, 'isolate> { + fn drop(&mut self) { + unsafe { v8_FreeNativeFunction(self.0.inner_val) } + } } -impl<'isolate_scope, 'isolate> LocalNativeFunction<'isolate_scope, 'isolate> { - /// Convert the native function into a JS generic value - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_NativeFunctionToValue(self.inner_func) }; - LocalValueGeneric { +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from( + value: LocalNativeFunction<'isolate_scope, 'isolate>, + ) -> LocalValueAny<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_NativeFunctionToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> Drop for LocalNativeFunction<'isolate_scope, 'isolate> { - fn drop(&mut self) { - unsafe { v8_FreeNativeFunction(self.inner_func) } +impl<'isolate_scope, 'isolate> From> + for Value<'isolate_scope, 'isolate> +{ + fn from( + value: LocalNativeFunction<'isolate_scope, 'isolate>, + ) -> Value<'isolate_scope, 'isolate> { + LocalValueAny::from(value).into() } } diff --git a/src/v8/types/native_function_template.rs b/src/v8/types/native_function_template.rs index a14f327..17615ef 100644 --- a/src/v8/types/native_function_template.rs +++ b/src/v8/types/native_function_template.rs @@ -4,6 +4,7 @@ * the Server Side Public License v1 (SSPLv1). */ +use crate::v8_c_raw::bindings::v8_NewNativeFunctionTemplate; use crate::v8_c_raw::bindings::{ v8_ArgsGet, v8_ArgsGetSelf, v8_FreeNativeFunctionTemplate, v8_GetCurrentCtxRef, v8_GetCurrentIsolate, v8_NativeFunctionTemplateToFunction, v8_local_native_function_template, @@ -18,12 +19,44 @@ use crate::v8::isolate::Isolate; use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::native_function::LocalNativeFunction; use crate::v8::types::LocalObject; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// Native function template object -pub struct LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { - pub(crate) inner_func: *mut v8_local_native_function_template, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, +use super::any::LocalValueAny; +use super::Value; + +/// Native function template object. +#[derive(Debug, Clone)] +pub struct LocalNativeFunctionTemplate<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_native_function_template>, +); + +impl<'isolate_scope, 'isolate> LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { + /// Creates a new local native function template within the + /// provided [IsolateScope]. + pub fn new< + T: for<'d, 'e> Fn( + &LocalNativeFunctionArgs<'d, 'e>, + &'d IsolateScope<'e>, + &ContextScope<'d, 'e>, + ) -> Option>, + >( + function: T, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> Self { + let inner_val = unsafe { + v8_NewNativeFunctionTemplate( + isolate_scope.isolate.inner_isolate, + Some(native_basic_function::), + Box::into_raw(Box::new(function)).cast(), + Some(free_pd::), + ) + }; + + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } } /// Native function args @@ -38,7 +71,7 @@ pub(crate) extern "C" fn free_pd< &LocalNativeFunctionArgs<'d, 'c>, &'d IsolateScope<'c>, &ContextScope<'d, 'c>, - ) -> Option>, + ) -> Option>, >( pd: *mut c_void, ) { @@ -52,7 +85,7 @@ pub(crate) extern "C" fn native_basic_function< &LocalNativeFunctionArgs<'d, 'c>, &'d IsolateScope<'c>, &ContextScope<'d, 'c>, - ) -> Option>, + ) -> Option>, >( args: *mut v8_local_value_arr, len: usize, @@ -85,8 +118,8 @@ pub(crate) extern "C" fn native_basic_function< match res { Some(mut r) => { - let inner_val = r.inner_val; - r.inner_val = ptr::null_mut(); + let inner_val = r.0.inner_val; + r.0.inner_val = ptr::null_mut(); inner_val } None => ptr::null_mut(), @@ -98,13 +131,13 @@ impl<'isolate_scope, 'isolate> LocalNativeFunctionTemplate<'isolate_scope, 'isol &self, ctx_scope: &ContextScope, ) -> LocalNativeFunction<'isolate_scope, 'isolate> { - let inner_func = unsafe { - v8_NativeFunctionTemplateToFunction(ctx_scope.inner_ctx_ref, self.inner_func) + let inner_val = unsafe { + v8_NativeFunctionTemplateToFunction(ctx_scope.inner_ctx_ref, self.0.inner_val) }; - LocalNativeFunction { - inner_func, - isolate_scope: self.isolate_scope, - } + LocalNativeFunction(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) } } @@ -112,13 +145,14 @@ impl<'isolate_scope, 'isolate> LocalNativeFunctionArgs<'isolate_scope, 'isolate> /// Return the i-th argument from the native function args /// # Panics #[must_use] - pub fn get(&self, i: usize) -> LocalValueGeneric<'isolate_scope, 'isolate> { + pub fn get(&self, i: usize) -> Value<'isolate_scope, 'isolate> { assert!(i <= self.len); let val = unsafe { v8_ArgsGet(self.inner_arr, i) }; - LocalValueGeneric { + LocalValueAny(ScopedValue { inner_val: val, isolate_scope: self.isolate_scope, - } + }) + .into() } /// Return the amount of arguments passed to the native function @@ -136,11 +170,11 @@ impl<'isolate_scope, 'isolate> LocalNativeFunctionArgs<'isolate_scope, 'isolate> /// Checks if the list of args is empty #[must_use] pub fn get_self(&self) -> LocalObject<'isolate_scope, 'isolate> { - let val = unsafe { v8_ArgsGetSelf(self.inner_arr) }; - LocalObject { - inner_obj: val, + let inner_val = unsafe { v8_ArgsGetSelf(self.inner_arr) }; + LocalObject(ScopedValue { + inner_val, isolate_scope: self.isolate_scope, - } + }) } pub const fn persist(&self) {} @@ -161,7 +195,7 @@ pub struct V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { impl<'isolate_scope, 'isolate, 'a> Iterator for V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { - type Item = LocalValueGeneric<'isolate_scope, 'isolate>; + type Item = Value<'isolate_scope, 'isolate>; fn next(&mut self) -> Option { if self.index >= self.args.len() { return None; @@ -174,6 +208,6 @@ impl<'isolate_scope, 'isolate, 'a> Iterator impl<'isolate_scope, 'isolate> Drop for LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeNativeFunctionTemplate(self.inner_func) } + unsafe { v8_FreeNativeFunctionTemplate(self.0.inner_val) } } } diff --git a/src/v8/types/object.rs b/src/v8/types/object.rs index f477e59..4b0ad70 100644 --- a/src/v8/types/object.rs +++ b/src/v8/types/object.rs @@ -5,7 +5,7 @@ */ use crate::v8_c_raw::bindings::{ - v8_FreeObject, v8_GetInternalFieldCount, v8_ObjectFreeze, v8_ObjectGet, + v8_FreeObject, v8_GetInternalFieldCount, v8_NewObject, v8_ObjectFreeze, v8_ObjectGet, v8_ObjectGetInternalField, v8_ObjectSet, v8_ObjectSetInternalField, v8_ObjectToValue, v8_ValueGetPropertyNames, v8_local_object, }; @@ -14,52 +14,69 @@ use crate::v8::context_scope::ContextScope; use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::native_function_template::LocalNativeFunctionArgs; use crate::v8::types::LocalArray; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object -pub struct LocalObject<'isolate_scope, 'isolate> { - pub(crate) inner_obj: *mut v8_local_object, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::string::LocalString; +use super::{LocalValueAny, Value}; + +/// A JavaScript object. +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct LocalObject<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_object>, +); impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { - /// Return the value of a given key + /// Creates a new local object within the provided [IsolateScope]. + pub fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewObject(isolate_scope.isolate.inner_isolate) }; + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } + + /// Returns the value of a given key. #[must_use] pub fn get( &self, ctx_scope: &ContextScope, - key: &LocalValueGeneric, - ) -> Option> { + key: &LocalValueAny<'isolate_scope, 'isolate>, + ) -> Option> { let inner_val = - unsafe { v8_ObjectGet(ctx_scope.inner_ctx_ref, self.inner_obj, key.inner_val) }; + unsafe { v8_ObjectGet(ctx_scope.inner_ctx_ref, self.0.inner_val, key.0.inner_val) }; if inner_val.is_null() { None } else { - Some(LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - }) + Some( + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + .into(), + ) } } - /// Sugar for get that recieve the field name as &str + /// Get value of a field by string. #[must_use] pub fn get_str_field( &self, ctx_scope: &ContextScope, key: &str, - ) -> Option> { - let key = self.isolate_scope.new_string(key); - self.get(ctx_scope, &key.to_value()) + ) -> Option> { + let key: LocalString = self.0.isolate_scope.create_string(key).try_into().unwrap(); + let key = LocalValueAny::from(key); + self.get(ctx_scope, &key) } - pub fn set(&self, ctx_scope: &ContextScope, key: &LocalValueGeneric, val: &LocalValueGeneric) { + pub fn set(&self, ctx_scope: &ContextScope, key: &LocalValueAny, val: &LocalValueAny) { unsafe { v8_ObjectSet( ctx_scope.inner_ctx_ref, - self.inner_obj, - key.inner_val, - val.inner_val, + self.0.inner_val, + key.0.inner_val, + val.0.inner_val, ) }; } @@ -69,88 +86,104 @@ impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { &LocalNativeFunctionArgs<'d, 'e>, &'d IsolateScope<'e>, &ContextScope<'d, 'e>, - ) -> Option>, + ) -> Option>, >( &self, ctx_scope: &ContextScope, key: &str, func: T, ) { - let native_function = ctx_scope.new_native_function(func).to_value(); - let name = self.isolate_scope.new_string(key).to_value(); + let native_function = + LocalValueAny::try_from(ctx_scope.create_native_function(func)).unwrap(); + let name: LocalString = self.0.isolate_scope.create_string(key).try_into().unwrap(); + let name = LocalValueAny::from(name); unsafe { v8_ObjectSet( ctx_scope.inner_ctx_ref, - self.inner_obj, - name.inner_val, - native_function.inner_val, + self.0.inner_val, + name.0.inner_val, + native_function.0.inner_val, ) }; } - pub fn set_internal_field(&self, index: usize, val: &LocalValueGeneric) { - unsafe { v8_ObjectSetInternalField(self.inner_obj, index, val.inner_val) }; + pub fn set_internal_field(&self, index: usize, val: &LocalValueAny) { + unsafe { v8_ObjectSetInternalField(self.0.inner_val, index, val.0.inner_val) }; } - #[must_use] - pub fn get_internal_field(&self, index: usize) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ObjectGetInternalField(self.inner_obj, index) }; - LocalValueGeneric { + pub fn get_internal_field(&self, index: usize) -> Value<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_ObjectGetInternalField(self.0.inner_val, index) }; + LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: self.0.isolate_scope, + }) + .into() } - #[must_use] pub fn get_internal_field_count(&self) -> usize { - unsafe { v8_GetInternalFieldCount(self.inner_obj) } - } - - /// Convert the object into a generic JS value - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ObjectToValue(self.inner_obj) }; - LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - } + unsafe { v8_GetInternalFieldCount(self.0.inner_val) } } pub fn freeze(&self, ctx_scope: &ContextScope) { - unsafe { v8_ObjectFreeze(ctx_scope.inner_ctx_ref, self.inner_obj) }; + unsafe { v8_ObjectFreeze(ctx_scope.inner_ctx_ref, self.0.inner_val) }; } /// Convert the object into a generic JS value - #[must_use] pub fn get_property_names( &self, ctx_scope: &ContextScope, ) -> LocalArray<'isolate_scope, 'isolate> { - let inner_array = - unsafe { v8_ValueGetPropertyNames(ctx_scope.inner_ctx_ref, self.inner_obj) }; - LocalArray { - inner_array, - isolate_scope: self.isolate_scope, - } + let inner_val = + unsafe { v8_ValueGetPropertyNames(ctx_scope.inner_ctx_ref, self.0.inner_val) }; + LocalArray(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) } } impl<'isolate_scope, 'isolate> Drop for LocalObject<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeObject(self.inner_obj) } + unsafe { v8_FreeObject(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalObject<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_ObjectToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> TryFrom> +impl<'isolate_scope, 'isolate> TryFrom> for LocalObject<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { if !val.is_object() { return Err("Value is not an object"); } - Ok(val.as_object()) + Ok(unsafe { val.as_object() }) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalObject<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::Object(object) => Ok(object), + Value::Other(any) => Self::try_from(any), + _ => Err("Value is not an object"), + } } } diff --git a/src/v8/types/object_template.rs b/src/v8/types/object_template.rs index 6a71403..1155d4d 100644 --- a/src/v8/types/object_template.rs +++ b/src/v8/types/object_template.rs @@ -5,10 +5,10 @@ */ use crate::v8_c_raw::bindings::{ - v8_FreeObjectTemplate, v8_FreePersistedObjectTemplate, v8_ObjectTemplateNewInstance, - v8_ObjectTemplatePersist, v8_ObjectTemplateSetFunction, v8_ObjectTemplateSetInternalFieldCount, - v8_ObjectTemplateSetObject, v8_ObjectTemplateSetValue, v8_PersistedObjectTemplateToLocal, - v8_local_object_template, v8_persisted_object_template, + v8_FreeObjectTemplate, v8_FreePersistedObjectTemplate, v8_NewObjectTemplate, + v8_ObjectTemplateNewInstance, v8_ObjectTemplatePersist, v8_ObjectTemplateSetFunction, + v8_ObjectTemplateSetInternalFieldCount, v8_ObjectTemplateSetObject, v8_ObjectTemplateSetValue, + v8_PersistedObjectTemplateToLocal, v8_local_object_template, v8_persisted_object_template, }; use crate::v8::context_scope::ContextScope; @@ -18,18 +18,30 @@ use crate::v8::types::native_function_template::{ }; use crate::v8::types::object::LocalObject; use crate::v8::types::string::LocalString; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object template -pub struct LocalObjectTemplate<'isolate_scope, 'isolate> { - pub(crate) inner_obj: *mut v8_local_object_template, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::any::LocalValueAny; + +/// JS object template. +#[derive(Debug, Clone)] +pub struct LocalObjectTemplate<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_object_template>, +); impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { + /// Creates a new object template. + pub fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewObjectTemplate(isolate_scope.isolate.inner_isolate) }; + LocalObjectTemplate(ScopedValue { + inner_val, + isolate_scope, + }) + } /// Set a native function to the object template as a given key pub fn set_native_function(&mut self, name: &LocalString, func: &LocalNativeFunctionTemplate) { - unsafe { v8_ObjectTemplateSetFunction(self.inner_obj, name.inner_string, func.inner_func) }; + unsafe { + v8_ObjectTemplateSetFunction(self.0.inner_val, name.0.inner_val, func.0.inner_val) + }; } /// Same as `set_native_function` but gets the key as &str and the native function as closure. @@ -38,57 +50,62 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { &LocalNativeFunctionArgs<'d, 'e>, &'d IsolateScope<'e>, &ContextScope<'d, 'e>, - ) -> Option>, + ) -> Option>, >( &mut self, name: &str, func: T, ) { - let native_func = self.isolate_scope.new_native_function_template(func); - let func_name = self.isolate_scope.new_string(name); + let native_func = self + .0 + .isolate_scope + .create_native_function_template(func) + .try_into() + .unwrap(); + let func_name = self.0.isolate_scope.create_string(name).try_into().unwrap(); self.set_native_function(&func_name, &native_func); } /// Set the given object to the object template on a given key pub fn set_object(&mut self, name: &LocalString, obj: &Self) { - unsafe { v8_ObjectTemplateSetObject(self.inner_obj, name.inner_string, obj.inner_obj) }; + unsafe { v8_ObjectTemplateSetObject(self.0.inner_val, name.0.inner_val, obj.0.inner_val) }; } pub fn set_internal_field_count(&mut self, count: usize) { - unsafe { v8_ObjectTemplateSetInternalFieldCount(self.inner_obj, count) }; + unsafe { v8_ObjectTemplateSetInternalFieldCount(self.0.inner_val, count) }; } /// Same as `set_object` but gets the key as &str pub fn add_object(&mut self, name: &str, obj: &Self) { - let obj_name = self.isolate_scope.new_string(name); + let obj_name = self.0.isolate_scope.create_string(name).try_into().unwrap(); self.set_object(&obj_name, obj); } /// Set a generic JS value into the object template as a given key - pub fn set_value(&mut self, name: &LocalString, obj: &LocalValueGeneric) { - unsafe { v8_ObjectTemplateSetValue(self.inner_obj, name.inner_string, obj.inner_val) }; + pub fn set_value(&mut self, name: &LocalString, obj: &LocalValueAny) { + unsafe { v8_ObjectTemplateSetValue(self.0.inner_val, name.0.inner_val, obj.0.inner_val) }; } /// Same as `set_value` but gets the key as &str - pub fn add_value(&mut self, name: &str, obj: &LocalValueGeneric) { - let val_name = self.isolate_scope.new_string(name); + pub fn add_value(&mut self, name: &str, obj: &LocalValueAny) { + let val_name = self.0.isolate_scope.create_string(name).try_into().unwrap(); self.set_value(&val_name, obj); } /// Convert the object template into a generic JS value #[must_use] pub fn new_instance(&self, ctx_scope: &ContextScope) -> LocalObject<'isolate_scope, 'isolate> { - let inner_obj = - unsafe { v8_ObjectTemplateNewInstance(ctx_scope.inner_ctx_ref, self.inner_obj) }; - LocalObject { - inner_obj, - isolate_scope: self.isolate_scope, - } + let inner_val = + unsafe { v8_ObjectTemplateNewInstance(ctx_scope.inner_ctx_ref, self.0.inner_val) }; + LocalObject(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) } pub fn persist(&self) -> V8PersistedObjectTemplate { let inner_persist = unsafe { - v8_ObjectTemplatePersist(self.isolate_scope.isolate.inner_isolate, self.inner_obj) + v8_ObjectTemplatePersist(self.0.isolate_scope.isolate.inner_isolate, self.0.inner_val) }; V8PersistedObjectTemplate { inner_persisted_obj_template: inner_persist, @@ -98,7 +115,7 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { impl<'isolate_scope, 'isolate> Drop for LocalObjectTemplate<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeObjectTemplate(self.inner_obj) } + unsafe { v8_FreeObjectTemplate(self.0.inner_val) } } } @@ -111,16 +128,16 @@ impl V8PersistedObjectTemplate { &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> LocalObjectTemplate<'isolate_scope, 'isolate> { - let inner_obj = unsafe { + let inner_val = unsafe { v8_PersistedObjectTemplateToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_obj_template, ) }; - LocalObjectTemplate { - inner_obj, + LocalObjectTemplate(ScopedValue { + inner_val, isolate_scope, - } + }) } } diff --git a/src/v8/types/persistent.rs b/src/v8/types/persistent.rs new file mode 100644 index 0000000..aa45bec --- /dev/null +++ b/src/v8/types/persistent.rs @@ -0,0 +1,92 @@ +/* + * Copyright Redis Ltd. 2022 - present + * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or + * the Server Side Public License v1 (SSPLv1). + */ +//! This is an abstraction over a persistent (non-scoped) V8 value. +//! As this is a fully abstract class in V8, the objects it can hold +//! can be of any javascript type. Hence it is generic. + +use crate::{ + v8::isolate_scope::IsolateScope, + v8_c_raw::bindings::{v8_FreePersistedValue, v8_PersistedValueToLocal, v8_persisted_value}, +}; + +use super::{any::LocalValueAny, ScopedValue}; + +/// JS generic persisted value +pub struct PersistValue { + pub(crate) inner_val: *mut v8_persisted_value, + forget: bool, +} + +impl PersistValue { + /// Converts the persisted value back to local value. + /// + /// # Panics + /// + /// Panics when the inner value is a null pointer. + #[must_use] + pub fn as_local<'isolate, 'isolate_scope>( + &self, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalValueAny<'isolate_scope, 'isolate> { + assert!(!self.inner_val.is_null()); + let inner_val = unsafe { + v8_PersistedValueToLocal(isolate_scope.isolate.inner_isolate, self.inner_val) + }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope, + }) + } + + /// Disables the [Drop] implementation for this object, marking it + /// as a non-requiring to be dropped. + /// + /// # Panics + /// + /// Panics when the inner value is a null pointer. + pub fn forget(&mut self) { + assert!(!self.inner_val.is_null()); + self.forget = true; + } + + /// Consumes the current persistent value and attempts to convert it + /// into a local value. The object isn't dropped. + /// + /// # Panics + /// + /// Panics when the inner value is a null pointer, see [Self::as_local]. + pub fn take_local<'isolate, 'isolate_scope>( + mut self, + isolate_scope: &'isolate_scope IsolateScope<'isolate>, + ) -> LocalValueAny<'isolate_scope, 'isolate> { + let val = self.as_local(isolate_scope); + unsafe { v8_FreePersistedValue(self.inner_val) } + self.forget(); + self.inner_val = std::ptr::null_mut(); + val + } +} + +impl From<*mut v8_persisted_value> for PersistValue { + fn from(value: *mut v8_persisted_value) -> Self { + Self { + inner_val: value, + forget: false, + } + } +} + +unsafe impl Sync for PersistValue {} +unsafe impl Send for PersistValue {} + +impl Drop for PersistValue { + fn drop(&mut self) { + if self.forget { + return; + } + unsafe { v8_FreePersistedValue(self.inner_val) } + } +} diff --git a/src/v8/types/promise.rs b/src/v8/types/promise.rs index 4b3fc2c..333d5ff 100644 --- a/src/v8/types/promise.rs +++ b/src/v8/types/promise.rs @@ -11,14 +11,14 @@ use crate::v8_c_raw::bindings::{ }; use crate::v8::context_scope::ContextScope; -use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::native_function::LocalNativeFunction; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -pub struct LocalPromise<'isolate_scope, 'isolate> { - pub(crate) inner_promise: *mut v8_local_promise, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::any::LocalValueAny; + +pub struct LocalPromise<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_promise>, +); #[derive(Debug, PartialEq)] pub enum PromiseState { @@ -38,19 +38,17 @@ impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { ) { unsafe { v8_PromiseThen( - self.inner_promise, + self.0.inner_val, ctx.inner_ctx_ref, - resolve.inner_func, - reject.inner_func, + resolve.0.inner_val, + reject.0.inner_val, ); }; } - /// Return the state on the promise object - /// # Panics - #[must_use] + /// Return the state on the promise object. pub fn state(&self) -> PromiseState { - let inner_state = unsafe { v8_PromiseGetState(self.inner_promise) }; + let inner_state = unsafe { v8_PromiseGetState(self.0.inner_val) }; if inner_state == v8_PromiseState_v8_PromiseState_Fulfilled { PromiseState::Fulfilled } else if inner_state == v8_PromiseState_v8_PromiseState_Rejected { @@ -58,34 +56,49 @@ impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { } else if inner_state == v8_PromiseState_v8_PromiseState_Pending { PromiseState::Pending } else { - panic!("bad promise state"); + PromiseState::Unknown } } /// Return the result of the promise object. /// Only applicable if the promise object was resolved/rejected. - #[must_use] - pub fn get_result(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_PromiseGetResult(self.inner_promise) }; - LocalValueGeneric { + pub fn get_result(&self) -> LocalValueAny<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_PromiseGetResult(self.0.inner_val) }; + LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: self.0.isolate_scope, + }) } +} - /// Convert the promise object into a generic JS value - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_PromiseToValue(self.inner_promise) }; - LocalValueGeneric { +impl<'isolate_scope, 'isolate> Drop for LocalPromise<'isolate_scope, 'isolate> { + fn drop(&mut self) { + unsafe { v8_FreePromise(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalPromise<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_PromiseToValue(value.0.inner_val) }; + Self(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> Drop for LocalPromise<'isolate_scope, 'isolate> { - fn drop(&mut self) { - unsafe { v8_FreePromise(self.inner_promise) } +impl<'isolate_scope, 'isolate> TryFrom> + for LocalPromise<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(value: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if value.is_promise() { + Ok(unsafe { value.as_promise() }) + } else { + Err("The value is not a promise.") + } } } diff --git a/src/v8/types/resolver.rs b/src/v8/types/resolver.rs index 6ecebfa..6235fbb 100644 --- a/src/v8/types/resolver.rs +++ b/src/v8/types/resolver.rs @@ -10,50 +10,51 @@ use crate::v8_c_raw::bindings::{ }; use crate::v8::context_scope::ContextScope; -use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::promise::LocalPromise; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::any::LocalValueAny; /// JS resolver object -pub struct LocalResolver<'isolate_scope, 'isolate> { - pub(crate) inner_resolver: *mut v8_local_resolver, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +pub struct LocalResolver<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_resolver>, +); impl<'isolate_scope, 'isolate> LocalResolver<'isolate_scope, 'isolate> { /// Get the promise object assosiated with this resolver. - #[must_use] pub fn get_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { - let inner_promise = unsafe { v8_ResolverGetPromise(self.inner_resolver) }; - LocalPromise { - inner_promise, - isolate_scope: self.isolate_scope, - } + let inner_val = unsafe { v8_ResolverGetPromise(self.0.inner_val) }; + LocalPromise(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) } /// Resolve the resolver with the given JS value. - pub fn resolve(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { - unsafe { v8_ResolverResolve(ctx_scope.inner_ctx_ref, self.inner_resolver, val.inner_val) }; + pub fn resolve(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { + unsafe { v8_ResolverResolve(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } /// Reject the resolver with the given JS value. - pub fn reject(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { - unsafe { v8_ResolverReject(ctx_scope.inner_ctx_ref, self.inner_resolver, val.inner_val) }; - } - - /// Convert the resolver into a generic JS value. - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_ResolverToValue(self.inner_resolver) }; - LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - } + pub fn reject(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { + unsafe { v8_ResolverReject(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } } impl<'isolate_scope, 'isolate> Drop for LocalResolver<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeResolver(self.inner_resolver) } + unsafe { v8_FreeResolver(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalResolver<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_ResolverToValue(value.0.inner_val) }; + Self(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } } diff --git a/src/v8/types/script.rs b/src/v8/types/script.rs index 5cf643d..d412952 100644 --- a/src/v8/types/script.rs +++ b/src/v8/types/script.rs @@ -11,13 +11,15 @@ use crate::v8_c_raw::bindings::{ use crate::v8::context_scope::ContextScope; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::any::LocalValueAny; +use super::Value; /// JS script object -pub struct LocalScript<'isolate_scope, 'isolate> { - pub(crate) inner_script: *mut v8_local_script, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +pub struct LocalScript<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_script>, +); pub struct PersistedScript { pub(crate) inner_persisted_script: *mut v8_persisted_script, @@ -26,21 +28,24 @@ pub struct PersistedScript { impl<'isolate_scope, 'isolate> LocalScript<'isolate_scope, 'isolate> { /// Run the script #[must_use] - pub fn run(&self, ctx: &ContextScope) -> Option> { - let inner_val = unsafe { v8_Run(ctx.inner_ctx_ref, self.inner_script) }; + pub fn run(&self, ctx: &ContextScope) -> Option> { + let inner_val = unsafe { v8_Run(ctx.inner_ctx_ref, self.0.inner_val) }; if inner_val.is_null() { None } else { - Some(LocalValueGeneric { - inner_val, - isolate_scope: self.isolate_scope, - }) + Some( + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: self.0.isolate_scope, + }) + .into(), + ) } } pub fn persist(&self) -> PersistedScript { let inner_persisted_script = unsafe { - v8_ScriptPersist(self.isolate_scope.isolate.inner_isolate, self.inner_script) + v8_ScriptPersist(self.0.isolate_scope.isolate.inner_isolate, self.0.inner_val) }; PersistedScript { inner_persisted_script, @@ -53,22 +58,22 @@ impl PersistedScript { &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> LocalScript<'isolate_scope, 'isolate> { - let inner_script = unsafe { + let inner_val = unsafe { v8_PersistedScriptToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_script, ) }; - LocalScript { - inner_script, + LocalScript(ScopedValue { + inner_val, isolate_scope, - } + }) } } impl<'isolate_scope, 'isolate> Drop for LocalScript<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeScript(self.inner_script) } + unsafe { v8_FreeScript(self.0.inner_val) } } } diff --git a/src/v8/types/set.rs b/src/v8/types/set.rs index 484f954..81d3bc0 100644 --- a/src/v8/types/set.rs +++ b/src/v8/types/set.rs @@ -4,50 +4,78 @@ * the Server Side Public License v1 (SSPLv1). */ -use crate::v8_c_raw::bindings::{v8_FreeSet, v8_SetAdd, v8_SetToValue, v8_local_set}; +use crate::v8_c_raw::bindings::{v8_FreeSet, v8_NewSet, v8_SetAdd, v8_SetToValue, v8_local_set}; use crate::v8::context_scope::ContextScope; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; -/// JS object -pub struct LocalSet<'isolate_scope, 'isolate> { - pub(crate) inner_set: *mut v8_local_set, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +use super::any::LocalValueAny; +use super::Value; + +/// A javascript set. +#[derive(Debug, Clone)] +pub struct LocalSet<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_set>, +); impl<'isolate_scope, 'isolate> LocalSet<'isolate_scope, 'isolate> { - /// Convert the object into a generic JS value - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_SetToValue(self.inner_set) }; - LocalValueGeneric { + /// Creates a new local set for the passed [IsolateScope]. + pub fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewSet(isolate_scope.isolate.inner_isolate) }; + Self(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope, + }) } - pub fn add(&self, ctx_scope: &ContextScope, val: &LocalValueGeneric) { - unsafe { v8_SetAdd(ctx_scope.inner_ctx_ref, self.inner_set, val.inner_val) }; + pub fn add(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { + unsafe { v8_SetAdd(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } } impl<'isolate_scope, 'isolate> Drop for LocalSet<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeSet(self.inner_set) } + unsafe { v8_FreeSet(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalSet<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_SetToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> TryFrom> +impl<'isolate_scope, 'isolate> TryFrom> for LocalSet<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { if !val.is_set() { return Err("Value is not a set"); } - Ok(val.as_set()) + Ok(unsafe { val.as_set() }) + } +} + +impl<'isolate_scope, 'isolate> TryFrom> + for LocalSet<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::Set(set) => Ok(set), + Value::Other(any) => any.try_into(), + _ => Err("Value is not a set"), + } } } diff --git a/src/v8/types/string.rs b/src/v8/types/string.rs index 50cdf57..80a1199 100644 --- a/src/v8/types/string.rs +++ b/src/v8/types/string.rs @@ -5,45 +5,84 @@ */ use crate::v8_c_raw::bindings::{ - v8_FreeString, v8_StringToStringObject, v8_StringToValue, v8_local_string, + v8_FreeString, v8_NewString, v8_StringToStringObject, v8_StringToValue, v8_local_string, }; use crate::v8::isolate_scope::IsolateScope; use crate::v8::types::object::LocalObject; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::any::LocalValueAny; /// JS string object -pub struct LocalString<'isolate_scope, 'isolate> { - pub(crate) inner_string: *mut v8_local_string, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +#[derive(Debug, Clone)] +pub struct LocalString<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_string>, +); impl<'isolate_scope, 'isolate> LocalString<'isolate_scope, 'isolate> { - /// Convert the string object into a generic JS object. - #[must_use] - pub fn to_value(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_StringToValue(self.inner_string) }; - LocalValueGeneric { + /// Creates a new JavaScript string within the passed [IsolateScope]. + pub fn new(s: &str, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { + v8_NewString( + isolate_scope.isolate.inner_isolate, + s.as_ptr().cast(), + s.len(), + ) + }; + + Self(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope, + }) + } +} + +impl<'isolate_scope, 'isolate> Drop for LocalString<'isolate_scope, 'isolate> { + fn drop(&mut self) { + unsafe { v8_FreeString(self.0.inner_val) } + } +} + +impl<'isolate_scope, 'isolate> From> + for LocalValueAny<'isolate_scope, 'isolate> +{ + fn from(value: LocalString<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { v8_StringToValue(value.0.inner_val) }; + LocalValueAny(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } +} - /// Same as writing 'new String(...)'. - #[must_use] - pub fn to_string_object(&self) -> LocalObject<'isolate_scope, 'isolate> { - let inner_obj = unsafe { - v8_StringToStringObject(self.isolate_scope.isolate.inner_isolate, self.inner_string) +impl<'isolate_scope, 'isolate> From> + for LocalObject<'isolate_scope, 'isolate> +{ + fn from(value: LocalString<'isolate_scope, 'isolate>) -> Self { + let inner_val = unsafe { + v8_StringToStringObject( + value.0.isolate_scope.isolate.inner_isolate, + value.0.inner_val, + ) }; - LocalObject { - inner_obj, - isolate_scope: self.isolate_scope, - } + LocalObject(ScopedValue { + inner_val, + isolate_scope: value.0.isolate_scope, + }) } } -impl<'isolate_scope, 'isolate> Drop for LocalString<'isolate_scope, 'isolate> { - fn drop(&mut self) { - unsafe { v8_FreeString(self.inner_string) } +impl<'isolate_scope, 'isolate> TryFrom> + for LocalString<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !val.is_string() { + return Err("Value is not a string"); + } + + Ok(unsafe { val.as_string() }) } } diff --git a/src/v8/types/try_catch.rs b/src/v8/types/try_catch.rs index 3bab275..7af2f38 100644 --- a/src/v8/types/try_catch.rs +++ b/src/v8/types/try_catch.rs @@ -4,60 +4,72 @@ * the Server Side Public License v1 (SSPLv1). */ +use crate::v8::isolate_scope::IsolateScope; use crate::v8_c_raw::bindings::{ - v8_FreeTryCatch, v8_TryCatchGetException, v8_TryCatchGetTrace, v8_TryCatchHasTerminated, - v8_trycatch, + v8_FreeTryCatch, v8_NewTryCatch, v8_TryCatchGetException, v8_TryCatchGetTrace, + v8_TryCatchHasTerminated, v8_trycatch, }; use crate::v8::context_scope::ContextScope; -use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; +use crate::v8::types::ScopedValue; + +use super::any::LocalValueAny; /// An object that responsible to catch any exception which raised /// during the JS code invocation. -pub struct TryCatch<'isolate_scope, 'isolate> { - pub(crate) inner_trycatch: *mut v8_trycatch, - pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +#[derive(Debug, Clone)] +pub struct TryCatch<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_trycatch>, +); impl<'isolate_scope, 'isolate> TryCatch<'isolate_scope, 'isolate> { + /// Creates a new JavaScript try-catch within the passed [IsolateScope]. + pub fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewTryCatch(isolate_scope.isolate.inner_isolate) }; + + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } + /// Return the exception that was raise during the JS code invocation. - #[must_use] - pub fn get_exception(&self) -> LocalValueGeneric<'isolate_scope, 'isolate> { - let inner_val = unsafe { v8_TryCatchGetException(self.inner_trycatch) }; + /// + /// # Panics + /// + /// Panics when the exception pointer is null. + pub fn get_exception(&self) -> LocalValueAny<'isolate_scope, 'isolate> { + let inner_val = unsafe { v8_TryCatchGetException(self.0.inner_val) }; assert!(!inner_val.is_null()); - LocalValueGeneric { + LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - } + isolate_scope: self.0.isolate_scope, + }) } /// Return the trace of the catch exception, the function returns Option because trace is not always provided. - #[must_use] pub fn get_trace( &self, ctx_scope: &ContextScope, - ) -> Option> { - let inner_val = - unsafe { v8_TryCatchGetTrace(self.inner_trycatch, ctx_scope.inner_ctx_ref) }; + ) -> Option> { + let inner_val = unsafe { v8_TryCatchGetTrace(self.0.inner_val, ctx_scope.inner_ctx_ref) }; if inner_val.is_null() { return None; } - Some(LocalValueGeneric { + Some(LocalValueAny(ScopedValue { inner_val, - isolate_scope: self.isolate_scope, - }) + isolate_scope: self.0.isolate_scope, + })) } - #[must_use] pub fn has_terminated(&self) -> bool { - let res = unsafe { v8_TryCatchHasTerminated(self.inner_trycatch) }; + let res = unsafe { v8_TryCatchHasTerminated(self.0.inner_val) }; res > 0 } } impl<'isolate_scope, 'isolate> Drop for TryCatch<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeTryCatch(self.inner_trycatch) } + unsafe { v8_FreeTryCatch(self.0.inner_val) } } } diff --git a/src/v8/types/unlocker.rs b/src/v8/types/unlocker.rs index 08e2545..5cd54cb 100644 --- a/src/v8/types/unlocker.rs +++ b/src/v8/types/unlocker.rs @@ -5,15 +5,29 @@ */ use crate::v8::isolate_scope::IsolateScope; -use crate::v8_c_raw::bindings::{v8_FreeUnlocker, v8_unlocker}; +use crate::v8_c_raw::bindings::{v8_FreeUnlocker, v8_NewUnlocker, v8_unlocker}; -pub struct Unlocker<'isolate_scope, 'isolate> { - pub(crate) inner_unlocker: *mut v8_unlocker, - pub(crate) _isolate_scope: &'isolate_scope IsolateScope<'isolate>, +use super::ScopedValue; + +/// TODO add comment. +#[derive(Debug, Clone)] +pub struct Unlocker<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_unlocker>, +); + +impl<'isolate_scope, 'isolate> Unlocker<'isolate_scope, 'isolate> { + /// Creates a new [Unlocker] within the provided [IsolateScope]. + pub fn new(isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + let inner_val = unsafe { v8_NewUnlocker(isolate_scope.isolate.inner_isolate) }; + Self(ScopedValue { + inner_val, + isolate_scope, + }) + } } impl<'isolate_scope, 'isolate> Drop for Unlocker<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeUnlocker(self.inner_unlocker) }; + unsafe { v8_FreeUnlocker(self.0.inner_val) }; } } diff --git a/src/v8/types/utf8.rs b/src/v8/types/utf8.rs index 38577d0..78ff33f 100644 --- a/src/v8/types/utf8.rs +++ b/src/v8/types/utf8.rs @@ -4,47 +4,89 @@ * the Server Side Public License v1 (SSPLv1). */ -use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::LocalValueGeneric; -use crate::v8_c_raw::bindings::{v8_FreeUtf8, v8_Utf8PtrLen, v8_utf8_value}; +use crate::v8::types::ScopedValue; +use crate::v8_c_raw::bindings::{v8_FreeUtf8, v8_ToUtf8, v8_Utf8PtrLen, v8_utf8_value}; +use std::ptr::NonNull; use std::slice; use std::str; +use super::any::LocalValueAny; +use super::string::LocalString; + /// JS utf8 object -pub struct LocalUtf8<'isolate_scope, 'isolate> { - pub(crate) inner_val: *mut v8_utf8_value, - pub(crate) _isolate_scope: &'isolate_scope IsolateScope<'isolate>, -} +pub struct LocalUtf8<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_utf8_value>, +); impl<'isolate_scope, 'isolate> LocalUtf8<'isolate_scope, 'isolate> { - /// Get &str from the utf8 object + /// Get a [str] slice from the object. + /// /// # Panics - #[must_use] + /// + /// Panics when the [std::str::from_utf8] fails. pub fn as_str(&self) -> &str { let mut len: usize = 0; - let buff = unsafe { v8_Utf8PtrLen(self.inner_val, &mut len) }; - let bytes = unsafe { slice::from_raw_parts(buff.cast::(), len) }; - str::from_utf8(bytes).unwrap() + let buff = unsafe { v8_Utf8PtrLen(self.0.inner_val, &mut len) }; + let bytes = unsafe { slice::from_raw_parts(buff.cast(), len) }; + str::from_utf8(bytes).expect("Couldn't create a string") + } +} + +impl<'isolate_scope, 'isolate> AsRef for LocalUtf8<'isolate_scope, 'isolate> { + fn as_ref(&self) -> &str { + self.as_str() } } impl<'isolate_scope, 'isolate> Drop for LocalUtf8<'isolate_scope, 'isolate> { fn drop(&mut self) { - unsafe { v8_FreeUtf8(self.inner_val) } + unsafe { v8_FreeUtf8(self.0.inner_val) } } } -impl<'isolate_scope, 'isolate> TryFrom> +impl<'isolate_scope, 'isolate> From> + for LocalUtf8<'isolate_scope, 'isolate> +{ + fn from(value: LocalString<'isolate_scope, 'isolate>) -> Self { + let value = LocalValueAny::from(value); + // Note that given the implementation of the `TryFrom` below, + // this code should never fail as we always check for the actual + // type of the value stored within the `LocalValueAny` to be + // a string or a string object, and since in this case it was + // a string and we knew that fact, it must never fail. + Self::try_from(value).expect("Failed to convert a string to Utf8.") + } +} + +impl<'isolate_scope, 'isolate> TryFrom> for LocalUtf8<'isolate_scope, 'isolate> { type Error = &'static str; - fn try_from(val: LocalValueGeneric<'isolate_scope, 'isolate>) -> Result { - if !val.is_string() && !val.is_string_object() { + fn try_from(value: LocalValueAny<'isolate_scope, 'isolate>) -> Result { + if !value.is_string() && !value.is_string_object() { return Err("Value is not string"); } - val.to_utf8().ok_or("Failed converting to utf8") + NonNull::new(unsafe { + v8_ToUtf8( + value.0.isolate_scope.isolate.inner_isolate, + value.0.inner_val, + ) + }) + .map(|ptr| { + LocalUtf8(ScopedValue { + inner_val: ptr.as_ptr(), + isolate_scope: value.0.isolate_scope, + }) + }) + .ok_or("Failed converting to utf8") + } +} + +impl<'isolate_scope, 'isolate> From> for String { + fn from(value: LocalUtf8<'isolate_scope, 'isolate>) -> Self { + value.as_str().to_owned() } } diff --git a/v8-rs-derive/Cargo.toml b/v8-rs-derive/Cargo.toml index 3b639b9..717b4e1 100644 --- a/v8-rs-derive/Cargo.toml +++ b/v8-rs-derive/Cargo.toml @@ -6,10 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = { version="1.0", features = ["full"]} -quote = "1.0" +syn = { version = "1", features = ["full"]} +quote = "1" [lib] name = "v8_derive" path = "src/lib.rs" -proc-macro = true \ No newline at end of file +proc-macro = true diff --git a/v8-rs-derive/src/lib.rs b/v8-rs-derive/src/lib.rs index 9ab1d7f..95fb223 100644 --- a/v8-rs-derive/src/lib.rs +++ b/v8-rs-derive/src/lib.rs @@ -209,7 +209,7 @@ pub fn new_native_function(item: TokenStream) -> TokenStream { fn __create_closure__(f: F) -> F where - F: for<'i_s, 'i> Fn(&'i_s v8_rs::v8::isolate_scope::IsolateScope<'i>, &v8_rs::v8::context_scope::ContextScope<'i_s, 'i>, #(#types_for_closure, )*) -> Result>, E>, + F: for<'i_s, 'i> Fn(&'i_s v8_rs::v8::isolate_scope::IsolateScope<'i>, &v8_rs::v8::context_scope::ContextScope<'i_s, 'i>, #(#types_for_closure, )*) -> Result>, E>, E: std::fmt::Display, { f From 3f50b6f7065b706dc95fade1a53a5fc6e425b0ec Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Fri, 21 Apr 2023 11:01:06 +0200 Subject: [PATCH 3/5] Add more documentation. --- src/lib.rs | 24 +++++----- src/v8/context_scope.rs | 6 +-- src/v8/mod.rs | 9 ++++ src/v8/types/array.rs | 2 + src/v8/types/array_buffer.rs | 5 +++ src/v8/types/external_data.rs | 16 ++++++- src/v8/types/mod.rs | 18 ++++++++ src/v8/types/module.rs | 84 +++++++++++++++++++++++++---------- 8 files changed, 125 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 896b72c..191c4cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ */ //! V8-rs is a crate containing bindings to the V8 C++ API. -// #![deny(missing_docs)] +#![warn(missing_docs)] /// The module contains the rust-idiomatic data structures and functions. pub mod v8; @@ -326,16 +326,18 @@ mod json_path_tests { let module = ctx_scope .compile_as_module(&code_name, &code_str, true) .unwrap(); - module.initialize( - &ctx_scope, - |isolate_scope, ctx_scope, name_to_load, _identity_hash| { - let code_str = isolate_scope - .create_string("export let msg = \"foo\";") - .try_into() - .unwrap(); - ctx_scope.compile_as_module(name_to_load, &code_str, true) - }, - ); + let module = module + .initialize( + &ctx_scope, + |isolate_scope, ctx_scope, name_to_load, _identity_hash| { + let code_str = isolate_scope + .create_string("export let msg = \"foo\";") + .try_into() + .unwrap(); + ctx_scope.compile_as_module(name_to_load, &code_str, true) + }, + ) + .unwrap(); let res = module.evaluate(&ctx_scope).unwrap(); let res: LocalPromise = res.try_into().unwrap(); assert_eq!( diff --git a/src/v8/context_scope.rs b/src/v8/context_scope.rs index c5a71df..6536a46 100644 --- a/src/v8/context_scope.rs +++ b/src/v8/context_scope.rs @@ -17,7 +17,7 @@ use std::os::raw::c_void; use std::ptr::NonNull; use crate::v8::isolate_scope::IsolateScope; -use crate::v8::types::module::LocalModule; +use crate::v8::types::module::UninitialisedLocalModule; use crate::v8::types::native_function::LocalNativeFunction; use crate::v8::types::native_function_template::free_pd; use crate::v8::types::native_function_template::native_basic_function; @@ -96,7 +96,7 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { name: &LocalString, code: &LocalString, is_module: bool, - ) -> Option> { + ) -> Option> { let inner_val = unsafe { v8_CompileAsModule( self.inner_ctx_ref, @@ -108,7 +108,7 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { if inner_val.is_null() { None } else { - Some(LocalModule(ScopedValue { + Some(UninitialisedLocalModule(ScopedValue { inner_val, isolate_scope: self.isolate_scope, })) diff --git a/src/v8/mod.rs b/src/v8/mod.rs index 1c2e786..3f8a000 100644 --- a/src/v8/mod.rs +++ b/src/v8/mod.rs @@ -20,9 +20,18 @@ pub(crate) type OutOfMemoryErrorCallback = dyn Fn(&str, bool); pub(crate) static mut FATAL_ERROR_CALLBACK: Option> = None; pub(crate) static mut OOM_ERROR_CALLBACK: Option> = None; +/// A value-missing-aware conversion for types. If a value passed to the +/// [OptionalTryFrom::optional_try_from] method may be considered +/// absent, the [Option::None] is returned instead of an error; errors +/// are only returned when there **is** a value (it is present) but the +/// conversion itself fails. pub trait OptionalTryFrom: Sized { + /// The error type for the conversion failure. type Error; + /// Returns an [Option] of the value indicating the presence or + /// absence of the value, and [Result::Err] in case there was an + /// error during the conversion. fn optional_try_from(value: T) -> Result, Self::Error>; } diff --git a/src/v8/types/array.rs b/src/v8/types/array.rs index 322733a..6374ff5 100644 --- a/src/v8/types/array.rs +++ b/src/v8/types/array.rs @@ -3,6 +3,8 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! The Javascript array facilities, represented by the type +//! [LocalArray]. use crate::v8_c_raw::bindings::{ v8_ArrayGet, v8_ArrayLen, v8_ArrayToValue, v8_FreeArray, v8_NewArray, v8_local_array, diff --git a/src/v8/types/array_buffer.rs b/src/v8/types/array_buffer.rs index 09d8f75..f4775af 100644 --- a/src/v8/types/array_buffer.rs +++ b/src/v8/types/array_buffer.rs @@ -3,6 +3,10 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! The Javascript array buffer facilities, represented by the type +//! [LocalArrayBuffer]. The types [super::LocalArray] and +//! [LocalArrayBuffer] are different, the first stores valid javascript +//! objects, the latter stores bytes. use crate::v8_c_raw::bindings::{ v8_ArrayBufferGetData, v8_ArrayBufferToValue, v8_FreeArrayBuffer, v8_NewArrayBuffer, @@ -38,6 +42,7 @@ impl<'isolate_scope, 'isolate> LocalArrayBuffer<'isolate_scope, 'isolate> { }) } + /// Returns a byte slice to the stored data. pub fn data(&self) -> &[u8] { let mut size = 0; let data = unsafe { v8_ArrayBufferGetData(self.0.inner_val, &mut size as *mut usize) }; diff --git a/src/v8/types/external_data.rs b/src/v8/types/external_data.rs index 046c7e2..e6d3b85 100644 --- a/src/v8/types/external_data.rs +++ b/src/v8/types/external_data.rs @@ -3,6 +3,15 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Provides a way to allow the JavaScript code to interoperate with +//! foreign objects. + +// TODO make the objects of this structure store a tag of the type, so +// that for get_data/get_data_mut it is checked before the conversion. +// +// This should help when an object of type `X` is created and stored, +// but the extraction is performed for another type `Y`, what may bring +// the undefined behaviour. use crate::v8_c_raw::bindings::{ v8_ExternalDataGet, v8_ExternalDataToValue, v8_NewExternalData, v8_local_external_data, @@ -17,7 +26,10 @@ extern "C" fn free_external_data(arg1: *mut ::std::os::raw::c_void) { unsafe { Box::from_raw(arg1 as *mut T) }; } -/// TODO a proper comment. +/// The V8's `External` type. +/// This is a JavaScript value that wraps a C++ void*. +/// This type is mainly used to associate non-javascript-native data +/// structures with JavaScript objects. #[derive(Debug, Clone)] pub struct LocalExternalData<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_external_data>, @@ -40,10 +52,12 @@ impl<'isolate_scope, 'isolate> LocalExternalData<'isolate_scope, 'isolate> { }) } + /// Returns the data stored, as an immutable reference to `T`. pub fn get_data(&self) -> &'isolate_scope T { unsafe { &*(v8_ExternalDataGet(self.0.inner_val) as *const T) } } + /// Returns the data stored, as a mutable reference to `T`. pub fn get_data_mut(&mut self) -> &mut T { unsafe { &mut *(v8_ExternalDataGet(self.0.inner_val) as *mut T) } } diff --git a/src/v8/types/mod.rs b/src/v8/types/mod.rs index 200b631..dc25007 100644 --- a/src/v8/types/mod.rs +++ b/src/v8/types/mod.rs @@ -3,6 +3,24 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! This module contains the supported JavaScript V8 value types. +//! See [Value], [LocalValueAny] types for the generic implementations. +//! +//! The objects cannot be created without having an isolate scope within +//! which they should be created. All the objects' lifetimes are limited +//! to the isolate scope lifetime they were created for. +//! +//! All the concrete types are a subtype of a more generic base type +//! [ScopedValue] which contains the isolate scope and a generic type +//! argument for the value. +//! +//! Sometimes, the values are convertible to and from each other, either +//! via the [From] or [TryFrom] traits, depending on the possibility of +//! such a conversion. +//! +//! The most commonly used type is the V8's type-erased +//! [v8_c_raw::bindings::v8_local_value] mutable pointer, which is +//! represented by [LocalValueAny]. use crate::v8_c_raw::bindings::{v8_NewBool, v8_NewNull, v8_ValueFromDouble, v8_ValueFromLong}; diff --git a/src/v8/types/module.rs b/src/v8/types/module.rs index 9cbab3f..35bfcda 100644 --- a/src/v8/types/module.rs +++ b/src/v8/types/module.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! A collection of types of data which represent module objects. use crate::v8_c_raw::bindings::{ v8_ContextRefGetIsolate, v8_EvaluateModule, v8_FreeModule, v8_FreePersistedModule, @@ -22,11 +23,19 @@ use std::ptr; use super::any::LocalValueAny; use super::Value; -/// JS script object -pub struct LocalModule<'isolate_scope, 'isolate>( +/// A module in JavaScript is a collection of functions and objects. +/// An unitialised module cannot be evaluated and must be initialised +/// prior to any use. +pub struct UninitialisedLocalModule<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_module>, ); +/// An initialised module. +pub struct InitialisedLocalModule<'isolate_scope, 'isolate>( + pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_module>, +); + +/// The same as [LocalModule] but not tied to an [IsolateScope]. pub struct PersistedModule { pub(crate) inner_persisted_module: *mut v8_persisted_module, } @@ -37,7 +46,8 @@ pub(crate) extern "C" fn load_module< &'isolate ContextScope<'isolate_scope, 'c>, &'isolate LocalString<'isolate_scope, 'c>, i64, - ) -> Option>, + ) + -> Option>, >( v8_ctx_ref: *mut v8_context_ref, name: *mut v8_local_string, @@ -69,19 +79,21 @@ pub(crate) extern "C" fn load_module< } } -impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> UninitialisedLocalModule<'isolate_scope, 'isolate> { + /// Initialises the module. A module must be initialised before + /// it can be evaluated. pub fn initialize< T: for<'c, 'd, 'e> Fn( &'c IsolateScope<'e>, &'c ContextScope<'d, 'e>, &'c LocalString<'d, 'e>, i64, - ) -> Option>, + ) -> Option>, >( &self, ctx_scope: &ContextScope, load_module_callback: T, - ) -> bool { + ) -> Option> { ctx_scope.set_private_data_raw(RawIndex(0), &load_module_callback); let res = unsafe { v8_InitiateModule( @@ -91,9 +103,36 @@ impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { ) }; ctx_scope.reset_private_data_raw(RawIndex(0)); - res != 0 + if res != 0 { + Some(InitialisedLocalModule(ScopedValue { + inner_val: self.0.inner_val, + isolate_scope: self.0.isolate_scope, + })) + } else { + None + } } + /// Persists the module by allowing it outlive the [IsolateScope] it + /// has by converting it into a [PersistedModule] for the provided + /// [Isolate]. + pub fn persist(&self, isolate: &Isolate) -> PersistedModule { + let inner_persisted_module = + unsafe { v8_ModulePersist(isolate.inner_isolate, self.0.inner_val) }; + PersistedModule { + inner_persisted_module, + } + } + + /// Returns the hash value for the module. + pub fn get_identity_hash(&self) -> i64 { + unsafe { v8_ModuleGetIdentityHash(self.0.inner_val) as i64 } + } +} + +impl<'isolate_scope, 'isolate> InitialisedLocalModule<'isolate_scope, 'isolate> { + /// Evalutes the module and returns a value if it was returned by + /// the module during the evaluation. pub fn evaluate(&self, ctx_scope: &ContextScope) -> Option> { let res = unsafe { v8_EvaluateModule(self.0.inner_val, ctx_scope.inner_ctx_ref) }; if res.is_null() { @@ -108,40 +147,37 @@ impl<'isolate_scope, 'isolate> LocalModule<'isolate_scope, 'isolate> { ) } } - - /// Convert the module into a generic JS value - pub fn persist(&self, isolate: &Isolate) -> PersistedModule { - let inner_persisted_module = - unsafe { v8_ModulePersist(isolate.inner_isolate, self.0.inner_val) }; - PersistedModule { - inner_persisted_module, - } - } - - pub fn get_identity_hash(&self) -> i64 { - unsafe { v8_ModuleGetIdentityHash(self.0.inner_val) as i64 } - } } impl PersistedModule { - pub fn to_local<'isolate_scope, 'isolate>( + /// Returns a local module object, which is tied to the passed + /// [IsolateScope]. + pub fn as_local<'isolate_scope, 'isolate>( &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, - ) -> LocalModule<'isolate_scope, 'isolate> { + ) -> UninitialisedLocalModule<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ModuleToLocal( isolate_scope.isolate.inner_isolate, self.inner_persisted_module, ) }; - LocalModule(ScopedValue { + UninitialisedLocalModule(ScopedValue { inner_val, isolate_scope, }) } } -impl<'isolate_scope, 'isolate> Drop for LocalModule<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for UninitialisedLocalModule<'isolate_scope, 'isolate> { + fn drop(&mut self) { + if !self.0.inner_val.is_null() { + unsafe { v8_FreeModule(self.0.inner_val) } + } + } +} + +impl<'isolate_scope, 'isolate> Drop for InitialisedLocalModule<'isolate_scope, 'isolate> { fn drop(&mut self) { if !self.0.inner_val.is_null() { unsafe { v8_FreeModule(self.0.inner_val) } From 56009d05923efb6f85f568e35ee93359d43f2c88 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Fri, 21 Apr 2023 11:47:13 +0200 Subject: [PATCH 4/5] Add more documentation. --- src/lib.rs | 6 +++--- src/v8/context_scope.rs | 6 +++--- src/v8/types/any.rs | 9 +++++---- src/v8/types/promise.rs | 27 ++++++++++++++++----------- src/v8/types/resolver.rs | 22 +++++++++++++--------- src/v8/types/script.rs | 9 ++++++++- src/v8/types/set.rs | 2 ++ src/v8/types/string.rs | 3 ++- src/v8/types/try_catch.rs | 6 +++++- src/v8/types/unlocker.rs | 22 +++++++++++++++++++++- src/v8/types/utf8.rs | 4 +++- 11 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 191c4cf..db6d664 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -341,7 +341,7 @@ mod json_path_tests { let res = module.evaluate(&ctx_scope).unwrap(); let res: LocalPromise = res.try_into().unwrap(); assert_eq!( - res.state(), + res.state().unwrap(), crate::v8::types::promise::PromiseState::Fulfilled ); } @@ -364,7 +364,7 @@ mod json_path_tests { let async_res = res.call(&ctx_scope, None).unwrap(); let promise: LocalPromise = async_res.try_into().unwrap(); assert_eq!( - promise.state(), + promise.state().unwrap(), crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); @@ -400,7 +400,7 @@ mod json_path_tests { println!("{}", s.as_str()); let promise: LocalPromise = res.try_into().unwrap(); assert_eq!( - promise.state(), + promise.state().unwrap(), crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); diff --git a/src/v8/context_scope.rs b/src/v8/context_scope.rs index 6536a46..796ec56 100644 --- a/src/v8/context_scope.rs +++ b/src/v8/context_scope.rs @@ -23,7 +23,7 @@ use crate::v8::types::native_function_template::free_pd; use crate::v8::types::native_function_template::native_basic_function; use crate::v8::types::native_function_template::LocalNativeFunctionArgs; use crate::v8::types::object::LocalObject; -use crate::v8::types::resolver::LocalResolver; +use crate::v8::types::resolver::LocalPromiseResolver; use crate::v8::types::script::LocalScript; use crate::v8::types::string::LocalString; use crate::v8::types::ScopedValue; @@ -181,9 +181,9 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { } /// Create a new resolver object - pub fn create_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { + pub fn create_resolver(&self) -> LocalPromiseResolver<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_NewResolver(self.inner_ctx_ref) }; - LocalResolver(ScopedValue { + LocalPromiseResolver(ScopedValue { inner_val, isolate_scope: self.isolate_scope, }) diff --git a/src/v8/types/any.rs b/src/v8/types/any.rs index 818eb4e..34d25f7 100644 --- a/src/v8/types/any.rs +++ b/src/v8/types/any.rs @@ -24,8 +24,9 @@ use crate::{ use super::{ array::LocalArray, array_buffer::LocalArrayBuffer, external_data::LocalExternalData, - object::LocalObject, persistent::PersistValue, promise::LocalPromise, resolver::LocalResolver, - set::LocalSet, string::LocalString, utf8::LocalUtf8, ScopedValue, + object::LocalObject, persistent::PersistValue, promise::LocalPromise, + resolver::LocalPromiseResolver, set::LocalSet, string::LocalString, utf8::LocalUtf8, + ScopedValue, }; /// A type the objects of [LocalValueAny] can hold. @@ -286,9 +287,9 @@ impl<'isolate_scope, 'isolate> LocalValueAny<'isolate_scope, 'isolate> { /// In case the target type is not checked before this function is /// invoked and the value is not of this target type, the results /// are unknown. - pub unsafe fn as_resolver(&self) -> LocalResolver<'isolate_scope, 'isolate> { + pub unsafe fn as_resolver(&self) -> LocalPromiseResolver<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ValueAsResolver(self.0.inner_val) }; - LocalResolver(ScopedValue { + LocalPromiseResolver(ScopedValue { inner_val, isolate_scope: self.0.isolate_scope, }) diff --git a/src/v8/types/promise.rs b/src/v8/types/promise.rs index 333d5ff..31deee3 100644 --- a/src/v8/types/promise.rs +++ b/src/v8/types/promise.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the JavaScript promise facilities. use crate::v8_c_raw::bindings::{ v8_FreePromise, v8_PromiseGetResult, v8_PromiseGetState, @@ -16,16 +17,22 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; +/// A promise is an object representing an eventual completion +/// (successful or not) of an asynchronous operation and its resulting +/// value. pub struct LocalPromise<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_promise>, ); +/// The states a [LocalPromise] can be in. #[derive(Debug, PartialEq)] pub enum PromiseState { + /// The operation has completed successfully. Fulfilled, + /// The operation has failed. Rejected, + /// The initial state of a promise - pending execution. Pending, - Unknown, } impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { @@ -47,17 +54,15 @@ impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { } /// Return the state on the promise object. - pub fn state(&self) -> PromiseState { + #[allow(non_upper_case_globals)] + pub fn state(&self) -> Option { let inner_state = unsafe { v8_PromiseGetState(self.0.inner_val) }; - if inner_state == v8_PromiseState_v8_PromiseState_Fulfilled { - PromiseState::Fulfilled - } else if inner_state == v8_PromiseState_v8_PromiseState_Rejected { - PromiseState::Rejected - } else if inner_state == v8_PromiseState_v8_PromiseState_Pending { - PromiseState::Pending - } else { - PromiseState::Unknown - } + Some(match inner_state { + v8_PromiseState_v8_PromiseState_Fulfilled => PromiseState::Fulfilled, + v8_PromiseState_v8_PromiseState_Rejected => PromiseState::Rejected, + v8_PromiseState_v8_PromiseState_Pending => PromiseState::Pending, + _ => return None, + }) } /// Return the result of the promise object. diff --git a/src/v8/types/resolver.rs b/src/v8/types/resolver.rs index 6235fbb..fa165a3 100644 --- a/src/v8/types/resolver.rs +++ b/src/v8/types/resolver.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! This module contains the promise resolution facilities. use crate::v8_c_raw::bindings::{ v8_FreeResolver, v8_ResolverGetPromise, v8_ResolverReject, v8_ResolverResolve, @@ -15,13 +16,16 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; -/// JS resolver object -pub struct LocalResolver<'isolate_scope, 'isolate>( +// TODO it would be nice to associate a promise with the resolver, for +// example by lifetimes and a phantomguard or by a real object, to +// ensure that one promise is always associated with one, same promise. +/// A resolver for the [LocalPromise]. +pub struct LocalPromiseResolver<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_resolver>, ); -impl<'isolate_scope, 'isolate> LocalResolver<'isolate_scope, 'isolate> { - /// Get the promise object assosiated with this resolver. +impl<'isolate_scope, 'isolate> LocalPromiseResolver<'isolate_scope, 'isolate> { + /// Returns the promise object assosiated with this resolver. pub fn get_promise(&self) -> LocalPromise<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ResolverGetPromise(self.0.inner_val) }; LocalPromise(ScopedValue { @@ -30,27 +34,27 @@ impl<'isolate_scope, 'isolate> LocalResolver<'isolate_scope, 'isolate> { }) } - /// Resolve the resolver with the given JS value. + /// Resolves the associated promise with the given JavaScript value. pub fn resolve(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { unsafe { v8_ResolverResolve(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } - /// Reject the resolver with the given JS value. + /// Rejects the associated promise with the given JavaScript value. pub fn reject(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { unsafe { v8_ResolverReject(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } } -impl<'isolate_scope, 'isolate> Drop for LocalResolver<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> Drop for LocalPromiseResolver<'isolate_scope, 'isolate> { fn drop(&mut self) { unsafe { v8_FreeResolver(self.0.inner_val) } } } -impl<'isolate_scope, 'isolate> From> +impl<'isolate_scope, 'isolate> From> for LocalValueAny<'isolate_scope, 'isolate> { - fn from(value: LocalResolver<'isolate_scope, 'isolate>) -> Self { + fn from(value: LocalPromiseResolver<'isolate_scope, 'isolate>) -> Self { let inner_val = unsafe { v8_ResolverToValue(value.0.inner_val) }; Self(ScopedValue { inner_val, diff --git a/src/v8/types/script.rs b/src/v8/types/script.rs index d412952..e3d81e2 100644 --- a/src/v8/types/script.rs +++ b/src/v8/types/script.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! The JavaScript script facilities. use crate::v8_c_raw::bindings::{ v8_FreePersistedScript, v8_FreeScript, v8_PersistedScriptToLocal, v8_Run, v8_ScriptPersist, @@ -16,11 +17,13 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; use super::Value; -/// JS script object +/// A JavaScript script object. pub struct LocalScript<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_script>, ); +/// A persisted script is script that isn't tied to the [IsolateScope]'s +/// lifetime it was created for. pub struct PersistedScript { pub(crate) inner_persisted_script: *mut v8_persisted_script, } @@ -43,6 +46,8 @@ impl<'isolate_scope, 'isolate> LocalScript<'isolate_scope, 'isolate> { } } + /// Persists the [LocalScript] so that it can outlive the + /// [IsolateScope] it was tied to. pub fn persist(&self) -> PersistedScript { let inner_persisted_script = unsafe { v8_ScriptPersist(self.0.isolate_scope.isolate.inner_isolate, self.0.inner_val) @@ -54,6 +59,8 @@ impl<'isolate_scope, 'isolate> LocalScript<'isolate_scope, 'isolate> { } impl PersistedScript { + /// Converts the [PersistedScript] into a [LocalScript] for the + /// provided [IsolateScope]. pub fn to_local<'isolate_scope, 'isolate>( &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, diff --git a/src/v8/types/set.rs b/src/v8/types/set.rs index 81d3bc0..67a9691 100644 --- a/src/v8/types/set.rs +++ b/src/v8/types/set.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the JavaScript set facilities. use crate::v8_c_raw::bindings::{v8_FreeSet, v8_NewSet, v8_SetAdd, v8_SetToValue, v8_local_set}; @@ -29,6 +30,7 @@ impl<'isolate_scope, 'isolate> LocalSet<'isolate_scope, 'isolate> { }) } + /// Adds new element to the set. pub fn add(&self, ctx_scope: &ContextScope, val: &LocalValueAny) { unsafe { v8_SetAdd(ctx_scope.inner_ctx_ref, self.0.inner_val, val.0.inner_val) }; } diff --git a/src/v8/types/string.rs b/src/v8/types/string.rs index 80a1199..2efc67a 100644 --- a/src/v8/types/string.rs +++ b/src/v8/types/string.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! The JavaScript string facilities. use crate::v8_c_raw::bindings::{ v8_FreeString, v8_NewString, v8_StringToStringObject, v8_StringToValue, v8_local_string, @@ -14,7 +15,7 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; -/// JS string object +/// A JavaScript string object. #[derive(Debug, Clone)] pub struct LocalString<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_string>, diff --git a/src/v8/types/try_catch.rs b/src/v8/types/try_catch.rs index 7af2f38..2cd5342 100644 --- a/src/v8/types/try_catch.rs +++ b/src/v8/types/try_catch.rs @@ -3,6 +3,9 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the `try-catch` facilities for JavaScript. It is possible +//! to assign a custom, external Rust-based exception handler via +//! [TryCatch]. use crate::v8::isolate_scope::IsolateScope; use crate::v8_c_raw::bindings::{ @@ -15,7 +18,7 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; -/// An object that responsible to catch any exception which raised +/// An object that is responsible to catch any exception which raised /// during the JS code invocation. #[derive(Debug, Clone)] pub struct TryCatch<'isolate_scope, 'isolate>( @@ -62,6 +65,7 @@ impl<'isolate_scope, 'isolate> TryCatch<'isolate_scope, 'isolate> { })) } + /// Returns `true` if the try_catch has terminated. pub fn has_terminated(&self) -> bool { let res = unsafe { v8_TryCatchHasTerminated(self.0.inner_val) }; res > 0 diff --git a/src/v8/types/unlocker.rs b/src/v8/types/unlocker.rs index 5cd54cb..3b6b21a 100644 --- a/src/v8/types/unlocker.rs +++ b/src/v8/types/unlocker.rs @@ -3,13 +3,33 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the thread-safe facilities. +//! +//! From [https://v8.github.io/api/head/classv8_1_1Unlocker.html#aa6789fe804cc059d9554c7ae7958c440]: +//! +//! > Multiple threads in V8 are allowed, but only one thread at a time +//! > is allowed to use any given V8 isolate, see the comments in the +//! > Isolate class. The definition of 'using a V8 isolate' includes +//! > accessing handles or holding onto object pointers obtained from V8 +//! > handles while in the particular V8 isolate. It is up to the user +//! > of V8 to ensure, perhaps with locking, that this constraint is not +//! > violated. In addition to any other synchronization mechanism that +//! > may be used, the v8::Locker and v8::Unlocker classes must be used +//! > to signal thread switches to V8. +//! > +//! > v8::Locker is a scoped lock object. While it's active, i.e. +//! > between its construction and destruction, the current thread is +//! > allowed to use the locked isolate. V8 guarantees that an isolate +//! > can be locked by at most one thread at any time. In other words, +//! > the scope of a v8::Locker is a critical section. use crate::v8::isolate_scope::IsolateScope; use crate::v8_c_raw::bindings::{v8_FreeUnlocker, v8_NewUnlocker, v8_unlocker}; use super::ScopedValue; -/// TODO add comment. +/// Releases the threads locked by the `Locker`, for example a +/// long-running callback from V8, to enable other threads to work. #[derive(Debug, Clone)] pub struct Unlocker<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_unlocker>, diff --git a/src/v8/types/utf8.rs b/src/v8/types/utf8.rs index 78ff33f..a306c2c 100644 --- a/src/v8/types/utf8.rs +++ b/src/v8/types/utf8.rs @@ -3,6 +3,8 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the UTF-8 object representation facilities, represented by +//! the [LocalUtf8] type. use crate::v8::types::ScopedValue; use crate::v8_c_raw::bindings::{v8_FreeUtf8, v8_ToUtf8, v8_Utf8PtrLen, v8_utf8_value}; @@ -14,7 +16,7 @@ use std::str; use super::any::LocalValueAny; use super::string::LocalString; -/// JS utf8 object +/// An UTF-8 string representation of an object. pub struct LocalUtf8<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_utf8_value>, ); From 69198c5463192a9d849d8660b1f1646e50ed27f8 Mon Sep 17 00:00:00 2001 From: Victor Polevoy Date: Mon, 24 Apr 2023 12:14:03 +0200 Subject: [PATCH 5/5] Add documentation and fix clippy issues. --- src/lib.rs | 73 +++++------- src/v8/context.rs | 13 ++- src/v8/context_scope.rs | 12 ++ src/v8/isolate_scope.rs | 39 +++++-- src/v8/types/any.rs | 135 ++++++++++++++++++++++- src/v8/types/mod.rs | 129 ++++++++++++++-------- src/v8/types/native_function.rs | 5 +- src/v8/types/native_function_template.rs | 30 +++-- src/v8/types/object.rs | 14 +++ src/v8/types/object_template.rs | 34 ++++-- src/v8/types/promise.rs | 4 +- 11 files changed, 356 insertions(+), 132 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index db6d664..aadd681 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ */ //! V8-rs is a crate containing bindings to the V8 C++ API. -#![warn(missing_docs)] +#![deny(missing_docs)] /// The module contains the rust-idiomatic data structures and functions. pub mod v8; @@ -57,17 +57,13 @@ impl From for RawIndex { mod json_path_tests { use crate as v8_rs; use crate::v8::types::any::LocalValueAny; - use crate::v8::types::native_function::LocalNativeFunction; use crate::v8::types::native_function_template::LocalNativeFunctionTemplate; use crate::v8::types::object_template::LocalObjectTemplate; use crate::v8::types::promise::LocalPromise; use crate::v8::types::try_catch::TryCatch; use crate::v8::types::utf8::LocalUtf8; use crate::v8::types::Value; - use crate::v8::{ - context_scope, isolate, isolate_scope, types, types::array, types::array_buffer, - types::native_function_template, types::object, types::set, types::utf8, v8_init, - }; + use crate::v8::{context_scope, isolate, isolate_scope, types, v8_init}; use v8_derive::new_native_function; @@ -199,7 +195,7 @@ mod json_path_tests { .create_native_function_template(|args, isolate_scope, ctx_scope| { let foo: LocalValueAny = isolate_scope.create_string("foo").try_into().unwrap(); let v: LocalValueAny = args.get(0).try_into().unwrap(); - let _res = v.call(ctx_scope, Some(&[&foo.into()])); + let _res = v.call(ctx_scope, Some(&[&foo])); None }) .try_into() @@ -256,7 +252,7 @@ mod json_path_tests { let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); assert!(script.run(&ctx_scope).is_none()); let exception = trycatch.get_exception(); - let exception_msg = exception.into_utf8().unwrap(); + let exception_msg = LocalUtf8::try_from(exception).unwrap(); assert_eq!(exception_msg.as_str(), "this is an error"); } @@ -275,10 +271,10 @@ mod json_path_tests { let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); assert!(script.run(&ctx_scope).is_none()); let exception = trycatch.get_exception(); - let exception_msg = exception.into_utf8().unwrap(); + let exception_msg = LocalUtf8::try_from(exception).unwrap(); assert_eq!(exception_msg.as_str(), "Error: this is an error!"); let trace = trycatch.get_trace(&ctx_scope); - let trace_str = trace.unwrap().into_utf8().unwrap(); + let trace_str = LocalUtf8::try_from(trace.unwrap()).unwrap(); assert!(trace_str.as_str().contains("at foo")); } @@ -368,7 +364,7 @@ mod json_path_tests { crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); - let res_utf8 = promise_res.into_utf8().unwrap(); + let res_utf8 = LocalUtf8::try_from(promise_res).unwrap(); assert_eq!(res_utf8.as_str(), "1"); } @@ -382,7 +378,7 @@ mod json_path_tests { globals.add_native_function("foo", |_args, isolate_scope, ctx_scope| { let resolver = ctx_scope.create_resolver(); resolver.resolve( - &ctx_scope, + ctx_scope, &isolate_scope.create_string("foo").try_into().unwrap(), ); let promise = resolver.get_promise(); @@ -404,7 +400,7 @@ mod json_path_tests { crate::v8::types::promise::PromiseState::Fulfilled ); let promise_res = promise.get_result(); - let res_utf8 = promise_res.into_utf8().unwrap(); + let res_utf8 = LocalUtf8::try_from(promise_res).unwrap(); assert_eq!(res_utf8.as_str(), "foo"); } @@ -420,7 +416,9 @@ mod json_path_tests { let script = ctx_scope.compile(&code_str); assert!(script.is_none()); assert_eq!( - trycatch.get_exception().into_utf8().unwrap().as_str(), + LocalUtf8::try_from(trycatch.get_exception()) + .unwrap() + .as_str(), "SyntaxError: Unexpected end of input" ); } @@ -438,7 +436,9 @@ mod json_path_tests { let res = script.run(&ctx_scope); assert!(res.is_none()); assert_eq!( - trycatch.get_exception().into_utf8().unwrap().as_str(), + LocalUtf8::try_from(trycatch.get_exception()) + .unwrap() + .as_str(), "ReferenceError: foo is not defined" ); } @@ -472,9 +472,7 @@ mod json_path_tests { let trycatch: TryCatch = isolate_scope.create_try_catch().try_into().unwrap(); let res = match script.run(&ctx_scope) { Some(_res) => Ok(()), - None => Err(trycatch - .get_exception() - .into_utf8() + None => Err(LocalUtf8::try_from(trycatch.get_exception()) .unwrap() .as_str() .to_string()), @@ -485,11 +483,7 @@ mod json_path_tests { #[test] fn test_value_is_object() { define_function_and_call("foo({})", "foo", |args, _isolate, _ctx_scope| { - if let Value::Object(_) = args.get(0) { - assert!(true); - } else { - assert!(false, "The value should have been an object!"); - } + assert!(args.get(0).is_object()); None }) .expect("Got error on function run"); @@ -501,7 +495,7 @@ mod json_path_tests { if let Value::Other(any) = args.get(0) { assert!(any.is_function()); } else { - assert!(false, "The value should have been an object!"); + unreachable!("The value should have been a function!"); } None }) @@ -517,7 +511,7 @@ mod json_path_tests { if let Value::Other(any) = args.get(0) { assert!(any.is_async_function()); } else { - assert!(false, "The value should have been an object!"); + unreachable!("The value should have been an async function!"); } None }, @@ -528,11 +522,7 @@ mod json_path_tests { #[test] fn test_value_is_string() { define_function_and_call("foo(\"foo\")", "foo", |args, _isolate, _ctx_scope| { - if let Value::String(_) = args.get(0) { - assert!(true); - } else { - assert!(false, "The value should have been a string!"); - } + assert!(args.get(0).is_string()); None }) .expect("Got error on function run"); @@ -541,11 +531,7 @@ mod json_path_tests { #[test] fn test_value_is_number() { define_function_and_call("foo(1)", "foo", |args, _isolate, _ctx_scope| { - if let Value::Double(_) = args.get(0) { - assert!(true); - } else { - assert!(false, "The value should have been a number!"); - } + assert!(args.get(0).is_number()); None }) .expect("Got error on function run"); @@ -557,11 +543,7 @@ mod json_path_tests { "foo(async function(){}())", "foo", |args, _isolate, _ctx_scope| { - if let Value::Other(any) = args.get(0) { - assert!(any.is_promise()); - } else { - assert!(false, "The value should have been a number!"); - } + assert!(args.get(0).is_promise()); None }, ) @@ -619,7 +601,7 @@ mod json_path_tests { new_native_function!(|_isolate, _ctx_scope, arg1: i64, arg2: f64, arg3: bool| { assert_eq!(arg1, 1); assert_eq!(arg2, 2.2); - assert_eq!(arg3, true); + assert!(arg3); Result::, String>::Ok(None) }), ) @@ -839,9 +821,8 @@ mod json_path_tests { assert_eq!(arg2, 2); if let Some(array) = arg3 { assert_eq!(array.len(), 2); - assert!(true); } else { - assert!(false, "Should have been an array."); + unreachable!("Should have been an array."); } Result::, String>::Ok(None) } @@ -864,11 +845,7 @@ mod json_path_tests { |_isolate, _ctx_scope, arg1: i64, arg2: i64, arg3: Option| { assert_eq!(arg1, 1); assert_eq!(arg2, 2); - if let Some(Value::Array(_)) = arg3 { - assert!(true); - } else { - assert!(false, "Should have been an array."); - } + assert!(arg3.unwrap().is_array()); Result::, String>::Ok(None) } ), diff --git a/src/v8/context.rs b/src/v8/context.rs index 7e7c7b4..9da5bcc 100644 --- a/src/v8/context.rs +++ b/src/v8/context.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! See [Context]. use crate::v8_c_raw::bindings::{ v8_ContextEnter, v8_FreeContext, v8_GetPrivateData, v8_NewContext, v8_ResetPrivateData, @@ -21,14 +22,14 @@ use crate::v8::types::object_template::LocalObjectTemplate; /// An RAII data guard which resets the private data slot after going /// out of scope. -pub struct V8ContextDataGuard<'context, 'data, T: 'data> { +pub struct ContextDataGuard<'context, 'data, T: 'data> { /// A raw index to reset after the guard goes out of scope. index: RawIndex, /// The context in which the guard should reset the variable. context: &'context Context, _phantom_data: PhantomData<&'data T>, } -impl<'context, 'data, T: 'data> V8ContextDataGuard<'context, 'data, T> { +impl<'context, 'data, T: 'data> ContextDataGuard<'context, 'data, T> { /// Creates a new data guard with the provided index and context scope. pub(crate) fn new>(index: I, context: &'context Context) -> Self { let index = index.into(); @@ -40,12 +41,14 @@ impl<'context, 'data, T: 'data> V8ContextDataGuard<'context, 'data, T> { } } -impl<'context, 'data, T: 'data> Drop for V8ContextDataGuard<'context, 'data, T> { +impl<'context, 'data, T: 'data> Drop for ContextDataGuard<'context, 'data, T> { fn drop(&mut self) { self.context.reset_private_data_raw(self.index); } } +/// A sandboxed execution context with its own set of built-in objects +/// and functions. pub struct Context { pub(crate) inner_ctx: *mut v8_context, } @@ -94,10 +97,10 @@ impl Context { &'context self, index: I, data: &'data T, - ) -> V8ContextDataGuard<'context, 'data, T> { + ) -> ContextDataGuard<'context, 'data, T> { let index = index.into(); self.set_private_data_raw(index, data); - V8ContextDataGuard::new(index, self) + ContextDataGuard::new(index, self) } /// Resets a private data on the context considering the index as diff --git a/src/v8/context_scope.rs b/src/v8/context_scope.rs index 796ec56..3c7897d 100644 --- a/src/v8/context_scope.rs +++ b/src/v8/context_scope.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! See [ContextScope]. use crate::v8_c_raw::bindings::v8_SetPrivateDataOnCtxRef; use crate::v8_c_raw::bindings::{ @@ -65,6 +66,8 @@ impl<'context_scope, 'data, 'isolate_scope, 'isolate, T: 'data> Drop } } +/// A lifetime guard for [super::context::Context], which sets the +/// execution context for all operations executed within a local scope. pub struct ContextScope<'isolate_scope, 'isolate> { pub(crate) inner_ctx_ref: *mut v8_context_ref, pub(crate) exit_on_drop: bool, @@ -82,6 +85,7 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { }) } + /// Returns all the global variables attached to an object. pub fn get_globals(&self) -> LocalObject<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ContextRefGetGlobals(self.inner_ctx_ref) }; LocalObject(ScopedValue { @@ -175,6 +179,7 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { ContextScopeDataGuard::new(index, self) } + /// Resets the private data at the provided slot. pub fn reset_private_data>(&self, index: I) { let index = index.into(); self.reset_private_data_raw(index) @@ -189,6 +194,9 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { }) } + /// Creates a new JavaScript object from the passed JavaScript + /// string object. The string should contain the object structure in + /// the JavaScript Object Notation (JSON). pub fn create_object_from_json( &self, val: &LocalString, @@ -206,6 +214,9 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { ) } + /// Creates a JavaScript string for the provided JavaScript object + /// containing its representation in the JavaScript Object Notation + /// (JSON). pub fn json_stringify( &self, val: &LocalValueAny, @@ -220,6 +231,7 @@ impl<'isolate_scope, 'isolate> ContextScope<'isolate_scope, 'isolate> { })) } + /// Creates a function. See [LocalNativeFunction]. pub fn create_native_function< T: for<'d, 'c> Fn( &LocalNativeFunctionArgs<'d, 'c>, diff --git a/src/v8/isolate_scope.rs b/src/v8/isolate_scope.rs index ea64459..5133966 100644 --- a/src/v8/isolate_scope.rs +++ b/src/v8/isolate_scope.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! See [IsolateScope]. use crate::v8_c_raw::bindings::{ v8_FreeHandlersScope, v8_IsolateEnter, v8_IsolateExit, v8_IsolateRaiseException, @@ -19,6 +20,10 @@ use super::types::any::LocalValueAny; use super::types::native_function_template::LocalNativeFunctionArgs; use super::types::Value; +/// Isolate scope is a lifetime guard for the [Isolate]. +/// It allows working with the bound [Isolate] object and correctly +/// drop the data associated with the [Isolate] when it goes out of +/// scope. #[derive(Debug)] pub struct IsolateScope<'isolate> { pub(crate) isolate: &'isolate Isolate, @@ -54,8 +59,8 @@ impl<'isolate> IsolateScope<'isolate> { unsafe { v8_IsolateRaiseException(self.isolate.inner_isolate, value.0.inner_val) }; } - /// Return a new try catch object. The object will catch any exception that was - /// raised during the JS code invocation. + /// Returns a new try catch object. The object will catch any + /// exception that was raised during the JS code invocation. #[must_use] pub fn create_try_catch<'isolate_scope>( &'isolate_scope self, @@ -63,50 +68,62 @@ impl<'isolate> IsolateScope<'isolate> { Value::new_try_catch(self) } - /// Create a new string object. + /// Create a new string object. See + /// [crate::v8::types::string::LocalString]. #[must_use] pub fn create_string<'isolate_scope>( &'isolate_scope self, s: &str, ) -> Value<'isolate_scope, 'isolate> { - Value::new_string(s, self) + Value::from_str(s, self) } - /// Create a new array object. + /// Create a new array object. See + /// [crate::v8::types::array::LocalArray]. #[must_use] pub fn create_array<'isolate_scope>( &'isolate_scope self, values: &[&LocalValueAny], ) -> Value<'isolate_scope, 'isolate> { - Value::new_array(values, self) + Value::from_array(values, self) } + /// Creates a new array buffer. See + /// [crate::v8::types::array_buffer::LocalArrayBuffer]. #[must_use] pub fn create_array_buffer<'isolate_scope>( &'isolate_scope self, bytes: &[u8], ) -> Value<'isolate_scope, 'isolate> { - Value::new_array_buffer(bytes, self) + Value::from_array_buffer(bytes, self) } + /// Creates a new object. See + /// [crate::v8::types::object::LocalObject]. #[must_use] pub fn create_object<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { Value::new_object(self) } + /// Creates a new external data object. See + /// [crate::v8::types::external_data::LocalExternalData]. #[must_use] pub fn create_external_data<'isolate_scope, T>( &'isolate_scope self, data: T, ) -> Value<'isolate_scope, 'isolate> { - Value::new_external_data(data, self) + Value::from_external_data(data, self) } + /// Creates a new set object. See + /// [crate::v8::types::set::LocalSet]. #[must_use] pub fn create_set<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { Value::new_set(self) } + /// Creates a new boolean object. See + /// [crate::v8::types::LocalValueBoolean]. #[must_use] pub fn create_bool<'isolate_scope>( &'isolate_scope self, @@ -115,6 +132,8 @@ impl<'isolate> IsolateScope<'isolate> { Value::from_bool(val, self) } + /// Creates a new `BigInt` object. See + /// [crate::v8::types::LocalValueBigInteger]. pub fn create_long<'isolate_scope>( &'isolate_scope self, val: i64, @@ -122,6 +141,8 @@ impl<'isolate> IsolateScope<'isolate> { Value::from_i64(val, self) } + /// Creates a new `Number` primitive. See + /// [crate::v8::types::LocalValueNumber]. pub fn create_double<'isolate_scope>( &'isolate_scope self, val: f64, @@ -129,6 +150,8 @@ impl<'isolate> IsolateScope<'isolate> { Value::from_f64(val, self) } + /// Creates a new `null` object. See + /// [crate::v8::types::LocalValueNull]. pub fn create_null<'isolate_scope>(&'isolate_scope self) -> Value<'isolate_scope, 'isolate> { Value::new_null(self) } diff --git a/src/v8/types/any.rs b/src/v8/types/any.rs index 34d25f7..b6ce671 100644 --- a/src/v8/types/any.rs +++ b/src/v8/types/any.rs @@ -32,21 +32,146 @@ use super::{ /// A type the objects of [LocalValueAny] can hold. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum Type { - Integer, - Double, + /// The `BigInt` type in JavaScript. + /// BigInt values represent numeric values which are too large to be + /// represented by the number + BigInteger, + /// The `Number` type in JavaScript. + /// All primitive numbers in JavaScript are of this (`Number`) type, + /// even "Integer" literals like `5` is a floating-point value of + /// type `Number`. + /// + /// # Example + /// + /// ```javascript + /// 255; // two-hundred and fifty-five + /// 255.0; // same number + /// 255 === 255.0; // true + /// 255 === 0xff; // true (hexadecimal notation) + /// 255 === 0b11111111; // true (binary notation) + /// 255 === 0.255e+3; // true (decimal exponential notation) + /// ``` + /// + /// See more at + /// . + Number, + /// A boolean JavaScript object (not primitive!). + /// + /// # Example + /// + /// ```javascript + /// const x = new Boolean(false); + /// if (x) { + /// // this code is executed + /// } + /// // However: + /// const x = false; + /// if (x) { + /// // this code is not executed + /// } + /// ``` Boolean, + /// A JavaScript's `null` value. Null, + /// The Set object lets you store unique values of any type, + /// whether primitive values or object references. + /// + /// # Example + /// + /// ```javascript + /// const mySet1 = new Set(); + /// + /// mySet1.add(1); // Set(1) { 1 } + /// ``` Set, + /// A foreign, non-JavaScript object which can be worked with in + /// JavaScript. It doesn't have methods, but can be passed and + /// received. Usually, for such objects an API is provided to work + /// with those. An example may be a C++ object, for which a pointer + /// is provided to JavaScript as [Type::ExternalData]. ExternalData, + /// A JavaScript object. See more at + /// . Object, + /// Resolver is an object which can resolve or reject promises. + /// See more at + /// . Resolver, + /// The Promise object represents the eventual completion + /// (or failure) of an asynchronous operation and its resulting + /// value. + /// + /// # Example + /// + /// ```javascript + /// new Promise((resolveOuter) => { + /// resolveOuter( + /// new Promise((resolveInner) => { + /// setTimeout(resolveInner, 1000); + /// }), + /// ); + /// }); + /// ``` Promise, + /// A JavaScript function. Every function is actually an object of + /// type `Function`. + /// + /// # [Example](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) + /// + /// ```javascript + /// // Create a global property with `var` + /// var x = 10; + /// + /// function createFunction1() { + /// const x = 20; + /// return new Function("return x;"); // this `x` refers to global `x` + /// } + /// + /// function createFunction2() { + /// const x = 20; + /// function f() { + /// return x; // this `x` refers to the local `x` above + /// } + /// return f; + /// } + /// + /// const f1 = createFunction1(); + /// console.log(f1()); // 10 + /// const f2 = createFunction2(); + /// console.log(f2()); // 20 + /// ``` Function, + /// An asynchrous function. Every async function in JavaScript is + /// actually an AsyncFunction object. + /// AsyncFunction, + /// A javascript array, which can be created like this: + /// ```javascript + /// const fruits = []; + /// fruits.push("banana", "apple", "peach"); + /// ``` Array, + /// The ArrayBuffer is used to represent a generic raw binary data + /// buffer. Example: + /// ```javascript + /// const buffer = new ArrayBuffer(8); + /// const view = new Int32Array(buffer); + /// ``` ArrayBuffer, + /// A literal string in JavaScript. For example: + /// ```javascript + /// const string1 = "A string primitive"; + /// const string2 = 'Also a string primitive'; + /// const string3 = `Yet another string primitive`; + /// ``` String, + /// A string object. A string object is a proper JavaScript object + /// which can be created the following way: + /// ```javascript + /// const stringObject = new String("A String object"); + /// ``` StringObject, + /// A UTF-8 encoded string. Utf8, } @@ -74,11 +199,11 @@ impl<'isolate_scope, 'isolate> LocalValueAny<'isolate_scope, 'isolate> { } else if self.is_function() { Type::Function } else if self.is_long() { - Type::Integer + Type::BigInteger } else if self.is_null() { Type::Null } else if self.is_number() { - Type::Double + Type::Number } else if self.is_object() { Type::Object } else if self.is_promise() { @@ -319,6 +444,8 @@ impl<'isolate_scope, 'isolate> LocalValueAny<'isolate_scope, 'isolate> { }) } + /// Returns `true` if the value stored is of type `External`. If it + /// is so, this object can be converted into the [LocalExternalData]. pub fn is_external_data(&self) -> bool { (unsafe { v8_ValueIsExternalData(self.0.inner_val) } != 0) } diff --git a/src/v8/types/mod.rs b/src/v8/types/mod.rs index dc25007..0f26a65 100644 --- a/src/v8/types/mod.rs +++ b/src/v8/types/mod.rs @@ -49,7 +49,7 @@ use crate::v8::OptionalTryFrom; use array::LocalArray; use array_buffer::LocalArrayBuffer; use external_data::LocalExternalData; -use native_function_template::V8LocalNativeFunctionArgsIter; +use native_function_template::LocalNativeFunctionArgsIter; use object::LocalObject; use promise::LocalPromise; use set::LocalSet; @@ -69,14 +69,15 @@ pub struct ScopedValue<'isolate_scope, 'isolate, BindingType: std::fmt::Debug> { pub(crate) isolate_scope: &'isolate_scope IsolateScope<'isolate>, } -/// An isolate-scoped [f64] local value in JavaScript. +/// An isolate-scoped `Number` local value in JavaScript. +/// Can be converted into [f64]. #[repr(transparent)] #[derive(Debug, Clone)] -pub struct LocalValueDouble<'isolate_scope, 'isolate>( +pub struct LocalValueNumber<'isolate_scope, 'isolate>( pub(crate) LocalValueAny<'isolate_scope, 'isolate>, ); -impl<'isolate_scope, 'isolate> LocalValueDouble<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalValueNumber<'isolate_scope, 'isolate> { fn new(value: f64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { let inner_val = unsafe { v8_ValueFromDouble(isolate_scope.isolate.inner_isolate, value) }; Self(LocalValueAny(ScopedValue { @@ -86,8 +87,8 @@ impl<'isolate_scope, 'isolate> LocalValueDouble<'isolate_scope, 'isolate> { } } -impl<'isolate_scope, 'isolate> From> for f64 { - fn from(value: LocalValueDouble<'isolate_scope, 'isolate>) -> Self { +impl<'isolate_scope, 'isolate> From> for f64 { + fn from(value: LocalValueNumber<'isolate_scope, 'isolate>) -> Self { unsafe { value.0.get_number() } } } @@ -96,12 +97,12 @@ impl<'isolate_scope, 'isolate> TryFrom> type Error = &'static str; fn try_from(val: LocalValueAny<'isolate_scope, 'isolate>) -> Result { - Ok(LocalValueDouble::try_from(val)?.into()) + Ok(LocalValueNumber::try_from(val)?.into()) } } impl<'isolate_scope, 'isolate> TryFrom> - for LocalValueDouble<'isolate_scope, 'isolate> + for LocalValueNumber<'isolate_scope, 'isolate> { type Error = &'static str; @@ -114,14 +115,29 @@ impl<'isolate_scope, 'isolate> TryFrom> } } -/// An isolate-scoped [i64] local value in JavaScript. +impl<'isolate_scope, 'isolate> TryFrom> + for LocalValueNumber<'isolate_scope, 'isolate> +{ + type Error = &'static str; + + fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { + match val { + Value::Number(n) => Ok(n), + Value::Other(any) => any.try_into(), + _ => Err("Value is not a number"), + } + } +} + +/// An isolate-scoped `BigInt` local value in JavaScript. +/// Can be converted into [i64]. #[repr(transparent)] #[derive(Debug, Clone)] -pub struct LocalValueInteger<'isolate_scope, 'isolate>( +pub struct LocalValueBigInteger<'isolate_scope, 'isolate>( pub(crate) LocalValueAny<'isolate_scope, 'isolate>, ); -impl<'isolate_scope, 'isolate> LocalValueInteger<'isolate_scope, 'isolate> { +impl<'isolate_scope, 'isolate> LocalValueBigInteger<'isolate_scope, 'isolate> { fn new(value: i64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { let inner_val = unsafe { v8_ValueFromLong(isolate_scope.isolate.inner_isolate, value) }; Self(LocalValueAny(ScopedValue { @@ -131,14 +147,14 @@ impl<'isolate_scope, 'isolate> LocalValueInteger<'isolate_scope, 'isolate> { } } -impl<'isolate_scope, 'isolate> From> for i64 { - fn from(value: LocalValueInteger<'isolate_scope, 'isolate>) -> Self { +impl<'isolate_scope, 'isolate> From> for i64 { + fn from(value: LocalValueBigInteger<'isolate_scope, 'isolate>) -> Self { unsafe { value.0.get_long() } } } impl<'isolate_scope, 'isolate> TryFrom> - for LocalValueInteger<'isolate_scope, 'isolate> + for LocalValueBigInteger<'isolate_scope, 'isolate> { type Error = &'static str; @@ -235,10 +251,10 @@ pub enum Value<'isolate_scope, 'isolate> { String(LocalString<'isolate_scope, 'isolate>), /// See [LocalValueBoolean]. Boolean(LocalValueBoolean<'isolate_scope, 'isolate>), - /// See [LocalValueInteger]. - Integer(LocalValueInteger<'isolate_scope, 'isolate>), - /// See [LocalValueDouble]. - Double(LocalValueDouble<'isolate_scope, 'isolate>), + /// See [LocalValueBigInteger]. + BigInteger(LocalValueBigInteger<'isolate_scope, 'isolate>), + /// See [LocalValueNumber]. + Number(LocalValueNumber<'isolate_scope, 'isolate>), /// See [LocalArrayBuffer]. ArrayBuffer(LocalArrayBuffer<'isolate_scope, 'isolate>), /// See [LocalArray]. @@ -266,12 +282,12 @@ pub enum Value<'isolate_scope, 'isolate> { impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { /// Creates a new double local value from [f64] for the passed [IsolateScope]. pub fn from_f64(value: f64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { - Value::Double(LocalValueDouble::new(value, isolate_scope)) + Value::Number(LocalValueNumber::new(value, isolate_scope)) } /// Creates a new integer local value from [i64] for the passed [IsolateScope]. pub fn from_i64(value: i64, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { - Value::Integer(LocalValueInteger::new(value, isolate_scope)) + Value::BigInteger(LocalValueBigInteger::new(value, isolate_scope)) } /// Creates a new boolean local value from [bool] for the passed [IsolateScope]. @@ -300,7 +316,7 @@ impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { } /// Creates a new local string for the passed [IsolateScope]. - pub fn new_string(s: &str, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { + pub fn from_str(s: &str, isolate_scope: &'isolate_scope IsolateScope<'isolate>) -> Self { Value::String(LocalString::new(s, isolate_scope)) } @@ -310,7 +326,7 @@ impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { } /// Creates a new local array buffer for the passed [IsolateScope]. - pub fn new_array_buffer( + pub fn from_array_buffer( bytes: &[u8], isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> Self { @@ -318,7 +334,7 @@ impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { } /// Creates a new local array for the passed [IsolateScope]. - pub fn new_array( + pub fn from_array( values: &[&LocalValueAny], isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> Self { @@ -331,7 +347,7 @@ impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { } /// Creates a new external data object for the passed [IsolateScope]. - pub fn new_external_data( + pub fn from_external_data( data: T, isolate_scope: &'isolate_scope IsolateScope<'isolate>, ) -> Self { @@ -351,6 +367,31 @@ impl<'isolate_scope, 'isolate> Value<'isolate_scope, 'isolate> { ) -> Self { Value::NativeFunctionTemplate(LocalNativeFunctionTemplate::new(function, isolate_scope)) } + + /// Returns `true` if the value stored is a JavaScript object. + pub fn is_object(&self) -> bool { + LocalObject::try_from(self.clone()).is_ok() + } + + /// Returns `true` if the value stored is a JavaScript string. + pub fn is_string(&self) -> bool { + LocalString::try_from(self.clone()).is_ok() + } + + /// Returns `true` if the value stored is a JavaScript `Number`. + pub fn is_number(&self) -> bool { + LocalValueNumber::try_from(self.clone()).is_ok() + } + + /// Returns `true` if the value stored is a JavaScript `Promise`. + pub fn is_promise(&self) -> bool { + LocalPromise::try_from(self.clone()).is_ok() + } + + /// Returns `true` if the value stored is a JavaScript `Array`. + pub fn is_array(&self) -> bool { + LocalArray::try_from(self.clone()).is_ok() + } } impl<'isolate_scope, 'isolate> From> @@ -368,11 +409,11 @@ impl<'isolate_scope, 'isolate> From> Some(Type::String) => { Self::String(LocalString::try_from(value).expect("Conversion error")) } - Some(Type::Integer) => { - Self::Integer(LocalValueInteger::try_from(value).expect("Conversion error")) + Some(Type::BigInteger) => { + Self::BigInteger(LocalValueBigInteger::try_from(value).expect("Conversion error")) } - Some(Type::Double) => { - Self::Double(LocalValueDouble::try_from(value).expect("Conversion error")) + Some(Type::Number) => { + Self::Number(LocalValueNumber::try_from(value).expect("Conversion error")) } Some(Type::Set) => Self::Set(LocalSet::try_from(value).expect("Conversion error")), Some(Type::Object) => { @@ -497,7 +538,7 @@ impl<'isolate_scope, 'isolate> TryFrom> for i64 fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { Ok(match val { - Value::Integer(i) => i.into(), + Value::BigInteger(i) => i.into(), Value::Other(any) => { if !any.is_long() { return Err("Value is not a long."); @@ -515,7 +556,7 @@ impl<'isolate_scope, 'isolate> TryFrom> for f64 fn try_from(val: Value<'isolate_scope, 'isolate>) -> Result { Ok(match val { - Value::Double(f) => f.into(), + Value::Number(f) => f.into(), Value::Other(any) => { if !any.is_number() { return Err("Value is not a number"); @@ -551,8 +592,8 @@ impl<'isolate_scope, 'isolate> TryFrom> Value::Array(array) => Ok(array.into()), Value::ArrayBuffer(array_buffer) => Ok(array_buffer.into()), Value::Boolean(boolean) => Ok(boolean.0), - Value::Integer(integer) => Ok(integer.0), - Value::Double(double) => Ok(double.0), + Value::BigInteger(integer) => Ok(integer.0), + Value::Number(double) => Ok(double.0), Value::Null(null) => Ok(null.0), Value::String(string) => Ok(string.into()), Value::Set(set) => Ok(set.into()), @@ -573,12 +614,12 @@ impl<'isolate_scope, 'isolate> TryFrom> macro_rules! from_iter_impl { ( $x:ty ) => { impl<'isolate_scope, 'isolate, 'a> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for $x + TryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for $x { type Error = &'static str; fn try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { match val.next() { Some(val) => std::convert::TryInto::<$x>::try_into(val), @@ -600,27 +641,27 @@ from_iter_impl!(LocalSet<'isolate_scope, 'isolate>); from_iter_impl!(LocalUtf8<'isolate_scope, 'isolate>); impl<'isolate_scope, 'isolate, 'a> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> + TryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Value<'isolate_scope, 'isolate> { type Error = &'static str; fn try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { val.next().ok_or("Wrong number of arguments given") } } impl<'isolate_scope, 'isolate, 'a, T> - OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for T + OptionalTryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for T where T: TryFrom, Error = &'static str>, { type Error = &'static str; fn optional_try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result, Self::Error> { let val = match val.next() { Some(v) => v, @@ -633,13 +674,13 @@ where } impl<'isolate_scope, 'isolate, 'a> - OptionalTryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> + OptionalTryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Value<'isolate_scope, 'isolate> { type Error = &'static str; fn optional_try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result, Self::Error> { Ok(val.next()) } @@ -665,27 +706,27 @@ impl<'isolate_scope, 'isolate, 'a> // } impl<'isolate_scope, 'isolate, 'a> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> + TryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec> { type Error = &'static str; fn try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { Ok(val.collect()) } } impl<'isolate_scope, 'isolate, 'a, T> - TryFrom<&mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec + TryFrom<&mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>> for Vec where T: TryFrom, Error = &'static str>, { type Error = &'static str; fn try_from( - val: &mut V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, + val: &mut LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a>, ) -> Result { Ok(val.map(|v| T::try_from(v).unwrap()).collect()) } diff --git a/src/v8/types/native_function.rs b/src/v8/types/native_function.rs index 9159cee..dc7f1cb 100644 --- a/src/v8/types/native_function.rs +++ b/src/v8/types/native_function.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the native function facilities. use crate::v8_c_raw::bindings::{ v8_FreeNativeFunction, v8_NativeFunctionToValue, v8_local_native_function, @@ -13,7 +14,9 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; use super::Value; -/// Native function object +/// Native function object, which can be instantiated from a template +/// [super::LocalNativeFunctionTemplate] or created directly via +/// [crate::v8::context_scope::ContextScope::create_native_function]. pub struct LocalNativeFunction<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_native_function>, ); diff --git a/src/v8/types/native_function_template.rs b/src/v8/types/native_function_template.rs index 17615ef..4c3555e 100644 --- a/src/v8/types/native_function_template.rs +++ b/src/v8/types/native_function_template.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the native function template facilities. use crate::v8_c_raw::bindings::v8_NewNativeFunctionTemplate; use crate::v8_c_raw::bindings::{ @@ -25,6 +26,13 @@ use super::any::LocalValueAny; use super::Value; /// Native function template object. +/// +/// A [LocalNativeFunctionTemplate] is used to create functions at +/// runtime. There can only be one function created from a +/// [LocalNativeFunctionTemplate] in a context. The lifetime of the +/// created function is equal to the lifetime of the context. So in case +/// the embedder needs to create temporary functions that can be +/// collected using Scripts is preferred. #[derive(Debug, Clone)] pub struct LocalNativeFunctionTemplate<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_native_function_template>, @@ -59,7 +67,7 @@ impl<'isolate_scope, 'isolate> LocalNativeFunctionTemplate<'isolate_scope, 'isol } } -/// Native function args +/// An array of arguments for a [LocalNativeFunctionTemplate]. pub struct LocalNativeFunctionArgs<'isolate_scope, 'isolate> { pub(crate) inner_arr: *mut v8_local_value_arr, len: usize, @@ -127,10 +135,9 @@ pub(crate) extern "C" fn native_basic_function< } impl<'isolate_scope, 'isolate> LocalNativeFunctionTemplate<'isolate_scope, 'isolate> { - pub fn to_function( - &self, - ctx_scope: &ContextScope, - ) -> LocalNativeFunction<'isolate_scope, 'isolate> { + /// Builds (instantiates) a [LocalNativeFunction] out of this + /// template. + pub fn build(&self, ctx_scope: &ContextScope) -> LocalNativeFunction<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_NativeFunctionTemplateToFunction(ctx_scope.inner_ctx_ref, self.0.inner_val) }; @@ -177,23 +184,26 @@ impl<'isolate_scope, 'isolate> LocalNativeFunctionArgs<'isolate_scope, 'isolate> }) } - pub const fn persist(&self) {} + // pub const fn persist(&self) {} - pub fn iter<'a>(&'a self) -> V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { - V8LocalNativeFunctionArgsIter { + /// Returns an iterator [LocalNativeFunctionArgsIter] over the + /// function arguments. + pub fn iter<'a>(&'a self) -> LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { + LocalNativeFunctionArgsIter { args: self, index: 0, } } } -pub struct V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { +/// An iterator over the function arguments of a [LocalNativeFunction]. +pub struct LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { args: &'a LocalNativeFunctionArgs<'isolate_scope, 'isolate>, index: usize, } impl<'isolate_scope, 'isolate, 'a> Iterator - for V8LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> + for LocalNativeFunctionArgsIter<'isolate_scope, 'isolate, 'a> { type Item = Value<'isolate_scope, 'isolate>; fn next(&mut self) -> Option { diff --git a/src/v8/types/object.rs b/src/v8/types/object.rs index 4b0ad70..d334bdb 100644 --- a/src/v8/types/object.rs +++ b/src/v8/types/object.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! The JavaScript object facilities. use crate::v8_c_raw::bindings::{ v8_FreeObject, v8_GetInternalFieldCount, v8_NewObject, v8_ObjectFreeze, v8_ObjectGet, @@ -70,6 +71,7 @@ impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { self.get(ctx_scope, &key) } + /// Sets the value for the key within this [LocalObject]. pub fn set(&self, ctx_scope: &ContextScope, key: &LocalValueAny, val: &LocalValueAny) { unsafe { v8_ObjectSet( @@ -81,6 +83,7 @@ impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { }; } + /// Adds a method to this [LocalObject]. pub fn set_native_function< T: for<'d, 'e> Fn( &LocalNativeFunctionArgs<'d, 'e>, @@ -107,10 +110,13 @@ impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { }; } + /// Sets the value in an internal field. pub fn set_internal_field(&self, index: usize, val: &LocalValueAny) { unsafe { v8_ObjectSetInternalField(self.0.inner_val, index, val.0.inner_val) }; } + /// Returns the value of an internal field accessible by the + /// provided `index`. pub fn get_internal_field(&self, index: usize) -> Value<'isolate_scope, 'isolate> { let inner_val = unsafe { v8_ObjectGetInternalField(self.0.inner_val, index) }; LocalValueAny(ScopedValue { @@ -120,10 +126,18 @@ impl<'isolate_scope, 'isolate> LocalObject<'isolate_scope, 'isolate> { .into() } + /// Returns the number of internal fields. pub fn get_internal_field_count(&self) -> usize { unsafe { v8_GetInternalFieldCount(self.0.inner_val) } } + /// Freezes this [LocalObject]. Freezing an object prevents + /// extensions and makes existing properties non-writable and + /// non-configurable. A frozen object can no longer be changed: + /// new properties cannot be added, existing properties cannot be + /// removed, their enumerability, configurability, writability, or + /// value cannot be changed, and the object's prototype cannot be + /// re-assigned. freeze() returns the same object that was passed in. pub fn freeze(&self, ctx_scope: &ContextScope) { unsafe { v8_ObjectFreeze(ctx_scope.inner_ctx_ref, self.0.inner_val) }; } diff --git a/src/v8/types/object_template.rs b/src/v8/types/object_template.rs index 1155d4d..f30fc24 100644 --- a/src/v8/types/object_template.rs +++ b/src/v8/types/object_template.rs @@ -3,6 +3,7 @@ * Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or * the Server Side Public License v1 (SSPLv1). */ +//! Contains the object template facilities. use crate::v8_c_raw::bindings::{ v8_FreeObjectTemplate, v8_FreePersistedObjectTemplate, v8_NewObjectTemplate, @@ -22,7 +23,9 @@ use crate::v8::types::ScopedValue; use super::any::LocalValueAny; -/// JS object template. +/// The JavaScript object template, which is essentially a JavaScript +/// class builder: allows to set children objects (as in a map), add +/// member functions. #[derive(Debug, Clone)] pub struct LocalObjectTemplate<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_object_template>, @@ -44,7 +47,8 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { }; } - /// Same as `set_native_function` but gets the key as &str and the native function as closure. + /// Same as [set_native_function] but gets the key as &str and the + /// native function as closure. pub fn add_native_function< T: for<'d, 'e> Fn( &LocalNativeFunctionArgs<'d, 'e>, @@ -71,11 +75,13 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { unsafe { v8_ObjectTemplateSetObject(self.0.inner_val, name.0.inner_val, obj.0.inner_val) }; } + /// Sets the number of internal fields for objects generated from + /// this template. pub fn set_internal_field_count(&mut self, count: usize) { unsafe { v8_ObjectTemplateSetInternalFieldCount(self.0.inner_val, count) }; } - /// Same as `set_object` but gets the key as &str + /// Same as [set_object] but gets the key as an [str] slice. pub fn add_object(&mut self, name: &str, obj: &Self) { let obj_name = self.0.isolate_scope.create_string(name).try_into().unwrap(); self.set_object(&obj_name, obj); @@ -86,7 +92,7 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { unsafe { v8_ObjectTemplateSetValue(self.0.inner_val, name.0.inner_val, obj.0.inner_val) }; } - /// Same as `set_value` but gets the key as &str + /// Same as [set_value] but gets the key as an [str] slice. pub fn add_value(&mut self, name: &str, obj: &LocalValueAny) { let val_name = self.0.isolate_scope.create_string(name).try_into().unwrap(); self.set_value(&val_name, obj); @@ -103,11 +109,13 @@ impl<'isolate_scope, 'isolate> LocalObjectTemplate<'isolate_scope, 'isolate> { }) } - pub fn persist(&self) -> V8PersistedObjectTemplate { + /// Persists the [LocalObjectTemplate] by converting it into a + /// [PersistedObjectTemplate] which can outlive its [IsolateScope]. + pub fn persist(&self) -> PersistedObjectTemplate { let inner_persist = unsafe { v8_ObjectTemplatePersist(self.0.isolate_scope.isolate.inner_isolate, self.0.inner_val) }; - V8PersistedObjectTemplate { + PersistedObjectTemplate { inner_persisted_obj_template: inner_persist, } } @@ -119,11 +127,15 @@ impl<'isolate_scope, 'isolate> Drop for LocalObjectTemplate<'isolate_scope, 'iso } } -pub struct V8PersistedObjectTemplate { +/// The same as [LocalObjectTemplate] but not associated with an +/// [IsolateScope]. +pub struct PersistedObjectTemplate { pub(crate) inner_persisted_obj_template: *mut v8_persisted_object_template, } -impl V8PersistedObjectTemplate { +impl PersistedObjectTemplate { + /// Converts the [PersistedObjectTemplate] into a + /// [LocalObjectTemplate] within the provided [IsolateScope]. pub fn to_local<'isolate_scope, 'isolate>( &self, isolate_scope: &'isolate_scope IsolateScope<'isolate>, @@ -141,10 +153,10 @@ impl V8PersistedObjectTemplate { } } -unsafe impl Sync for V8PersistedObjectTemplate {} -unsafe impl Send for V8PersistedObjectTemplate {} +unsafe impl Sync for PersistedObjectTemplate {} +unsafe impl Send for PersistedObjectTemplate {} -impl Drop for V8PersistedObjectTemplate { +impl Drop for PersistedObjectTemplate { fn drop(&mut self) { unsafe { v8_FreePersistedObjectTemplate(self.inner_persisted_obj_template) } } diff --git a/src/v8/types/promise.rs b/src/v8/types/promise.rs index 31deee3..fddcf21 100644 --- a/src/v8/types/promise.rs +++ b/src/v8/types/promise.rs @@ -20,6 +20,8 @@ use super::any::LocalValueAny; /// A promise is an object representing an eventual completion /// (successful or not) of an asynchronous operation and its resulting /// value. +/// +/// See [Mozilla Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). pub struct LocalPromise<'isolate_scope, 'isolate>( pub(crate) ScopedValue<'isolate_scope, 'isolate, v8_local_promise>, ); @@ -36,7 +38,7 @@ pub enum PromiseState { } impl<'isolate_scope, 'isolate> LocalPromise<'isolate_scope, 'isolate> { - /// Set resolve and reject callbacks + /// Set resolve and reject callbacks. pub fn then( &self, ctx: &ContextScope,