1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 /*! Condition handling */
13 #[allow(missing_doc)];
18 // helper for transmutation, shown below.
19 type RustClosure = (int, int);
21 pub struct Handler<T, U> {
23 prev: Option<@Handler<T, U>>,
26 pub struct Condition<T, U> {
28 key: local_data::Key<@Handler<T, U>>
31 impl<T, U> Condition<T, U> {
32 pub fn trap<'a>(&'a self, h: &'a fn(T) -> U) -> Trap<'a, T, U> {
34 let p : *RustClosure = ::cast::transmute(&h);
35 let prev = local_data::get(self.key, |k| k.map(|&x| *x));
36 let h = @Handler { handle: *p, prev: prev };
37 Trap { cond: self, handler: h }
41 pub fn raise(&self, t: T) -> U {
42 let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
43 self.raise_default(t, || fail!(msg.clone()))
46 pub fn raise_default(&self, t: T, default: &fn() -> U) -> U {
48 match local_data::pop(self.key) {
50 debug!("Condition.raise: found no handler");
54 debug!("Condition.raise: found handler");
57 Some(hp) => local_data::set(self.key, hp)
59 let handle : &fn(T) -> U =
60 ::cast::transmute(handler.handle);
62 local_data::set(self.key, handler);
70 struct Trap<'self, T, U> {
71 cond: &'self Condition<T, U>,
72 handler: @Handler<T, U>
75 impl<'self, T, U> Trap<'self, T, U> {
76 pub fn inside<V>(&self, inner: &'self fn() -> V) -> V {
77 let _g = Guard { cond: self.cond };
78 debug!("Trap: pushing handler to TLS");
79 local_data::set(self.cond.key, self.handler);
84 struct Guard<'self, T, U> {
85 cond: &'self Condition<T, U>
89 impl<'self, T, U> Drop for Guard<'self, T, U> {
91 debug!("Guard: popping handler from TLS");
92 let curr = local_data::pop(self.cond.key);
95 Some(h) => match h.prev {
97 Some(hp) => local_data::set(self.cond.key, hp)
110 debug!("trouble: raising condition");
111 let j = sadness::cond.raise(i);
112 debug!("trouble: handler recovered with %d", j);
115 fn nested_trap_test_inner() {
116 let mut inner_trapped = false;
118 do sadness::cond.trap(|_j| {
119 debug!("nested_trap_test_inner: in handler");
120 inner_trapped = true;
123 debug!("nested_trap_test_inner: in protected block");
127 assert!(inner_trapped);
131 fn nested_trap_test_outer() {
132 let mut outer_trapped = false;
134 do sadness::cond.trap(|_j| {
135 debug!("nested_trap_test_outer: in handler");
136 outer_trapped = true; 0
138 debug!("nested_guard_test_outer: in protected block");
139 nested_trap_test_inner();
143 assert!(outer_trapped);
146 fn nested_reraise_trap_test_inner() {
147 let mut inner_trapped = false;
149 do sadness::cond.trap(|_j| {
150 debug!("nested_reraise_trap_test_inner: in handler");
151 inner_trapped = true;
153 debug!("nested_reraise_trap_test_inner: handler re-raising");
154 sadness::cond.raise(i)
156 debug!("nested_reraise_trap_test_inner: in protected block");
160 assert!(inner_trapped);
164 fn nested_reraise_trap_test_outer() {
165 let mut outer_trapped = false;
167 do sadness::cond.trap(|_j| {
168 debug!("nested_reraise_trap_test_outer: in handler");
169 outer_trapped = true; 0
171 debug!("nested_reraise_trap_test_outer: in protected block");
172 nested_reraise_trap_test_inner();
175 assert!(outer_trapped);
180 let mut trapped = false;
182 do sadness::cond.trap(|j| {
183 debug!("test_default: in handler");
184 sadness::cond.raise_default(j, || { trapped=true; 5 })
186 debug!("test_default: in protected block");
196 // #6009, #8215: should this truly need a `pub` for access from n?
197 pub sadness: int -> int;
204 fn test_conditions_are_public() {
205 let mut trapped = false;
206 do sadness::cond.trap(|_| {
210 sadness::cond.raise(0);