diff --git a/src/binding.cc b/src/binding.cc index 8568a0b6..333ae5f8 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1484,6 +1484,11 @@ const v8::Object* v8__Function__NewInstance(const v8::Function& self, ptr_to_local(&context), argc, const_ptr_array_to_local_array(argv))); } +const v8::Signature* v8__Signature__New(v8::Isolate* isolate, + const v8::FunctionTemplate* templ) { + return local_to_ptr(v8::Signature::New(isolate, ptr_to_local(templ))); +} + const v8::FunctionTemplate* v8__FunctionTemplate__New( v8::Isolate* isolate, v8::FunctionCallback callback, const v8::Value* data_or_null, const v8::Signature* signature_or_null, diff --git a/src/template.rs b/src/template.rs index 4d3dfcca..f4f868de 100644 --- a/src/template.rs +++ b/src/template.rs @@ -31,7 +31,10 @@ extern "C" { value: *const Data, attr: PropertyAttribute, ); - + fn v8__Signature__New( + isolate: *mut Isolate, + templ: *const FunctionTemplate, + ) -> *const Signature; fn v8__FunctionTemplate__New( isolate: *mut Isolate, callback: FunctionCallback, @@ -115,6 +118,24 @@ impl<'s> FunctionBuilder<'s, FunctionTemplate> { } } +/// A Signature specifies which receiver is valid for a function. +/// +/// A receiver matches a given signature if the receiver (or any of its +/// hidden prototypes) was created from the signature's FunctionTemplate, or +/// from a FunctionTemplate that inherits directly or indirectly from the +/// signature's FunctionTemplate. +impl Signature { + pub fn new<'s>( + scope: &mut HandleScope<'s, ()>, + templ: Local, + ) -> Local<'s, Self> { + unsafe { + scope.cast_local(|sd| v8__Signature__New(sd.get_isolate_ptr(), &*templ)) + } + .unwrap() + } +} + impl FunctionTemplate { /// Create a FunctionBuilder to configure a FunctionTemplate. /// This is the same as FunctionBuilder::::new(). diff --git a/tests/test_api.rs b/tests/test_api.rs index 57944c56..5367e51b 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -1277,6 +1277,43 @@ fn object_template_from_function_template() { } } +#[test] +fn function_template_signature() { + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + { + let scope = &mut v8::HandleScope::new(isolate); + + let templ0 = v8::FunctionTemplate::new(scope, fortytwo_callback); + let signature = v8::Signature::new(scope, templ0); + let templ1 = v8::FunctionTemplate::builder(fortytwo_callback) + .signature(signature) + .build(scope); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + let scope = &mut v8::TryCatch::new(scope); + let global = context.global(scope); + + let name = v8::String::new(scope, "C").unwrap(); + let value = templ0.get_function(scope).unwrap(); + global.set(scope, name.into(), value.into()).unwrap(); + + let name = v8::String::new(scope, "f").unwrap(); + let value = templ1.get_function(scope).unwrap(); + global.set(scope, name.into(), value.into()).unwrap(); + + assert!(eval(scope, "f.call(new C)").is_some()); + assert!(eval(scope, "f.call(new Object)").is_none()); + assert!(scope.has_caught()); + assert!(scope + .exception() + .unwrap() + .to_rust_string_lossy(scope) + .contains("Illegal invocation")); + } +} + #[test] fn object() { let _setup_guard = setup();