Skip to content

Commit

Permalink
Add v8::Eternal<T>
Browse files Browse the repository at this point in the history
Eternal handles are set-once handles that live for the lifetime of the isolate.

https://v8.github.io/api/head/classv8_1_1Eternal.html
  • Loading branch information
littledivy committed Dec 30, 2024
1 parent 6b12ea1 commit 76de184
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 0 deletions.
25 changes: 25 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,31 @@ const v8::Data* v8__TracedReference__Get(v8::TracedReference<v8::Data>* self,
return local_to_ptr(self->Get(isolate));
}

void v8__Eternal__CONSTRUCT(
uninit_t<v8::Eternal<v8::Data>>* buf) {
construct_in_place<v8::Eternal<v8::Data>>(buf);
}

void v8__Eternal__DESTRUCT(v8::Eternal<v8::Data>* self) {
self->~Eternal();
}

void v8__Eternal__Clear(v8::Eternal<v8::Data>* self) {
self->Clear();
}

bool v8__Eternal__IsEmpty(v8::Eternal<v8::Data>* self) { return self->IsEmpty(); }

void v8__Eternal__Set(v8::Eternal<v8::Data>* self, v8::Isolate* isolate,
const v8::Data* value) {
self->Set(isolate, ptr_to_local(value));
}

const v8::Data* v8__Eternal__Get(v8::Eternal<v8::Data>* self,
v8::Isolate* isolate) {
return local_to_ptr(self->Get(isolate));
}

v8::Isolate* v8__WeakCallbackInfo__GetIsolate(
const v8::WeakCallbackInfo<void>* self) {
return self->GetIsolate();
Expand Down
2 changes: 2 additions & 0 deletions src/binding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ static size_t cppgc__WeakMember_SIZE = sizeof(cppgc::WeakMember<RustObj>);

static size_t v8__TracedReference_SIZE = sizeof(v8::TracedReference<v8::Data>);

static size_t v8__Eternal_SIZE = sizeof(v8::Eternal<v8::Data>);

static size_t v8__String__ValueView_SIZE = sizeof(v8::String::ValueView);

static int v8__String__kMaxLength = v8::String::kMaxLength;
Expand Down
72 changes: 72 additions & 0 deletions src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ extern "C" {
this: *const TracedReference<Data>,
isolate: *mut Isolate,
) -> *const Data;

fn v8__Eternal__CONSTRUCT(this: *mut Eternal<Data>);
fn v8__Eternal__DESTRUCT(this: *mut Eternal<Data>);
fn v8__Eternal__Clear(this: *mut Eternal<Data>);
fn v8__Eternal__Get(
this: *const Eternal<Data>,
isolate: *mut Isolate,
) -> *const Data;
fn v8__Eternal__Set(
this: *mut Eternal<Data>,
isolate: *mut Isolate,
data: *mut Data,
);
fn v8__Eternal__IsEmpty(this: *const Eternal<Data>) -> bool;
}

/// An object reference managed by the v8 garbage collector.
Expand Down Expand Up @@ -1100,3 +1114,61 @@ impl<T> Drop for TracedReference<T> {
}
}
}

/// Eternal handles are set-once handles that live for the lifetime of the isolate.
#[repr(C)]
pub struct Eternal<T> {
data: [u8; crate::binding::v8__Eternal_SIZE],
_phantom: PhantomData<T>,
}

impl<T> Eternal<T> {
pub fn empty() -> Self {
let mut this = std::mem::MaybeUninit::uninit();
unsafe {
v8__Eternal__CONSTRUCT(this.as_mut_ptr() as _);
this.assume_init()
}
}

pub fn clear(&self) {
unsafe {
v8__Eternal__Clear(self as *const Self as *mut Eternal<Data>);
}
}

pub fn set(&self, scope: &mut HandleScope<()>, data: Local<T>) {
unsafe {
v8__Eternal__Set(
self as *const Self as *mut Eternal<Data>,
scope.get_isolate_ptr(),
data.as_non_null().as_ptr().cast(),
);
}
}

pub fn get<'s>(&self, scope: &mut HandleScope<'s, ()>) -> Local<'s, T> {
unsafe {
scope
.cast_local(|sd| {
v8__Eternal__Get(
self as *const Self as *const Eternal<Data>,
sd.get_isolate_ptr(),
) as *const T
})
.unwrap()
}
}

pub fn is_empty(&self) -> bool {
unsafe { v8__Eternal__IsEmpty(self as *const Self as *const Eternal<Data>) }
}
}

impl<T> Drop for Eternal<T> {
fn drop(&mut self) {
unsafe {
v8__Eternal__DESTRUCT(self as *mut Self as *mut Eternal<Data>);
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub use external_references::ExternalReferences;
pub use function::*;
pub use gc::*;
pub use get_property_names_args_builder::*;
pub use handle::Eternal;
pub use handle::Global;
pub use handle::Handle;
pub use handle::Local;
Expand Down
21 changes: 21 additions & 0 deletions tests/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11977,3 +11977,24 @@ fn use_counter_callback() {

assert_eq!(COUNT.load(Ordering::Relaxed), 1);
}

#[test]
fn test_eternals() {
let _setup_guard = setup::parallel_test();
let eternal1 = v8::Eternal::empty();

let mut isolate = v8::Isolate::new(Default::default());
let mut scope = v8::HandleScope::new(&mut isolate);

let str1 = v8::String::new(&mut scope, "hello").unwrap();

assert!(eternal1.is_empty());
eternal1.set(&mut scope, str1);
assert!(!eternal1.is_empty());

let str1_get = eternal1.get(&mut scope);
assert_eq!(str1, str1_get);

eternal1.clear();
assert!(eternal1.is_empty());
}

0 comments on commit 76de184

Please sign in to comment.