From 705afcd8445819c3f0493aa2befbe4788d9bb5ce Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Mon, 22 Oct 2012 17:26:26 -0700 Subject: [PATCH] core: settle on the trap/in condition convention for now. Implement proper re-raising. --- src/libcore/condition.rs | 397 ++++++++++++++------------------------- 1 file changed, 139 insertions(+), 258 deletions(-) diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index 77bd88e04d7..e50ebfc439b 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -1,125 +1,28 @@ // helper for transmutation, shown below. type RustClosure = (int,int); +struct Handler { + handle: RustClosure, + prev: Option<@Handler>, +} struct Condition { key: task::local_data::LocalDataKey> } -struct Handler { - handle: RustClosure -} - - -struct ProtectBlock { - cond: &Condition, - inner: RustClosure -} - -struct Guard { - cond: &Condition, - prev: Option<@Handler>, - 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 { - pb: &ProtectBlock, - prev: Option<@Handler>, - handler: @Handler, - 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 { - cond: &Condition, - handler: @Handler -} - -impl ProtectBlock { - fn handle(&self, h: &self/fn(&T) ->U) -> HandleBlock/&self { - 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 Trap { - fn in(&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 Condition { - fn guard(&self, h: &self/fn(&T) ->U) -> Guard/&self { - 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 { 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 { - 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 Condition { 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 { + cond: &Condition, + handler: @Handler +} + +impl Trap { + fn in(&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 { + cond: &Condition, + 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 Condition { #[cfg(test)] -fn sadness_key(_x: @Handler) { } +mod test { -#[cfg(test)] -fn trouble(i: int) { - // Condition should work as a const, just limitations in consts. - let sadness_condition : Condition = - 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 = - 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 = - 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 = - 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 = - 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 = - 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 = - 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) { } + fn trouble(i: int) { + // Condition should work as a const, just limitations in consts. + let sadness_condition : Condition = + 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 = + Condition { key: sadness_key }; -#[test] -fn nested_trap_test_outer() { + let mut inner_trapped = false; - let sadness_condition : Condition = - 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 = + 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 = + 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 = + 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; + } + +} \ No newline at end of file