2012-12-03 18:48:01 -06:00
|
|
|
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2013-01-08 21:37:25 -06:00
|
|
|
use prelude::*;
|
2012-12-23 16:41:37 -06:00
|
|
|
use task;
|
2012-12-24 08:56:04 -06:00
|
|
|
use task::local_data::{local_data_pop, local_data_set};
|
2012-12-23 16:41:37 -06:00
|
|
|
|
2012-10-17 18:40:18 -05:00
|
|
|
// helper for transmutation, shown below.
|
2012-12-24 08:56:04 -06:00
|
|
|
type RustClosure = (int, int);
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
pub struct Handler<T, U> {
|
2012-10-22 19:26:26 -05:00
|
|
|
handle: RustClosure,
|
2012-10-18 21:47:19 -05:00
|
|
|
prev: Option<@Handler<T, U>>,
|
2012-10-19 16:46:32 -05:00
|
|
|
}
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
pub struct Condition<T, U> {
|
|
|
|
name: &static/str,
|
2013-02-26 13:34:00 -06:00
|
|
|
key: task::local_data::LocalDataKey/&self<Handler<T, U>>
|
2012-10-19 16:46:32 -05:00
|
|
|
}
|
|
|
|
|
2013-02-26 13:34:00 -06:00
|
|
|
pub impl<T, U> Condition/&self<T, U> {
|
2012-12-24 08:56:04 -06:00
|
|
|
fn trap(&self, h: &self/fn(T) -> U) -> Trap/&self<T, U> {
|
2012-10-19 16:46:32 -05:00
|
|
|
unsafe {
|
|
|
|
let p : *RustClosure = ::cast::transmute(&h);
|
2012-10-22 19:26:26 -05:00
|
|
|
let prev = task::local_data::local_data_get(self.key);
|
2012-12-24 08:56:04 -06:00
|
|
|
let h = @Handler { handle: *p, prev: prev };
|
|
|
|
Trap { cond: self, handler: h }
|
2012-10-19 16:46:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-04 21:36:15 -06:00
|
|
|
fn raise(&self, t: T) -> U {
|
2012-12-24 08:56:04 -06:00
|
|
|
let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
|
2013-02-11 21:26:38 -06:00
|
|
|
self.raise_default(t, || fail!(copy msg))
|
2012-10-22 20:05:17 -05:00
|
|
|
}
|
|
|
|
|
2013-03-04 21:36:15 -06:00
|
|
|
fn raise_default(&self, t: T, default: &fn() -> U) -> U {
|
2012-10-17 18:40:18 -05:00
|
|
|
unsafe {
|
2012-12-24 08:56:04 -06:00
|
|
|
match local_data_pop(self.key) {
|
2012-10-18 14:27:09 -05:00
|
|
|
None => {
|
|
|
|
debug!("Condition.raise: found no handler");
|
2012-10-22 20:05:17 -05:00
|
|
|
default()
|
2012-10-18 14:27:09 -05:00
|
|
|
}
|
2012-10-17 18:40:18 -05:00
|
|
|
Some(handler) => {
|
2012-10-18 14:27:09 -05:00
|
|
|
debug!("Condition.raise: found handler");
|
2012-10-22 19:26:26 -05:00
|
|
|
match handler.prev {
|
2012-12-24 08:56:04 -06:00
|
|
|
None => {}
|
|
|
|
Some(hp) => local_data_set(self.key, hp)
|
2012-10-22 19:26:26 -05:00
|
|
|
}
|
2012-12-24 08:56:04 -06:00
|
|
|
let handle : &fn(T) -> U =
|
2012-10-22 19:26:26 -05:00
|
|
|
::cast::transmute(handler.handle);
|
|
|
|
let u = handle(t);
|
2012-12-24 08:56:04 -06:00
|
|
|
local_data_set(self.key, handler);
|
|
|
|
u
|
2012-10-17 18:40:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
struct Trap<T, U> {
|
2013-02-26 13:34:00 -06:00
|
|
|
cond: &self/Condition/&self<T, U>,
|
2012-10-22 19:26:26 -05:00
|
|
|
handler: @Handler<T, U>
|
2012-10-17 18:40:18 -05:00
|
|
|
}
|
|
|
|
|
2013-02-26 13:34:00 -06:00
|
|
|
pub impl<T, U> Trap/&self<T, U> {
|
2012-12-14 13:52:11 -06:00
|
|
|
fn in<V>(&self, inner: &self/fn() -> V) -> V {
|
2012-10-22 19:26:26 -05:00
|
|
|
unsafe {
|
|
|
|
let _g = Guard { cond: self.cond };
|
|
|
|
debug!("Trap: pushing handler to TLS");
|
2012-12-24 08:56:04 -06:00
|
|
|
local_data_set(self.cond.key, self.handler);
|
2012-10-22 19:26:26 -05:00
|
|
|
inner()
|
|
|
|
}
|
|
|
|
}
|
2012-10-18 14:27:09 -05:00
|
|
|
}
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
struct Guard<T, U> {
|
2013-02-26 13:34:00 -06:00
|
|
|
cond: &self/Condition/&self<T, U>
|
2012-12-24 08:56:04 -06:00
|
|
|
}
|
|
|
|
|
2013-02-26 13:34:00 -06:00
|
|
|
impl<T, U> Drop for Guard/&self<T, U> {
|
2012-12-24 08:56:04 -06:00
|
|
|
fn finalize(&self) {
|
2012-10-22 19:26:26 -05:00
|
|
|
unsafe {
|
|
|
|
debug!("Guard: popping handler from TLS");
|
2012-12-24 08:56:04 -06:00
|
|
|
let curr = local_data_pop(self.cond.key);
|
2012-10-22 19:26:26 -05:00
|
|
|
match curr {
|
2012-12-24 08:56:04 -06:00
|
|
|
None => {}
|
|
|
|
Some(h) => match h.prev {
|
|
|
|
None => {}
|
|
|
|
Some(hp) => local_data_set(self.cond.key, hp)
|
2012-10-22 19:26:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-10-18 14:27:09 -05:00
|
|
|
}
|
2012-10-18 21:47:19 -05:00
|
|
|
|
|
|
|
#[cfg(test)]
|
2012-10-22 19:26:26 -05:00
|
|
|
mod test {
|
2012-12-14 13:52:11 -06:00
|
|
|
condition! {
|
|
|
|
sadness: int -> int;
|
|
|
|
}
|
2012-11-06 19:13:52 -06:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
fn trouble(i: int) {
|
2012-12-24 08:56:04 -06:00
|
|
|
debug!("trouble: raising condition");
|
|
|
|
let j = sadness::cond.raise(i);
|
2012-10-22 19:26:26 -05:00
|
|
|
debug!("trouble: handler recovered with %d", j);
|
|
|
|
}
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
fn nested_trap_test_inner() {
|
|
|
|
let mut inner_trapped = false;
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
do sadness::cond.trap(|_j| {
|
2012-10-22 19:26:26 -05:00
|
|
|
debug!("nested_trap_test_inner: in handler");
|
|
|
|
inner_trapped = true;
|
|
|
|
0
|
|
|
|
}).in {
|
|
|
|
debug!("nested_trap_test_inner: in protected block");
|
|
|
|
trouble(1);
|
|
|
|
}
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
assert inner_trapped;
|
|
|
|
}
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
#[test]
|
|
|
|
fn nested_trap_test_outer() {
|
|
|
|
let mut outer_trapped = false;
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
do sadness::cond.trap(|_j| {
|
2012-10-22 19:26:26 -05:00
|
|
|
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);
|
|
|
|
}
|
2012-10-18 21:47:19 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
assert outer_trapped;
|
|
|
|
}
|
2012-10-19 16:46:32 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
fn nested_reraise_trap_test_inner() {
|
|
|
|
let mut inner_trapped = false;
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
do sadness::cond.trap(|_j| {
|
2012-10-22 19:26:26 -05:00
|
|
|
debug!("nested_reraise_trap_test_inner: in handler");
|
|
|
|
inner_trapped = true;
|
|
|
|
let i = 10;
|
|
|
|
debug!("nested_reraise_trap_test_inner: handler re-raising");
|
2012-12-24 08:56:04 -06:00
|
|
|
sadness::cond.raise(i)
|
2012-10-22 19:26:26 -05:00
|
|
|
}).in {
|
|
|
|
debug!("nested_reraise_trap_test_inner: in protected block");
|
|
|
|
trouble(1);
|
|
|
|
}
|
2012-10-19 16:46:32 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
assert inner_trapped;
|
2012-10-19 16:46:32 -05:00
|
|
|
}
|
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
#[test]
|
|
|
|
fn nested_reraise_trap_test_outer() {
|
|
|
|
let mut outer_trapped = false;
|
2012-10-19 16:46:32 -05:00
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
do sadness::cond.trap(|_j| {
|
2012-10-22 19:26:26 -05:00
|
|
|
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();
|
|
|
|
}
|
2012-10-19 16:46:32 -05:00
|
|
|
|
2012-10-22 19:26:26 -05:00
|
|
|
assert outer_trapped;
|
2012-10-19 16:46:32 -05:00
|
|
|
}
|
|
|
|
|
2012-10-22 20:05:17 -05:00
|
|
|
#[test]
|
|
|
|
fn test_default() {
|
|
|
|
let mut trapped = false;
|
|
|
|
|
2012-12-14 13:52:11 -06:00
|
|
|
do sadness::cond.trap(|j| {
|
2012-10-22 20:05:17 -05:00
|
|
|
debug!("test_default: in handler");
|
2012-12-24 08:56:04 -06:00
|
|
|
sadness::cond.raise_default(j, || { trapped=true; 5 })
|
2012-10-22 20:05:17 -05:00
|
|
|
}).in {
|
|
|
|
debug!("test_default: in protected block");
|
|
|
|
trouble(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert trapped;
|
|
|
|
}
|
|
|
|
}
|