8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- /*!
11
+ /*! Condition handling */
12
12
13
- Condition handling
14
-
15
- Conditions are a utility used to deal with handling error conditions. The syntax
16
- of a condition handler strikes a resemblance to try/catch blocks in other
17
- languages, but condition handlers are *not* a form of exception handling in the
18
- same manner.
19
-
20
- A condition is declared through the `condition!` macro provided by the compiler:
21
-
22
- ~~~{.rust}
23
- condition! {
24
- pub my_error: int -> ~str;
25
- }
26
- ~~~
27
-
28
- This macro declares an inner module called `my_error` with one static variable,
29
- `cond` that is a static `Condition` instance. To help understand what the other
30
- parameters are used for, an example usage of this condition would be:
31
-
32
- ~~~{.rust}
33
- do my_error::cond.trap(|raised_int| {
34
-
35
- // the condition `my_error` was raised on, and the value it raised is stored
36
- // in `raised_int`. This closure must return a `~str` type (as specified in
37
- // the declaration of the condition
38
- if raised_int == 3 { ~"three" } else { ~"oh well" }
39
-
40
- }).inside {
41
-
42
- // The condition handler above is installed for the duration of this block.
43
- // That handler will override any previous handler, but the previous handler
44
- // is restored when this block returns (handlers nest)
45
- //
46
- // If any code from this block (or code from another block) raises on the
47
- // condition, then the above handler will be invoked (so long as there's no
48
- // other nested handler).
49
-
50
- println(my_error::cond.raise(3)); // prints "three"
51
- println(my_error::cond.raise(4)); // prints "oh well"
52
-
53
- }
54
- ~~~
55
-
56
- Condition handling is useful in cases where propagating errors is either to
57
- cumbersome or just not necessary in the first place. It should also be noted,
58
- though, that if there is not handler installed when a condition is raised, then
59
- the task invokes `fail!()` and will terminate.
60
-
61
- ## More Info
62
-
63
- Condition handlers as an error strategy is well explained in the [conditions
64
- tutorial](http://static.rust-lang.org/doc/master/tutorial-conditions.html),
65
- along with comparing and contrasting it with other error handling strategies.
66
-
67
- */
13
+ #[ allow( missing_doc) ] ;
68
14
69
15
use local_data;
70
16
use prelude:: * ;
71
- use unstable:: raw:: Closure ;
72
17
73
- #[ doc( hidden) ]
18
+ // helper for transmutation, shown below.
19
+ type RustClosure = ( int , int ) ;
20
+
74
21
pub struct Handler < T , U > {
75
- priv handle : Closure ,
76
- priv prev : Option < @Handler < T , U > > ,
22
+ handle : RustClosure ,
23
+ prev : Option < @Handler < T , U > > ,
77
24
}
78
25
79
- /// This struct represents the state of a condition handler. It contains a key
80
- /// into TLS which holds the currently install handler, along with the name of
81
- /// the condition (useful for debugging).
82
- ///
83
- /// This struct should never be created directly, but rather only through the
84
- /// `condition!` macro provided to all libraries using libstd.
85
26
pub struct Condition < T , U > {
86
- /// Name of the condition handler
87
27
name : & ' static str ,
88
- /// TLS key used to insert/remove values in TLS.
89
28
key : local_data:: Key < @Handler < T , U > >
90
29
}
91
30
92
31
impl < T , U > Condition < T , U > {
93
- /// Creates an object which binds the specified handler. This will also save
94
- /// the current handler *on creation* such that when the `Trap` is consumed,
95
- /// it knows which handler to restore.
96
- ///
97
- /// # Example
98
- ///
99
- /// ~~~{.rust}
100
- /// condition! { my_error: int -> int; }
101
- ///
102
- /// let trap = my_error::cond.trap(|error| error + 3);
103
- ///
104
- /// // use `trap`'s inside method to register the handler and then run a
105
- /// // block of code with the handler registered
106
- /// ~~~
107
32
pub fn trap < ' a > ( & ' a self , h : & ' a fn ( T ) -> U ) -> Trap < ' a , T , U > {
108
- let h: Closure = unsafe { :: cast:: transmute ( h) } ;
109
- let prev = local_data:: get ( self . key , |k| k. map ( |& x| * x) ) ;
110
- let h = @Handler { handle : h, prev : prev } ;
111
- Trap { cond : self , handler : h }
33
+ unsafe {
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 }
38
+ }
112
39
}
113
40
114
- /// Raises on this condition, invoking any handler if one has been
115
- /// registered, or failing the current task otherwise.
116
- ///
117
- /// While a condition handler is being run, the condition will have no
118
- /// handler listed, so a task failure will occur if the condition is
119
- /// re-raised during the handler.
120
- ///
121
- /// # Arguments
122
- ///
123
- /// * t - The argument to pass along to the condition handler.
124
- ///
125
- /// # Return value
126
- ///
127
- /// If a handler is found, its return value is returned, otherwise this
128
- /// function will not return.
129
41
pub fn raise ( & self , t : T ) -> U {
130
42
let msg = fmt ! ( "Unhandled condition: %s: %?" , self . name, t) ;
131
43
self . raise_default ( t, || fail ! ( msg. clone( ) ) )
132
44
}
133
45
134
- /// Performs the same functionality as `raise`, except that when no handler
135
- /// is found the `default` argument is called instead of failing the task.
136
46
pub fn raise_default ( & self , t : T , default : & fn ( ) -> U ) -> U {
137
- match local_data:: pop ( self . key ) {
138
- None => {
139
- debug ! ( "Condition.raise: found no handler" ) ;
140
- default ( )
141
- }
142
- Some ( handler) => {
143
- debug ! ( "Condition.raise: found handler" ) ;
144
- match handler. prev {
145
- None => { }
146
- Some ( hp) => local_data:: set ( self . key , hp)
47
+ unsafe {
48
+ match local_data:: pop ( self . key ) {
49
+ None => {
50
+ debug ! ( "Condition.raise: found no handler" ) ;
51
+ default ( )
52
+ }
53
+ Some ( handler) => {
54
+ debug ! ( "Condition.raise: found handler" ) ;
55
+ match handler. prev {
56
+ None => { }
57
+ Some ( hp) => local_data:: set ( self . key , hp)
58
+ }
59
+ let handle : & fn ( T ) -> U =
60
+ :: cast:: transmute ( handler. handle ) ;
61
+ let u = handle ( t) ;
62
+ local_data:: set ( self . key , handler) ;
63
+ u
147
64
}
148
- let handle : & fn ( T ) -> U = unsafe {
149
- :: cast:: transmute ( handler. handle )
150
- } ;
151
- let u = handle ( t) ;
152
- local_data:: set ( self . key , handler) ;
153
- u
154
65
}
155
66
}
156
67
}
157
68
}
158
69
159
- /// A `Trap` is created when the `trap` method is invoked on a `Condition`, and
160
- /// it is used to actually bind a handler into the TLS slot reserved for this
161
- /// condition.
162
- ///
163
- /// Normally this object is not dealt with directly, but rather it's directly
164
- /// used after being returned from `trap`
165
70
struct Trap < ' self , T , U > {
166
- priv cond : & ' self Condition < T , U > ,
167
- priv handler : @Handler < T , U >
71
+ cond : & ' self Condition < T , U > ,
72
+ handler : @Handler < T , U >
168
73
}
169
74
170
75
impl < ' self , T , U > Trap < ' self , T , U > {
171
- /// Execute a block of code with this trap handler's exception handler
172
- /// registered.
173
- ///
174
- /// # Example
175
- ///
176
- /// ~~~{.rust}
177
- /// condition! { my_error: int -> int; }
178
- ///
179
- /// let result = do my_error::cond.trap(|error| error + 3).inside {
180
- /// my_error::cond.raise(4)
181
- /// };
182
- /// assert_eq!(result, 7);
183
- /// ~~~
184
76
pub fn inside < V > ( & self , inner : & ' self fn ( ) -> V ) -> V {
185
77
let _g = Guard { cond : self . cond } ;
186
78
debug ! ( "Trap: pushing handler to TLS" ) ;
@@ -189,9 +81,8 @@ impl<'self, T, U> Trap<'self, T, U> {
189
81
}
190
82
}
191
83
192
- #[ doc( hidden) ]
193
84
struct Guard < ' self , T , U > {
194
- priv cond : & ' self Condition < T , U >
85
+ cond : & ' self Condition < T , U >
195
86
}
196
87
197
88
#[ unsafe_destructor]
0 commit comments