1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::ptr;
use libc::c_void;
use chakracore_sys::*;
use context::ContextGuard;
use super::{Value, Object};
pub struct External(JsValueRef);
impl External {
pub fn new<T>(_guard: &ContextGuard, external: Box<T>) -> Self {
let mut value = JsValueRef::new();
unsafe {
jsassert!(JsCreateExternalObject(Box::into_raw(external) as *mut _,
Some(Self::finalize::<T>),
&mut value));
Self::from_raw(value)
}
}
pub unsafe fn from_ptr<T>(_guard: &ContextGuard, external: *mut T) -> Self {
let mut value = JsValueRef::new();
jsassert!(JsCreateExternalObject(external as *mut _,
None,
&mut value));
Self::from_raw(value)
}
pub unsafe fn value<T>(&self) -> &mut T {
let mut data = ptr::null_mut();
jsassert!(JsGetExternalData(self.as_raw(), &mut data));
(data as *mut T).as_mut().expect("retrieving external data")
}
pub fn is_same(value: &Value) -> bool {
value.get_type() == JsValueType::Object && Self::has_external_data(value)
}
fn has_external_data(value: &Value) -> bool {
let mut result = false;
jsassert!(unsafe { JsHasExternalData(value.as_raw(), &mut result) });
result
}
unsafe extern "system" fn finalize<T>(data: *mut c_void) {
Box::from_raw(data as *mut T);
}
}
reference!(External);
inherit!(External, Object);
subtype!(External, Value);
#[cfg(test)]
mod tests {
use {test, value};
#[test]
fn destructor() {
static mut CALLED: bool = false;
{
struct Foo(i32);
impl Drop for Foo {
fn drop(&mut self) {
assert_eq!(self.0, 10);
unsafe { CALLED = true };
}
}
test::run_with_context(|guard| {
let _ = value::External::new(guard, Box::new(Foo(10)));
});
}
assert!(unsafe { CALLED });
}
}