diff --git a/src/binding.cc b/src/binding.cc index c0a371e4..7fe1067e 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1490,6 +1490,16 @@ const v8::Script* v8__Script__Compile(const v8::Context& context, const_cast(&origin))); } +const v8::UnboundScript* v8__Script__GetUnboundScript( + const v8::Script& script) { + return local_to_ptr(ptr_to_local(&script)->GetUnboundScript()); +} + +const v8::Script* v8__UnboundScript__BindToCurrentContext( + const v8::UnboundScript& unbound_script) { + return local_to_ptr(ptr_to_local(&unbound_script)->BindToCurrentContext()); +} + const v8::Value* v8__Script__Run(const v8::Script& script, const v8::Context& context) { return maybe_local_to_ptr(ptr_to_local(&script)->Run(ptr_to_local(&context))); diff --git a/src/lib.rs b/src/lib.rs index a808a7d3..755894b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ mod support; mod symbol; mod template; mod typed_array; +mod unbound_script; mod value; mod value_deserializer; mod value_serializer; diff --git a/src/script.rs b/src/script.rs index 44ab2bb8..9b444400 100644 --- a/src/script.rs +++ b/src/script.rs @@ -9,6 +9,7 @@ use crate::Integer; use crate::Local; use crate::Script; use crate::String; +use crate::UnboundScript; use crate::Value; /// The origin, within a file, of a script. @@ -22,6 +23,9 @@ extern "C" { source: *const String, origin: *const ScriptOrigin, ) -> *const Script; + fn v8__Script__GetUnboundScript( + script: *const Script, + ) -> *const UnboundScript; fn v8__Script__Run( script: *const Script, context: *const Context, @@ -59,6 +63,18 @@ impl Script { } } + /// Returns the corresponding context-unbound script. + pub fn get_unbound_script<'s>( + &self, + scope: &mut HandleScope<'s>, + ) -> Local<'s, UnboundScript> { + unsafe { + scope + .cast_local(|_| v8__Script__GetUnboundScript(self)) + .unwrap() + } + } + /// Runs the script returning the resulting value. It will be run in the /// context in which it was created (ScriptCompiler::CompileBound or /// UnboundScript::BindToCurrentContext()). diff --git a/src/unbound_script.rs b/src/unbound_script.rs new file mode 100644 index 00000000..1f453209 --- /dev/null +++ b/src/unbound_script.rs @@ -0,0 +1,23 @@ +use crate::HandleScope; +use crate::Local; +use crate::Script; +use crate::UnboundScript; + +extern "C" { + fn v8__UnboundScript__BindToCurrentContext( + script: *const UnboundScript, + ) -> *const Script; +} + +impl UnboundScript { + /// Binds the script to the currently entered context. + pub fn bind_to_current_context<'s>( + &self, + scope: &mut HandleScope<'s>, + ) -> Local<'s, Script> { + unsafe { + scope.cast_local(|_| v8__UnboundScript__BindToCurrentContext(self)) + } + .unwrap() + } +} diff --git a/tests/test_api.rs b/tests/test_api.rs index 1137184b..eb6360f3 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -4393,3 +4393,31 @@ fn wasm_streaming_callback() { scope.perform_microtask_checkpoint(); assert!(global.get(scope, name).unwrap().strict_equals(exception)); } + +#[test] +fn unbound_script_conversion() { + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + let scope = &mut v8::HandleScope::new(isolate); + let unbound_script = { + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + let source = v8::String::new(scope, "'Hello ' + value").unwrap(); + let script = v8::Script::compile(scope, source, None).unwrap(); + script.get_unbound_script(scope) + }; + + { + // Execute the script in another context. + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + let global_object = scope.get_current_context().global(scope); + let key = v8::String::new(scope, "value").unwrap(); + let value = v8::String::new(scope, "world").unwrap(); + global_object.set(scope, key.into(), value.into()); + + let script = unbound_script.bind_to_current_context(scope); + let result = script.run(scope).unwrap(); + assert_eq!(result.to_rust_string_lossy(scope), "Hello world"); + } +}