From f049ad0229ae0df09abdf76252b1d70e0cddaf7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 21 Apr 2023 23:53:51 +0200 Subject: [PATCH] feat: Add v8::Object::get_constructor_name (#1212) --- src/binding.cc | 4 ++++ src/object.rs | 8 ++++++++ tests/test_api.rs | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/binding.cc b/src/binding.cc index b70423ff..e790c6b6 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1241,6 +1241,10 @@ MaybeBool v8__Object__SetPrototype(const v8::Object& self, ptr_to_local(&context), ptr_to_local(&prototype))); } +const v8::String* v8__Object__GetConstructorName(v8::Object& self) { + return local_to_ptr(self.GetConstructorName()); +} + MaybeBool v8__Object__CreateDataProperty(const v8::Object& self, const v8::Context& context, const v8::Name& key, diff --git a/src/object.rs b/src/object.rs index 05fc6295..6d727ad1 100644 --- a/src/object.rs +++ b/src/object.rs @@ -19,6 +19,7 @@ use crate::Private; use crate::PropertyAttribute; use crate::PropertyDescriptor; use crate::PropertyFilter; +use crate::String; use crate::Value; use std::convert::TryFrom; use std::ffi::c_void; @@ -74,6 +75,7 @@ extern "C" { context: *const Context, prototype: *const Value, ) -> MaybeBool; + fn v8__Object__GetConstructorName(this: *const Object) -> *const String; fn v8__Object__CreateDataProperty( this: *const Object, context: *const Context, @@ -295,6 +297,12 @@ impl Object { .into() } + /// Returns the name of the function invoked as a constructor for this object. + #[inline(always)] + pub fn get_constructor_name(&self) -> Local { + unsafe { Local::from_raw(v8__Object__GetConstructorName(self)) }.unwrap() + } + /// Implements CreateDataProperty (ECMA-262, 7.3.4). /// /// Defines a configurable, writable, enumerable property with the given value diff --git a/tests/test_api.rs b/tests/test_api.rs index 07930bb1..10d0349e 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -5719,6 +5719,45 @@ fn take_heap_snapshot() { } } +#[test] +fn get_constructor_name() { + let _setup_guard = setup::parallel_test(); + 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); + + fn check_ctor_name( + scope: &mut v8::HandleScope, + script: &str, + expected_name: &str, + ) { + let val = eval(scope, script).unwrap(); + let obj: v8::Local = val.try_into().unwrap(); + assert_eq!( + obj.get_constructor_name().to_rust_string_lossy(scope), + expected_name + ); + } + + let code = r#" + function Parent() {}; + function Child() {}; + Child.prototype = new Parent(); + Child.prototype.constructor = Child; + var outer = { inner: (0, function() { }) }; + var p = new Parent(); + var c = new Child(); + var x = new outer.inner(); + var proto = Child.prototype; + "#; + eval(scope, code).unwrap(); + check_ctor_name(scope, "p", "Parent"); + check_ctor_name(scope, "c", "Child"); + check_ctor_name(scope, "x", "outer.inner"); + check_ctor_name(scope, "proto", "Parent"); +} + #[test] fn test_prototype_api() { let _setup_guard = setup::parallel_test();