From f5d275f622f36b258e3f85cabd1ec9db7a5d5b07 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Mon, 27 Jun 2022 08:12:06 +0530 Subject: [PATCH] Add type specialized setters for v8::ReturnValue (#1015) --- src/binding.cc | 29 +++++++++ src/function.rs | 33 +++++++++- tests/test_api.rs | 153 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 211 insertions(+), 4 deletions(-) diff --git a/src/binding.cc b/src/binding.cc index 693fca95..843fd080 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1846,6 +1846,35 @@ void v8__ReturnValue__Set(v8::ReturnValue* self, self->Set(ptr_to_local(&value)); } +void v8__ReturnValue__Set__Int32(v8::ReturnValue* self, int32_t i) { + self->Set(i); +} + +void v8__ReturnValue__Set__Uint32(v8::ReturnValue* self, + uint32_t i) { + self->Set(i); +} + +void v8__ReturnValue__Set__Double(v8::ReturnValue* self, double i) { + self->Set(i); +} + +void v8__ReturnValue__Set__Bool(v8::ReturnValue* self, bool value) { + self->Set(value); +} + +void v8__ReturnValue__SetNull(v8::ReturnValue* self) { + self->SetNull(); +} + +void v8__ReturnValue__SetUndefined(v8::ReturnValue* self) { + self->SetUndefined(); +} + +void v8__ReturnValue__SetEmptyString(v8::ReturnValue* self) { + self->SetEmptyString(); +} + const v8::Value* v8__ReturnValue__Get(const v8::ReturnValue& self) { return local_to_ptr(self.Get()); } diff --git a/src/function.rs b/src/function.rs index d6a3002d..4e7ae9cf 100644 --- a/src/function.rs +++ b/src/function.rs @@ -78,6 +78,13 @@ extern "C" { ) -> *const Object; fn v8__ReturnValue__Set(this: *mut ReturnValue, value: *const Value); + fn v8__ReturnValue__Set__Int32(this: *mut ReturnValue, value: i32); + fn v8__ReturnValue__Set__Uint32(this: *mut ReturnValue, value: u32); + fn v8__ReturnValue__Set__Double(this: *mut ReturnValue, value: f64); + fn v8__ReturnValue__SetNull(this: *mut ReturnValue); + fn v8__ReturnValue__SetUndefined(this: *mut ReturnValue); + fn v8__ReturnValue__SetEmptyString(this: *mut ReturnValue); + fn v8__ReturnValue__Get(this: *const ReturnValue) -> *const Value; } @@ -135,12 +142,34 @@ impl<'cb> ReturnValue<'cb> { Self(slot, PhantomData) } - // NOTE: simplest setter, possibly we'll need to add - // more setters specialized per type pub fn set(&mut self, value: Local) { unsafe { v8__ReturnValue__Set(&mut *self, &*value) } } + pub fn set_int32(&mut self, value: i32) { + unsafe { v8__ReturnValue__Set__Int32(&mut *self, value) } + } + + pub fn set_uint32(&mut self, value: u32) { + unsafe { v8__ReturnValue__Set__Uint32(&mut *self, value) } + } + + pub fn set_double(&mut self, value: f64) { + unsafe { v8__ReturnValue__Set__Double(&mut *self, value) } + } + + pub fn set_null(&mut self) { + unsafe { v8__ReturnValue__SetNull(&mut *self) } + } + + pub fn set_undefined(&mut self) { + unsafe { v8__ReturnValue__SetUndefined(&mut *self) } + } + + pub fn set_empty_string(&mut self) { + unsafe { v8__ReturnValue__SetEmptyString(&mut *self) } + } + /// Getter. Creates a new Local<> so it comes with a certain performance /// hit. If the ReturnValue was not yet set, this will return the undefined /// value. diff --git a/tests/test_api.rs b/tests/test_api.rs index 9be3c776..c910f41f 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -2244,11 +2244,11 @@ fn fn_callback2( } fn fortytwo_callback( - scope: &mut v8::HandleScope, + _: &mut v8::HandleScope, _: v8::FunctionCallbackArguments, mut rv: v8::ReturnValue, ) { - rv.set(v8::Integer::new(scope, 42).into()); + rv.set_int32(42); } fn data_is_true_callback( @@ -2277,6 +2277,155 @@ fn nested_builder<'a>( .build(scope); } +#[test] +fn return_value() { + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + { + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + let global = context.global(scope); + let recv: v8::Local = global.into(); + + // set_int32 + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_int32(69); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_int32()); + assert_eq!(value.int32_value(scope).unwrap(), 69); + } + + // set_uint32 + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_uint32(69); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_uint32()); + assert_eq!(value.uint32_value(scope).unwrap(), 69); + } + + // set_null + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_null(); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_null()); + } + + // set_undefined + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_undefined(); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_undefined()); + } + + // set_double + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_double(69.420); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_number()); + assert_eq!(value.number_value(scope).unwrap(), 69.420); + } + + // set_empty_string + { + let template = v8::FunctionTemplate::new( + scope, + |scope: &mut v8::HandleScope, + args: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue| { + assert_eq!(args.length(), 0); + assert!(rv.get(scope).is_undefined()); + rv.set_empty_string(); + }, + ); + + let function = template + .get_function(scope) + .expect("Unable to create function"); + let value = function + .call(scope, recv, &[]) + .expect("Function call failed"); + assert!(value.is_string()); + assert_eq!(value.to_rust_string_lossy(scope), ""); + } + } +} + #[test] fn function() { let _setup_guard = setup();