From da7ef32ead3268fb2c8140a9f271a24aceb04511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 18 Feb 2022 01:26:00 +0100 Subject: [PATCH] feat: v8::Global::from_raw, v8::Global::into_raw (#902) Co-authored-by: Bert Belder --- src/handle.rs | 23 ++++++++++++++++++----- tests/test_api.rs | 5 +++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/handle.rs b/src/handle.rs index bc0aaaf6..45ec44cc 100644 --- a/src/handle.rs +++ b/src/handle.rs @@ -2,6 +2,7 @@ use std::borrow::Borrow; use std::hash::Hash; use std::hash::Hasher; use std::marker::PhantomData; +use std::mem::forget; use std::mem::transmute; use std::ops::Deref; use std::ptr::NonNull; @@ -130,12 +131,12 @@ impl Global { pub fn new(isolate: &mut Isolate, handle: impl Handle) -> Self { let HandleInfo { data, host } = handle.get_handle_info(); host.assert_match_isolate(isolate); - unsafe { Self::new_raw(isolate, data) } + unsafe { Self::from_raw(isolate, data) } } - /// Implementation helper function that contains the code that can be shared - /// between `Global::new()` and `Global::clone()`. - unsafe fn new_raw(isolate: *mut Isolate, data: NonNull) -> Self { + /// Converts a raw pointer created with [`Global::into_raw()`] back to its + /// original `Global`. + pub unsafe fn from_raw(isolate: &mut Isolate, data: NonNull) -> Self { let data = data.cast().as_ptr(); let data = v8__Global__New(isolate, data) as *const T; let data = NonNull::new_unchecked(data as *mut _); @@ -146,6 +147,18 @@ impl Global { } } + /// Consume this `Global` and return the underlying raw pointer. + /// + /// The returned raw pointer must be converted back into a `Global` by using + /// [`Global::from_raw`], otherwise the V8 value referenced by this global + /// handle will be pinned on the V8 heap permanently and never get garbage + /// collected. + pub fn into_raw(self) -> NonNull { + let data = self.data; + forget(self); + data + } + pub fn open<'a>(&'a self, scope: &mut Isolate) -> &'a T { Handle::open(self, scope) } @@ -159,7 +172,7 @@ impl Global { impl Clone for Global { fn clone(&self) -> Self { let HandleInfo { data, host } = self.get_handle_info(); - unsafe { Self::new_raw(host.get_isolate().as_mut(), data) } + unsafe { Self::from_raw(host.get_isolate().as_mut(), data) } } } diff --git a/tests/test_api.rs b/tests/test_api.rs index 14d62512..135f4589 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -127,6 +127,11 @@ fn global_handles() { assert!(g6 == g1); assert_eq!(g6.open(scope).to_rust_string_lossy(scope), "bla"); } + { + let g1_ptr = g1.clone().into_raw(); + let g1_reconstructed = unsafe { v8::Global::from_raw(isolate, g1_ptr) }; + assert_eq!(g1, g1_reconstructed); + } } #[test]