Created
February 28, 2014 22:06
-
-
Save pcwalton/9280996 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[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