0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-25 15:29:43 -05:00
denoland-rusty-v8/tests/slots.rs

163 lines
4.3 KiB
Rust

// These tests mock out an organizational pattern that we hope to use in Deno.
// There we want to wrap v8::Isolate to provide extra functionality at multiple
// layers: v8::Isolate -> CoreIsolate -> EsIsolate
// This demonstrates how this can be done in a safe way.
use rusty_v8 as v8;
use std::ops::Deref;
use std::ops::DerefMut;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::sync::Once;
struct CoreIsolate(v8::OwnedIsolate);
struct CoreIsolateState {
drop_count: Rc<AtomicUsize>,
i: usize,
}
impl Drop for CoreIsolateState {
fn drop(&mut self) {
self.drop_count.fetch_add(1, Ordering::SeqCst);
}
}
impl CoreIsolate {
fn new(drop_count: Rc<AtomicUsize>) -> CoreIsolate {
static START: Once = Once::new();
START.call_once(|| {
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
v8::V8::initialize();
});
let mut isolate = v8::Isolate::new(Default::default());
let state = CoreIsolateState { drop_count, i: 0 };
isolate.set_slot(state);
CoreIsolate(isolate)
}
// Returns false if there was an error.
fn execute(&mut self, code: &str) -> bool {
let scope = &mut v8::HandleScope::new(&mut self.0);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let r = script.run(scope);
r.is_some()
}
fn get_i(&self) -> usize {
let s = self.0.get_slot::<CoreIsolateState>().unwrap();
s.i
}
fn set_i(&mut self, i: usize) {
let s = self.0.get_slot_mut::<CoreIsolateState>().unwrap();
s.i = i;
}
}
impl Deref for CoreIsolate {
type Target = v8::Isolate;
fn deref(&self) -> &v8::Isolate {
&self.0
}
}
impl DerefMut for CoreIsolate {
fn deref_mut(&mut self) -> &mut v8::Isolate {
&mut self.0
}
}
struct EsIsolate(CoreIsolate);
struct EsIsolateState {
drop_count: Rc<AtomicUsize>,
x: bool,
}
impl Drop for EsIsolateState {
fn drop(&mut self) {
self.drop_count.fetch_add(1, Ordering::SeqCst);
}
}
impl EsIsolate {
fn new(drop_count: Rc<AtomicUsize>) -> Self {
let mut core_isolate = CoreIsolate::new(drop_count.clone());
let state = EsIsolateState {
drop_count,
x: false,
};
core_isolate.set_slot(state);
EsIsolate(core_isolate)
}
fn get_x(&self) -> bool {
let state = self.0.get_slot::<EsIsolateState>().unwrap();
state.x
}
fn set_x(&mut self, x: bool) {
let state = self.0.get_slot_mut::<EsIsolateState>().unwrap();
state.x = x;
}
}
impl Deref for EsIsolate {
type Target = CoreIsolate;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for EsIsolate {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[test]
fn slots_layer1() {
let drop_count = Rc::new(AtomicUsize::new(0));
let mut core_isolate = CoreIsolate::new(drop_count.clone());
// The existence of a IsolateHandle that outlives the isolate should not
// inhibit dropping of slot contents.
let isolate_handle = core_isolate.thread_safe_handle();
assert!(core_isolate.execute("1 + 1"));
assert!(!core_isolate.execute("throw 'foo'"));
assert_eq!(0, core_isolate.get_i());
core_isolate.set_i(123);
assert_eq!(123, core_isolate.get_i());
assert_eq!(drop_count.load(Ordering::SeqCst), 0);
// Check that we can deref CoreIsolate by running a random v8::Isolate method
core_isolate.perform_microtask_checkpoint();
drop(core_isolate);
assert_eq!(drop_count.load(Ordering::SeqCst), 1);
drop(isolate_handle);
}
#[test]
fn slots_layer2() {
let drop_count = Rc::new(AtomicUsize::new(0));
let mut es_isolate = EsIsolate::new(drop_count.clone());
// We can deref to CoreIsolate and use execute...
assert!(es_isolate.execute("1 + 1"));
assert!(!es_isolate.execute("throw 'bar'"));
// We can use get_x set_x
assert!(!es_isolate.get_x());
es_isolate.set_x(true);
assert!(es_isolate.get_x());
// Check that we can deref all the way to a v8::Isolate method
es_isolate.perform_microtask_checkpoint();
// When we drop, both CoreIsolateState and EsIsolateState should be dropped.
assert_eq!(drop_count.load(Ordering::SeqCst), 0);
drop(es_isolate);
assert_eq!(drop_count.load(Ordering::SeqCst), 2);
}