From 218071692354de149b4c5f1922d4c95cd93863c2 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Wed, 19 Jan 2022 19:01:55 +0100 Subject: [PATCH] Add v8::Map bindings (#872) Support v8::Map operations (`new`, `clear`, `get`, `set`, `has`, and `delete`). --- src/binding.cc | 53 ++++++++++++++++++++++++++++------ src/object.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test_api.rs | 44 ++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 9 deletions(-) diff --git a/src/binding.cc b/src/binding.cc index 6150af60..621fe304 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1240,8 +1240,40 @@ const v8::External* v8__External__New(v8::Isolate* isolate, void* value) { void* v8__External__Value(const v8::External& self) { return self.Value(); } +const v8::Map* v8__Map__New(v8::Isolate* isolate) { + return local_to_ptr(v8::Map::New(isolate)); +} + size_t v8__Map__Size(const v8::Map& self) { return self.Size(); } +void v8__Map__Clear(const v8::Map& self) { + return ptr_to_local(&self)->Clear(); +} + +const v8::Value* v8__Map__Get(const v8::Map& self, const v8::Context& context, + const v8::Value& key) { + return maybe_local_to_ptr( + ptr_to_local(&self)->Get(ptr_to_local(&context), ptr_to_local(&key))); +} + +v8::Map* v8__Map__Set(const v8::Map& self, const v8::Context& context, + const v8::Value& key, const v8::Value& value) { + return maybe_local_to_ptr(ptr_to_local(&self)->Set( + ptr_to_local(&context), ptr_to_local(&key), ptr_to_local(&value))); +} + +MaybeBool v8__Map__Has(const v8::Map& self, const v8::Context& context, + const v8::Value& key) { + return maybe_to_maybe_bool( + ptr_to_local(&self)->Has(ptr_to_local(&context), ptr_to_local(&key))); +} + +MaybeBool v8__Map__Delete(const v8::Map& self, const v8::Context& context, + const v8::Value& key) { + return maybe_to_maybe_bool( + ptr_to_local(&self)->Delete(ptr_to_local(&context), ptr_to_local(&key))); +} + const v8::Array* v8__Map__As__Array(const v8::Map& self) { return local_to_ptr(self.AsArray()); } @@ -2437,8 +2469,8 @@ void v8__WasmStreaming__Abort(WasmStreamingSharedPtr* self, self->inner->Abort(ptr_to_maybe_local(exception)); } -void v8__WasmStreaming__SetUrl(WasmStreamingSharedPtr* self, - const char* url, size_t len) { +void v8__WasmStreaming__SetUrl(WasmStreamingSharedPtr* self, const char* url, + size_t len) { self->inner->SetUrl(url, len); } @@ -2478,7 +2510,8 @@ void v8__HeapProfiler__TakeHeapSnapshot(v8::Isolate* isolate, // This is necessary for v8__internal__GetIsolateFromHeapObject() to be // reliable enough for our purposes. -#if UINTPTR_MAX == 0xffffffffffffffff && !(defined V8_SHARED_RO_HEAP or defined V8_COMPRESS_POINTERS) +#if UINTPTR_MAX == 0xffffffffffffffff && \ + !(defined V8_SHARED_RO_HEAP or defined V8_COMPRESS_POINTERS) #error V8 must be built with either the 'v8_enable_pointer_compression' or \ 'v8_enable_shared_ro_heap' feature enabled. #endif @@ -2782,18 +2815,20 @@ bool v8__ValueDeserializer__ReadRawBytes(v8::ValueDeserializer* self, // v8::CompiledWasmModule extern "C" { -const v8::WasmModuleObject* v8__WasmModuleObject__FromCompiledModule(v8::Isolate* isolate, - const v8::CompiledWasmModule* compiled_module) { - return maybe_local_to_ptr(v8::WasmModuleObject::FromCompiledModule(isolate, *compiled_module)); +const v8::WasmModuleObject* v8__WasmModuleObject__FromCompiledModule( + v8::Isolate* isolate, const v8::CompiledWasmModule* compiled_module) { + return maybe_local_to_ptr( + v8::WasmModuleObject::FromCompiledModule(isolate, *compiled_module)); } -v8::CompiledWasmModule* v8__WasmModuleObject__GetCompiledModule(const v8::WasmModuleObject* self) { +v8::CompiledWasmModule* v8__WasmModuleObject__GetCompiledModule( + const v8::WasmModuleObject* self) { v8::CompiledWasmModule cwm = ptr_to_local(self)->GetCompiledModule(); return new v8::CompiledWasmModule(std::move(cwm)); } -const uint8_t* v8__CompiledWasmModule__GetWireBytesRef(v8::CompiledWasmModule* self, - size_t* length) { +const uint8_t* v8__CompiledWasmModule__GetWireBytesRef( + v8::CompiledWasmModule* self, size_t* length) { v8::MemorySpan span = self->GetWireBytesRef(); *length = span.size(); return span.data(); diff --git a/src/object.rs b/src/object.rs index dc4b4261..a2d5ebdd 100644 --- a/src/object.rs +++ b/src/object.rs @@ -148,6 +148,29 @@ extern "C" { length: usize, ) -> *const Array; fn v8__Array__Length(array: *const Array) -> u32; + fn v8__Map__New(isolate: *mut Isolate) -> *const Map; + fn v8__Map__Clear(this: *const Map); + fn v8__Map__Get( + this: *const Map, + context: *const Context, + key: *const Value, + ) -> *const Value; + fn v8__Map__Set( + this: *const Map, + context: *const Context, + key: *const Value, + value: *const Value, + ) -> *const Map; + fn v8__Map__Has( + this: *const Map, + context: *const Context, + key: *const Value, + ) -> MaybeBool; + fn v8__Map__Delete( + this: *const Map, + context: *const Context, + key: *const Value, + ) -> MaybeBool; fn v8__Map__Size(map: *const Map) -> usize; fn v8__Map__As__Array(this: *const Map) -> *const Array; } @@ -586,9 +609,59 @@ impl Array { } impl Map { + pub fn new<'s>(scope: &mut HandleScope<'s>) -> Local<'s, Map> { + unsafe { scope.cast_local(|sd| v8__Map__New(sd.get_isolate_ptr())) } + .unwrap() + } + pub fn size(&self) -> usize { unsafe { v8__Map__Size(self) } } + + pub fn clear(&self) { + unsafe { v8__Map__Clear(self) } + } + + pub fn get<'s>( + &self, + scope: &mut HandleScope<'s>, + key: Local, + ) -> Option> { + unsafe { + scope.cast_local(|sd| v8__Map__Get(self, sd.get_current_context(), &*key)) + } + } + + pub fn set<'s>( + &self, + scope: &mut HandleScope<'s>, + key: Local, + value: Local, + ) -> Option> { + unsafe { + scope.cast_local(|sd| { + v8__Map__Set(self, sd.get_current_context(), &*key, &*value) + }) + } + } + + pub fn has( + &self, + scope: &mut HandleScope, + key: Local, + ) -> Option { + unsafe { v8__Map__Has(self, &*scope.get_current_context(), &*key) }.into() + } + + pub fn delete( + &self, + scope: &mut HandleScope, + key: Local, + ) -> Option { + unsafe { v8__Map__Delete(self, &*scope.get_current_context(), &*key) } + .into() + } + /// Returns an array of length size() * 2, where index N is the Nth key and /// index N + 1 is the Nth value. pub fn as_array<'s>(&self, scope: &mut HandleScope<'s>) -> Local<'s, Array> { diff --git a/tests/test_api.rs b/tests/test_api.rs index dd3f9c3c..ac4693de 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -1556,6 +1556,50 @@ fn object() { } } +#[test] +fn map() { + 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 map = v8::Map::new(scope); + assert_eq!(map.size(), 0); + + let undefined = v8::undefined(scope).into(); + + { + let key = v8::Object::new(scope).into(); + let value = v8::Integer::new(scope, 1337).into(); + assert_eq!(map.has(scope, key), Some(false)); + assert_eq!(map.get(scope, key), Some(undefined)); + assert_eq!(map.set(scope, key, value), Some(map)); + + assert_eq!(map.has(scope, key), Some(true)); + assert_eq!(map.size(), 1); + assert_eq!(map.get(scope, key), Some(value)); + } + + map.clear(); + assert_eq!(map.size(), 0); + + { + let key = v8::String::new(scope, "key").unwrap().into(); + let value = v8::Integer::new(scope, 42).into(); + + assert_eq!(map.delete(scope, key), Some(false)); + + map.set(scope, key, value); + assert_eq!(map.size(), 1); + + assert_eq!(map.delete(scope, key), Some(true)); + assert_eq!(map.size(), 0); + } + } +} + #[test] fn array() { let _setup_guard = setup();