core: settle on the trap/in condition convention for now. Implement proper re-raising.
This commit is contained in:
parent
9ee5fff4f1
commit
705afcd844
@ -1,125 +1,28 @@
|
||||
// helper for transmutation, shown below.
|
||||
type RustClosure = (int,int);
|
||||
struct Handler<T, U:Copy> {
|
||||
handle: RustClosure,
|
||||
prev: Option<@Handler<T, U>>,
|
||||
}
|
||||
|
||||
struct Condition<T, U:Copy> {
|
||||
key: task::local_data::LocalDataKey<Handler<T,U>>
|
||||
}
|
||||
|
||||
struct Handler<T, U:Copy> {
|
||||
handle: RustClosure
|
||||
}
|
||||
|
||||
|
||||
struct ProtectBlock<T, U:Copy> {
|
||||
cond: &Condition<T, U>,
|
||||
inner: RustClosure
|
||||
}
|
||||
|
||||
struct Guard<T, U:Copy> {
|
||||
cond: &Condition<T,U>,
|
||||
prev: Option<@Handler<T, U>>,
|
||||
drop {
|
||||
match self.prev {
|
||||
None => (),
|
||||
Some(p) =>
|
||||
unsafe {
|
||||
debug!("Guard: popping handler from TLS");
|
||||
task::local_data::local_data_set(self.cond.key, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct HandleBlock<T, U:Copy> {
|
||||
pb: &ProtectBlock<T,U>,
|
||||
prev: Option<@Handler<T,U>>,
|
||||
handler: @Handler<T,U>,
|
||||
drop {
|
||||
unsafe {
|
||||
debug!("HandleBlock: pushing handler to TLS");
|
||||
let _g = Guard { cond: self.pb.cond,
|
||||
prev: self.prev };
|
||||
task::local_data::local_data_set(self.pb.cond.key,
|
||||
self.handler);
|
||||
// transmutation to avoid copying non-copyable, should
|
||||
// be fixable by tracking closure pointees in regionck.
|
||||
let f : &fn() = ::cast::transmute(self.pb.inner);
|
||||
debug!("HandleBlock: invoking protected code");
|
||||
f();
|
||||
debug!("HandleBlock: returned from protected code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Trap<T, U:Copy> {
|
||||
cond: &Condition<T,U>,
|
||||
handler: @Handler<T, U>
|
||||
}
|
||||
|
||||
impl<T, U: Copy> ProtectBlock<T,U> {
|
||||
fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self<T,U> {
|
||||
unsafe {
|
||||
debug!("ProtectBlock.handle: setting up handler block");
|
||||
let p : *RustClosure = ::cast::transmute(&h);
|
||||
let prev = task::local_data::local_data_get(self.cond.key);
|
||||
HandleBlock { pb: self,
|
||||
prev: prev,
|
||||
handler: @Handler{handle: *p} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl<T, U: Copy> Trap<T,U> {
|
||||
fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
|
||||
unsafe {
|
||||
let prev = task::local_data::local_data_get(self.cond.key);
|
||||
let _g = Guard { cond: self.cond,
|
||||
prev: prev };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
task::local_data::local_data_set(self.cond.key, self.handler);
|
||||
inner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U: Copy> Condition<T,U> {
|
||||
|
||||
fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self<T,U> {
|
||||
unsafe {
|
||||
let prev = task::local_data::local_data_get(self.key);
|
||||
let g = Guard { cond: self, prev: prev };
|
||||
debug!("Guard: pushing handler to TLS");
|
||||
let p : *RustClosure = ::cast::transmute(&h);
|
||||
let h = @Handler{handle: *p};
|
||||
task::local_data::local_data_set(self.key, h);
|
||||
move g
|
||||
}
|
||||
}
|
||||
|
||||
fn trap(&self, h: &self/fn(&T) ->U) -> Trap/&self<T,U> {
|
||||
unsafe {
|
||||
let p : *RustClosure = ::cast::transmute(&h);
|
||||
let h = @Handler{handle: *p};
|
||||
let prev = task::local_data::local_data_get(self.key);
|
||||
let h = @Handler{handle: *p, prev: prev};
|
||||
move Trap { cond: self, handler: h }
|
||||
}
|
||||
}
|
||||
|
||||
fn protect(&self, inner: &self/fn()) -> ProtectBlock/&self<T,U> {
|
||||
unsafe {
|
||||
// transmutation to avoid copying non-copyable, should
|
||||
// be fixable by tracking closure pointees in regionck.
|
||||
debug!("Condition.protect: setting up protected block");
|
||||
let p : *RustClosure = ::cast::transmute(&inner);
|
||||
ProtectBlock { cond: self,
|
||||
inner: *p }
|
||||
}
|
||||
}
|
||||
|
||||
fn raise(t:&T) -> U {
|
||||
unsafe {
|
||||
match task::local_data::local_data_get(self.key) {
|
||||
match task::local_data::local_data_pop(self.key) {
|
||||
None => {
|
||||
debug!("Condition.raise: found no handler");
|
||||
fail
|
||||
@ -127,8 +30,55 @@ impl<T, U: Copy> Condition<T,U> {
|
||||
|
||||
Some(handler) => {
|
||||
debug!("Condition.raise: found handler");
|
||||
let f : &fn(&T) -> U = ::cast::transmute(handler.handle);
|
||||
f(t)
|
||||
match handler.prev {
|
||||
None => (),
|
||||
Some(hp) =>
|
||||
task::local_data::local_data_set(self.key, hp)
|
||||
}
|
||||
let handle : &fn(&T) -> U =
|
||||
::cast::transmute(handler.handle);
|
||||
let u = handle(t);
|
||||
task::local_data::local_data_set(self.key,
|
||||
handler);
|
||||
move u
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct Trap<T, U:Copy> {
|
||||
cond: &Condition<T,U>,
|
||||
handler: @Handler<T, U>
|
||||
}
|
||||
|
||||
impl<T, U: Copy> Trap<T,U> {
|
||||
fn in<V: Copy>(&self, inner: &self/fn() -> V) -> V {
|
||||
unsafe {
|
||||
let _g = Guard { cond: self.cond };
|
||||
debug!("Trap: pushing handler to TLS");
|
||||
task::local_data::local_data_set(self.cond.key, self.handler);
|
||||
inner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Guard<T, U:Copy> {
|
||||
cond: &Condition<T,U>,
|
||||
drop {
|
||||
unsafe {
|
||||
debug!("Guard: popping handler from TLS");
|
||||
let curr = task::local_data::local_data_pop(self.cond.key);
|
||||
match curr {
|
||||
None => (),
|
||||
Some(h) =>
|
||||
match h.prev {
|
||||
None => (),
|
||||
Some(hp) => {
|
||||
task::local_data::local_data_set(self.cond.key, hp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,164 +87,95 @@ impl<T, U: Copy> Condition<T,U> {
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
fn sadness_key(_x: @Handler<int,int>) { }
|
||||
mod test {
|
||||
|
||||
#[cfg(test)]
|
||||
fn trouble(i: int) {
|
||||
// Condition should work as a const, just limitations in consts.
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
debug!("trouble: raising conition");
|
||||
let j = sadness_condition.raise(&i);
|
||||
debug!("trouble: handler recovered with %d", j);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test1() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut i = 10;
|
||||
|
||||
let b = do sadness_condition.protect {
|
||||
debug!("test1: in protected block");
|
||||
trouble(1);
|
||||
trouble(2);
|
||||
trouble(3);
|
||||
};
|
||||
|
||||
do b.handle |j| {
|
||||
debug!("test1: in handler");
|
||||
i += *j;
|
||||
i
|
||||
};
|
||||
|
||||
assert i == 16;
|
||||
}
|
||||
#[cfg(test)]
|
||||
fn nested_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
let b = do sadness_condition.protect {
|
||||
debug!("nested_test_inner: in protected block");
|
||||
trouble(1);
|
||||
};
|
||||
|
||||
do b.handle |_j| {
|
||||
debug!("nested_test_inner: in handler");
|
||||
inner_trapped = true;
|
||||
0
|
||||
};
|
||||
|
||||
assert inner_trapped;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_test_outer() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
let b = do sadness_condition.protect {
|
||||
debug!("nested_test_outer: in protected block");
|
||||
nested_test_inner();
|
||||
trouble(1);
|
||||
};
|
||||
|
||||
do b.handle |_j| {
|
||||
debug!("nested_test_outer: in handler");
|
||||
outer_trapped = true;
|
||||
0
|
||||
};
|
||||
|
||||
assert outer_trapped;
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
fn nested_guard_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
let _g = do sadness_condition.guard |_j| {
|
||||
debug!("nested_guard_test_inner: in handler");
|
||||
inner_trapped = true;
|
||||
0
|
||||
};
|
||||
|
||||
debug!("nested_guard_test_inner: in protected block");
|
||||
trouble(1);
|
||||
|
||||
assert inner_trapped;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_guard_test_outer() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
let _g = do sadness_condition.guard |_j| {
|
||||
debug!("nested_guard_test_outer: in handler");
|
||||
outer_trapped = true;
|
||||
0
|
||||
};
|
||||
|
||||
debug!("nested_guard_test_outer: in protected block");
|
||||
nested_guard_test_inner();
|
||||
trouble(1);
|
||||
|
||||
assert outer_trapped;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
fn nested_trap_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_trap_test_inner: in handler");
|
||||
inner_trapped = true;
|
||||
0
|
||||
}).in {
|
||||
debug!("nested_trap_test_inner: in protected block");
|
||||
trouble(1);
|
||||
fn sadness_key(_x: @Handler<int,int>) { }
|
||||
fn trouble(i: int) {
|
||||
// Condition should work as a const, just limitations in consts.
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
debug!("trouble: raising conition");
|
||||
let j = sadness_condition.raise(&i);
|
||||
debug!("trouble: handler recovered with %d", j);
|
||||
}
|
||||
|
||||
assert inner_trapped;
|
||||
}
|
||||
fn nested_trap_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
#[test]
|
||||
fn nested_trap_test_outer() {
|
||||
let mut inner_trapped = false;
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_trap_test_inner: in handler");
|
||||
inner_trapped = true;
|
||||
0
|
||||
}).in {
|
||||
debug!("nested_trap_test_inner: in protected block");
|
||||
trouble(1);
|
||||
}
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_trap_test_outer: in handler");
|
||||
outer_trapped = true; 0
|
||||
}).in {
|
||||
debug!("nested_guard_test_outer: in protected block");
|
||||
nested_trap_test_inner();
|
||||
trouble(1);
|
||||
assert inner_trapped;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_trap_test_outer() {
|
||||
|
||||
assert outer_trapped;
|
||||
}
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_trap_test_outer: in handler");
|
||||
outer_trapped = true; 0
|
||||
}).in {
|
||||
debug!("nested_guard_test_outer: in protected block");
|
||||
nested_trap_test_inner();
|
||||
trouble(1);
|
||||
}
|
||||
|
||||
|
||||
assert outer_trapped;
|
||||
}
|
||||
|
||||
fn nested_reraise_trap_test_inner() {
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut inner_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_reraise_trap_test_inner: in handler");
|
||||
inner_trapped = true;
|
||||
let i = 10;
|
||||
debug!("nested_reraise_trap_test_inner: handler re-raising");
|
||||
sadness_condition.raise(&i)
|
||||
}).in {
|
||||
debug!("nested_reraise_trap_test_inner: in protected block");
|
||||
trouble(1);
|
||||
}
|
||||
|
||||
assert inner_trapped;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_reraise_trap_test_outer() {
|
||||
|
||||
let sadness_condition : Condition<int,int> =
|
||||
Condition { key: sadness_key };
|
||||
|
||||
let mut outer_trapped = false;
|
||||
|
||||
do sadness_condition.trap(|_j| {
|
||||
debug!("nested_reraise_trap_test_outer: in handler");
|
||||
outer_trapped = true; 0
|
||||
}).in {
|
||||
debug!("nested_reraise_trap_test_outer: in protected block");
|
||||
nested_reraise_trap_test_inner();
|
||||
}
|
||||
|
||||
|
||||
assert outer_trapped;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user