Skip to content

Instantly share code, notes, and snippets.

@pcwalton
Created February 28, 2014 22:06
Show Gist options
  • Save pcwalton/9280996 to your computer and use it in GitHub Desktop.
Save pcwalton/9280996 to your computer and use it in GitHub Desktop.
#[feature(macro_rules)];
use std::cast;
use std::ptr;
macro_rules! root(
($($name:ident = $js:expr),+ in $rest:expr) => {
{
$(let $name;)+
unsafe {
$($name = Rooted::new(&$js);)+
}
$(let you_cannot_move_a_rooted_javascript_object = &$name;)+
$rest
}
}
)
pub struct JS<T> {
priv ptr: *mut T,
}
impl<T> JS<T> {
pub fn get<'a>(&'a self) -> &'a mut T {
unsafe {
cast::transmute(self.ptr)
}
}
pub fn set(&mut self, other: JSRef<T>) {
self.ptr = other.ptr;
}
}
#[unsafe_destructor]
impl<T> Drop for JS<T> {
fn drop(&mut self) {}
}
pub struct Rooted<T> {
priv ptr: *mut T,
}
impl<T> Rooted<T> {
pub unsafe fn new(js_object: &JS<T>) -> Rooted<T> {
println!("rooting!");
Rooted {
ptr: js_object.ptr,
}
}
pub fn get<'a>(&'a self) -> &'a mut T {
unsafe {
cast::transmute(self.ptr)
}
}
pub fn as_ref<'a>(&'a self) -> JSRef<'a,T> {
unsafe {
JSRef {
ptr: self.ptr,
chain: ::std::cast::transmute_region(&()),
}
}
}
}
#[unsafe_destructor]
impl<T> Drop for Rooted<T> {
fn drop(&mut self) {
println!("dropping root!");
}
}
/// Encapsulates a reference to something that is guaranteed to be alive. This is freely copyable.
pub struct JSRef<'a,T> {
priv ptr: *mut T,
priv chain: &'a (),
}
impl<'a,T> JSRef<'a,T> {
pub fn get<'a>(&'a self) -> &'a mut T {
unsafe {
cast::transmute(self.ptr)
}
}
}
pub struct IntContainer {
value: JS<int>,
}
pub fn main() {
// setup
let mut value = 3;
let three: JS<int> = JS {
ptr: &mut value,
};
let mut value = 5;
let five: JS<int> = JS {
ptr: &mut value,
};
let mut value = IntContainer {
value: five,
};
let int_container: JS<IntContainer> = JS {
ptr: &mut value,
};
// rooting!
root!(rooted_three = three,
rooted_int_container = int_container in {
println!("rooted object has value {}", *rooted_three.get());
// let _ = you_cannot_move_a_rooted_javascript_object; -- prohibited; inaccessible
// drop(rooted_three); -- prohibited; cannot move out because borrowed
other_function(rooted_int_container.as_ref(), rooted_three.as_ref());
})
}
fn other_function(int_container: JSRef<IntContainer>, value: JSRef<int>) {
println!("I had {}", *int_container.get().value.get());
int_container.get().value.set(value);
println!("I now have {}", *int_container.get().value.get());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment