From 6bf57abb5c23bfc4f0c4fd0693c7a5cc46e728d2 Mon Sep 17 00:00:00 2001 From: Max Bruce Date: Mon, 23 Mar 2020 08:39:43 -0700 Subject: [PATCH] Implement GetPrototype and SetPrototype on objects (#321) --- src/binding.cc | 10 ++++++++ src/object.rs | 28 +++++++++++++++++++++++ tests/test_api.rs | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/src/binding.cc b/src/binding.cc index ae37e0b2..c492b465 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -726,6 +726,10 @@ v8::Value* v8__Object__GetIndex(v8::Object& self, return maybe_local_to_ptr(self.Get(context, index)); } +v8::Value* v8__Object__GetPrototype(v8::Object& self) { + return local_to_ptr(self.GetPrototype()); +} + MaybeBool v8__Object__Set(v8::Object& self, v8::Local context, v8::Local key, v8::Local value) { @@ -737,6 +741,12 @@ MaybeBool v8__Object__SetIndex(v8::Object& self, v8::Local context, return maybe_to_maybe_bool(self.Set(context, index, value)); } +MaybeBool v8__Object__SetPrototype(v8::Object& self, + v8::Local context, + v8::Local prototype) { + return maybe_to_maybe_bool(self.SetPrototype(context, prototype)); +} + MaybeBool v8__Object__CreateDataProperty(v8::Object& self, v8::Local context, v8::Local key, diff --git a/src/object.rs b/src/object.rs index 67b8c112..a44cd872 100644 --- a/src/object.rs +++ b/src/object.rs @@ -37,6 +37,7 @@ extern "C" { context: Local, index: u32, ) -> *mut Value; + fn v8__Object__GetPrototype(object: &Object) -> *mut Value; fn v8__Object__Set( object: &Object, context: Local, @@ -49,6 +50,11 @@ extern "C" { index: u32, value: Local, ) -> MaybeBool; + fn v8__Object__SetPrototype( + object: &Object, + context: Local, + prototype: Local, + ) -> MaybeBool; fn v8__Object__CreateDataProperty( object: &Object, context: Local, @@ -128,6 +134,16 @@ impl Object { unsafe { v8__Object__SetIndex(self, context, index, value) }.into() } + /// Set the prototype object. This does not skip objects marked to be + /// skipped by proto and it does not consult the security handler. + pub fn set_prototype( + &self, + context: Local, + prototype: Local, + ) -> Option { + unsafe { v8__Object__SetPrototype(self, context, prototype) }.into() + } + /// Implements CreateDataProperty (ECMA-262, 7.3.4). /// /// Defines a configurable, writable, enumerable property with the given value @@ -185,6 +201,18 @@ impl Object { } } + /// Get the prototype object. This does not skip objects marked to be + /// skipped by proto and it does not consult the security handler. + pub fn get_prototype<'a>( + &self, + scope: &mut impl ToLocal<'a>, + ) -> Option> { + unsafe { + let ptr = v8__Object__GetPrototype(self); + scope.to_local(ptr) + } + } + /// Note: SideEffectType affects the getter only, not the setter. pub fn set_accessor( &mut self, diff --git a/tests/test_api.rs b/tests/test_api.rs index 0c5d53fb..b6e4f802 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -2805,3 +2805,61 @@ fn take_heap_snapshot() { assert!(s.find(r#""Eyecatcher""#).is_some()); } } + +#[test] +fn test_prototype_api() { + 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(); + let context = v8::Context::new(scope); + let mut cs = v8::ContextScope::new(scope, context); + let scope = cs.enter(); + + let obj = v8::Object::new(scope); + let proto_obj = v8::Object::new(scope); + let key_local: v8::Local = + v8::String::new(scope, "test_proto_key").unwrap().into(); + let value_local: v8::Local = + v8::String::new(scope, "test_proto_value").unwrap().into(); + proto_obj.set(context, key_local, value_local); + obj.set_prototype(context, proto_obj.into()); + + assert!(obj + .get_prototype(scope) + .unwrap() + .same_value(proto_obj.into())); + + let sub_gotten = obj.get(scope, context, key_local).unwrap(); + assert!(sub_gotten.is_string()); + let sub_gotten = sub_gotten.to_string(scope).unwrap(); + assert_eq!(sub_gotten.to_rust_string_lossy(scope), "test_proto_value"); + } + { + let mut hs = v8::HandleScope::new(&mut isolate); + let scope = hs.enter(); + let context = v8::Context::new(scope); + let mut cs = v8::ContextScope::new(scope, context); + let scope = cs.enter(); + + let obj = v8::Object::new(scope); + obj.set_prototype(context, v8::null(scope).into()); + + assert!(obj.get_prototype(scope).unwrap().is_null()); + } + { + let mut hs = v8::HandleScope::new(&mut isolate); + let scope = hs.enter(); + let context = v8::Context::new(scope); + let mut cs = v8::ContextScope::new(scope, context); + let scope = cs.enter(); + + let val = eval(scope, context, "({ __proto__: null })").unwrap(); + let obj = val.to_object(scope).unwrap(); + + assert!(obj.get_prototype(scope).unwrap().is_null()); + } +}