diff --git a/src/binding.cc b/src/binding.cc index ea9dac08..423e6681 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -478,57 +478,68 @@ bool v8__Value__SameValue(const v8::Value& self, v8::Value* that) { return self.SameValue(ptr_to_local(that)); } -v8::Uint32* v8__Value__ToUint32(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToUint32(ptr_to_local(context))); +v8::Uint32* v8__Value__ToUint32(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToUint32(context)); } -v8::Int32* v8__Value__ToInt32(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToInt32(ptr_to_local(context))); +v8::Int32* v8__Value__ToInt32(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToInt32(context)); } -v8::Integer* v8__Value__ToInteger(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToInteger(ptr_to_local(context))); +v8::Integer* v8__Value__ToInteger(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToInteger(context)); } -v8::BigInt* v8__Value__ToBigInt(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToBigInt(ptr_to_local(context))); +v8::BigInt* v8__Value__ToBigInt(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToBigInt(context)); } -v8::String* v8__Value__ToString(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToString(ptr_to_local(context))); +v8::String* v8__Value__ToString(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToString(context)); } v8::String* v8__Value__ToDetailString(const v8::Value& self, - v8::Context* context) { - return maybe_local_to_ptr(self.ToDetailString(ptr_to_local(context))); + v8::Local context) { + return maybe_local_to_ptr(self.ToDetailString(context)); } -v8::Number* v8__Value__ToNumber(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToNumber(ptr_to_local(context))); +v8::Number* v8__Value__ToNumber(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToNumber(context)); } -v8::Object* v8__Value__ToObject(const v8::Value& self, v8::Context* context) { - return maybe_local_to_ptr(self.ToObject(ptr_to_local(context))); +v8::Object* v8__Value__ToObject(const v8::Value& self, + v8::Local context) { + return maybe_local_to_ptr(self.ToObject(context)); } -void v8__Value__NumberValue(const v8::Value& self, v8::Context* context, +void v8__Value__NumberValue(const v8::Value& self, + v8::Local context, v8::Maybe* out) { - *out = self.NumberValue(ptr_to_local(context)); + *out = self.NumberValue(context); } -void v8__Value__IntegerValue(const v8::Value& self, v8::Context* context, +void v8__Value__IntegerValue(const v8::Value& self, + v8::Local context, v8::Maybe* out) { - *out = self.IntegerValue(ptr_to_local(context)); + *out = self.IntegerValue(context); } -void v8__Value__Uint32Value(const v8::Value& self, v8::Context* context, +void v8__Value__Uint32Value(const v8::Value& self, + v8::Local context, v8::Maybe* out) { - *out = self.Uint32Value(ptr_to_local(context)); + *out = self.Uint32Value(context); } -void v8__Value__Int32Value(const v8::Value& self, v8::Context* context, +void v8__Value__Int32Value(const v8::Value& self, + v8::Local context, v8::Maybe* out) { - *out = self.Int32Value(ptr_to_local(context)); + *out = self.Int32Value(context); } v8::Primitive* v8__Null(v8::Isolate* isolate) { diff --git a/src/isolate.rs b/src/isolate.rs index a922f00b..f3a4c08e 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -78,10 +78,6 @@ extern "C" { fn v8__Isolate__GetNumberOfDataSlots(this: *const Isolate) -> u32; fn v8__Isolate__Enter(this: *mut Isolate); fn v8__Isolate__Exit(this: *mut Isolate); - fn v8__Isolate__GetCurrentContext(this: *mut Isolate) -> *mut Context; - fn v8__Isolate__GetEnteredOrMicrotaskContext( - this: *mut Isolate, - ) -> *mut Context; fn v8__Isolate__SetCaptureStackTraceForUncaughtExceptions( this: *mut Isolate, caputre: bool, @@ -204,24 +200,6 @@ impl Isolate { unsafe { v8__Isolate__Exit(self) } } - /// Returns the context of the currently running JavaScript, or the context - /// on the top of the stack if no JavaScript is running. - pub fn get_current_context<'sc>(&mut self) -> Local<'sc, Context> { - unsafe { Local::from_raw(v8__Isolate__GetCurrentContext(self)).unwrap() } - } - - /// Returns either the last context entered through V8's C++ API, or the - /// context of the currently running microtask while processing microtasks. - /// If a context is entered while executing a microtask, that context is - /// returned. - pub fn get_entered_or_microtask_context<'sc>( - &mut self, - ) -> Local<'sc, Context> { - unsafe { - Local::from_raw(v8__Isolate__GetEnteredOrMicrotaskContext(self)).unwrap() - } - } - /// Tells V8 to capture current stack trace when uncaught exception occurs /// and report it to the message listeners. The option is off by default. pub fn set_capture_stack_trace_for_uncaught_exceptions( diff --git a/src/lib.rs b/src/lib.rs index 6b92f401..9a9cf320 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,17 +47,14 @@ //! InIsolate which gives access to &mut Isolate is implemented for all scopes, //! ToLocal (I might rename that) is implemented for all Scopes in which new //! Local handles can be created and it sets the appropriate lifetime on them. -//! InContext means that a context has been entered (I'll make sure they have a -//! get_context() method), etc. //! //! Furthermore, many callbacks will receive receive an appropriate Scope object //! as their first argument, which 'encodes' the the state the isolate is in //! when the callback is called. E.g. a FunctionCallbackScope implements -//! InIsolate + InContext + (there is an active context) and ToLocal (it acts as -//! a handlescope). HostImportModuleDynamicallyScope would also implement -//! InIsolate + InContext plus EscapeLocal (it doesn't act like a HandleScope, -//! but it lets you safely escape one MaybeLocal which is returned to the -//! caller. +//! InIsolate + and ToLocal (it acts as a HandleScope). +//! HostImportModuleDynamicallyScope would also implement InIsolate plus +//! EscapeLocal (it doesn't act like a HandleScope, but it lets you safely +//! escape one MaybeLocal which is returned to the caller). //! //! In a nutshell, that's it. //! diff --git a/src/scope_traits.rs b/src/scope_traits.rs index e753f68b..6852464e 100644 --- a/src/scope_traits.rs +++ b/src/scope_traits.rs @@ -141,20 +141,28 @@ where } } -pub trait InContext: InIsolate {} -impl<'s> InContext for Entered<'s, FunctionCallbackInfo, ()> {} -impl<'s> InContext for Entered<'s, PropertyCallbackInfo, ()> {} -impl<'s, X> InContext for Entered<'s, CallbackScope> {} -impl<'s, P> InContext for Entered<'s, ContextScope, P> {} -impl<'s, P> InContext for Entered<'s, HandleScope, P> where P: InContext {} -impl<'s, P> InContext for Entered<'s, EscapableHandleScope, P> where P: InContext -{} +extern "C" { + fn v8__Isolate__GetCurrentContext(this: *mut Isolate) -> *mut Context; + fn v8__Isolate__GetEnteredOrMicrotaskContext( + this: *mut Isolate, + ) -> *mut Context; +} /// When scope implements this trait, this means that Local handles can be /// created inside it. pub trait ToLocal<'s>: InIsolate { unsafe fn to_local(&mut self, ptr: *mut T) -> Option> { - crate::Local::<'s, T>::from_raw(ptr) + Local::from_raw(ptr) + } + + fn get_current_context(&mut self) -> Option> { + unsafe { Local::from_raw(v8__Isolate__GetCurrentContext(self.isolate())) } + } + + fn get_entered_or_microtask_context(&mut self) -> Option> { + unsafe { + Local::from_raw(v8__Isolate__GetEnteredOrMicrotaskContext(self.isolate())) + } } } @@ -162,7 +170,10 @@ impl<'s> ToLocal<'s> for Entered<'s, FunctionCallbackInfo> {} impl<'s> ToLocal<'s> for Entered<'s, PropertyCallbackInfo> {} impl<'s, P> ToLocal<'s> for Entered<'s, HandleScope, P> {} impl<'s, P> ToLocal<'s> for Entered<'s, EscapableHandleScope, P> {} -impl<'s, P> ToLocal<'s> for Entered<'s, ContextScope, P> where P: ToLocal<'s> {} +impl<'s, 'p: 's, P> ToLocal<'p> for Entered<'s, ContextScope, P> where + P: ToLocal<'p> +{ +} pub trait ToLocalOrReturnsLocal<'s>: InIsolate {} impl<'s, E> ToLocalOrReturnsLocal<'s> for E where E: ToLocal<'s> {} @@ -213,10 +224,33 @@ where } } +impl<'s, 'p: 's, S, P> Entered<'s, S, P> +where + Self: ToLocal<'p>, +{ + /// Returns the context of the currently running JavaScript, or the context + /// on the top of the stack if no JavaScript is running. + pub fn get_current_context(&mut self) -> Option> { + >::get_current_context(self) + } + + /// Returns either the last context entered through V8's C++ API, or the + /// context of the currently running microtask while processing microtasks. + /// If a context is entered while executing a microtask, that context is + /// returned. + pub fn get_entered_or_microtask_context( + &mut self, + ) -> Option> { + >::get_entered_or_microtask_context(self) + } +} + impl<'s, 'p: 's, S, P> Entered<'s, S, P> where Self: EscapeLocal<'s, 'p>, { + /// Pushes the value into the previous scope and returns a handle to it. + /// Cannot be called twice. pub fn escape(&mut self, local: Local) -> Local<'p, T> { >::escape(self, local) } diff --git a/src/script.rs b/src/script.rs index 1fcbe6e5..a11fdaa4 100644 --- a/src/script.rs +++ b/src/script.rs @@ -5,7 +5,6 @@ use std::ptr::null; use crate::support::Opaque; use crate::Boolean; use crate::Context; -use crate::InContext; use crate::Integer; use crate::Local; use crate::String; @@ -46,7 +45,7 @@ pub struct Script(Opaque); impl Script { /// A shorthand for ScriptCompiler::Compile(). pub fn compile<'sc>( - scope: &mut (impl ToLocal<'sc> + InContext), + scope: &mut impl ToLocal<'sc>, mut context: Local, mut source: Local, origin: Option<&ScriptOrigin>, diff --git a/src/value.rs b/src/value.rs index 9f5945cb..d85ff264 100644 --- a/src/value.rs +++ b/src/value.rs @@ -69,36 +69,39 @@ extern "C" { fn v8__Value__StrictEquals(this: &Value, that: &Value) -> bool; fn v8__Value__SameValue(this: &Value, that: &Value) -> bool; - fn v8__Value__ToBigInt(this: &Value, context: *mut Context) -> *mut BigInt; - fn v8__Value__ToNumber(this: &Value, context: *mut Context) -> *mut Number; - fn v8__Value__ToString(this: &Value, context: *mut Context) -> *mut String; + fn v8__Value__ToBigInt(this: &Value, context: Local) -> *mut BigInt; + fn v8__Value__ToNumber(this: &Value, context: Local) -> *mut Number; + fn v8__Value__ToString(this: &Value, context: Local) -> *mut String; fn v8__Value__ToDetailString( this: &Value, - context: *mut Context, + context: Local, ) -> *mut String; - fn v8__Value__ToObject(this: &Value, context: *mut Context) -> *mut Object; - fn v8__Value__ToInteger(this: &Value, context: *mut Context) -> *mut Integer; - fn v8__Value__ToUint32(this: &Value, context: *mut Context) -> *mut Uint32; - fn v8__Value__ToInt32(this: &Value, context: *mut Context) -> *mut Int32; + fn v8__Value__ToObject(this: &Value, context: Local) -> *mut Object; + fn v8__Value__ToInteger( + this: &Value, + context: Local, + ) -> *mut Integer; + fn v8__Value__ToUint32(this: &Value, context: Local) -> *mut Uint32; + fn v8__Value__ToInt32(this: &Value, context: Local) -> *mut Int32; fn v8__Value__NumberValue( this: &Value, - context: *mut Context, + context: Local, out: *mut Maybe, ); fn v8__Value__IntegerValue( this: &Value, - context: *mut Context, + context: Local, out: *mut Maybe, ); fn v8__Value__Uint32Value( this: &Value, - context: *mut Context, + context: Local, out: *mut Maybe, ); fn v8__Value__Int32Value( this: &Value, - context: *mut Context, + context: Local, out: *mut Maybe, ); } @@ -396,112 +399,112 @@ impl Value { &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToBigInt(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToBigInt(self, context)) + }) } pub fn to_number<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToNumber(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToNumber(self, context)) + }) } pub fn to_string<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToString(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToString(self, context)) + }) } pub fn to_detail_string<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToDetailString(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToDetailString(self, context)) + }) } pub fn to_object<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToObject(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToObject(self, context)) + }) } pub fn to_integer<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToInteger(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToInteger(self, context)) + }) } pub fn to_uint32<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToUint32(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToUint32(self, context)) + }) } pub fn to_int32<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option> { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - unsafe { Local::from_raw(v8__Value__ToInt32(self, &mut *context)) } + scope.get_current_context().and_then(|context| unsafe { + Local::from_raw(v8__Value__ToInt32(self, context)) + }) } pub fn number_value<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - let mut out = Maybe::::default(); - unsafe { v8__Value__NumberValue(self, &mut *context, &mut out) }; - out.into() + scope.get_current_context().and_then(|context| unsafe { + let mut out = Maybe::::default(); + v8__Value__NumberValue(self, context, &mut out); + out.into() + }) } pub fn integer_value<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - let mut out = Maybe::::default(); - unsafe { v8__Value__IntegerValue(self, &mut *context, &mut out) }; - out.into() + scope.get_current_context().and_then(|context| unsafe { + let mut out = Maybe::::default(); + v8__Value__IntegerValue(self, context, &mut out); + out.into() + }) } pub fn uint32_value<'sc>( &self, scope: &mut impl ToLocal<'sc>, ) -> Option { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - let mut out = Maybe::::default(); - unsafe { v8__Value__Uint32Value(self, &mut *context, &mut out) }; - out.into() + scope.get_current_context().and_then(|context| unsafe { + let mut out = Maybe::::default(); + v8__Value__Uint32Value(self, context, &mut out); + out.into() + }) } pub fn int32_value<'sc>(&self, scope: &mut impl ToLocal<'sc>) -> Option { - let isolate = scope.isolate(); - let mut context = isolate.get_current_context(); - let mut out = Maybe::::default(); - unsafe { v8__Value__Int32Value(self, &mut *context, &mut out) }; - out.into() + scope.get_current_context().and_then(|context| unsafe { + let mut out = Maybe::::default(); + v8__Value__Int32Value(self, context, &mut out); + out.into() + }) } } diff --git a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr index 4086c2dd..ebd535ac 100644 --- a/tests/compile_fail/handle_scope_escape_to_nowhere.stderr +++ b/tests/compile_fail/handle_scope_escape_to_nowhere.stderr @@ -14,5 +14,5 @@ error[E0277]: the trait bound `rusty_v8::scope::Entered<'_, rusty_v8::scope::Cal as rusty_v8::scope_traits::ToLocal<'s>> as rusty_v8::scope_traits::ToLocal<'s>> as rusty_v8::scope_traits::ToLocal<'s>> - as rusty_v8::scope_traits::ToLocal<'s>> + as rusty_v8::scope_traits::ToLocal<'p>> = note: required because of the requirements on the impl of `rusty_v8::scope_traits::ToLocalOrReturnsLocal<'_>` for `rusty_v8::scope::Entered<'_, rusty_v8::scope::CallbackScope>` diff --git a/tests/test_api.rs b/tests/test_api.rs index be8ece4f..900c64ec 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -226,6 +226,32 @@ fn escapable_handle_scope() { } } +#[test] +fn context_scope() { + let _setup_guard = setup(); + let mut params = v8::Isolate::create_params(); + params.set_array_buffer_allocator(v8::new_default_allocator()); + let mut isolate = v8::Isolate::new(params); + + let mut hs = v8::HandleScope::new(&mut isolate); + let scope = hs.enter(); + + assert!(scope.get_current_context().is_none()); + assert!(scope.get_entered_or_microtask_context().is_none()); + + { + let context = v8::Context::new(scope); + let mut cs = v8::ContextScope::new(scope, context); + let scope = cs.enter(); + + scope.get_current_context().unwrap(); + scope.get_entered_or_microtask_context().unwrap(); + } + + assert!(scope.get_current_context().is_none()); + assert!(scope.get_entered_or_microtask_context().is_none()); +} + #[test] fn microtasks() { let _setup_guard = setup(); @@ -378,7 +404,7 @@ fn v8_str<'sc>( } fn eval<'sc>( - scope: &mut (impl v8::ToLocal<'sc> + v8::InContext), + scope: &mut impl v8::ToLocal<'sc>, context: v8::Local, code: &'static str, ) -> Option> { @@ -601,7 +627,7 @@ fn add_message_listener() { let mut sc = v8::CallbackScope::new(message); let mut sc = v8::HandleScope::new(sc.enter()); let scope = sc.enter(); - let context = scope.isolate().get_current_context(); + let context = scope.get_current_context().unwrap(); let message_str = message.get(scope); assert_eq!(message_str.to_rust_string_lossy(scope), "Uncaught foo"); assert_eq!(Some(1), message.get_line_number(context)); @@ -1135,7 +1161,7 @@ fn object_set_accessor() { key: v8::Local, args: v8::PropertyCallbackArguments, mut rv: v8::ReturnValue| { - let context = scope.isolate().get_current_context(); + let context = scope.get_current_context().unwrap(); let this = args.this(); let expected_key = v8::String::new(scope, "getter_key").unwrap();