1
+ // helper for transmutation, shown below.
2
+ type RustClosure = ( int , int ) ;
3
+
4
+ struct Condition {
5
+ key : task:: local_data:: LocalDataKey < Handler >
6
+ }
7
+
8
+ struct Handler {
9
+ // Handler should link to previous handler and
10
+ // reinstall it when popped.
11
+ handle : RustClosure
12
+ }
13
+
14
+
15
+ struct ProtectBlock {
16
+ cond : & Condition ,
17
+ inner : RustClosure
18
+ }
19
+
20
+ struct PopHandler {
21
+ cond : & Condition ,
22
+ drop {
23
+ unsafe {
24
+ task : : local_data:: local_data_pop ( self . cond. key) ;
25
+ }
26
+ }
27
+ }
28
+
29
+ struct HandleBlock {
30
+ pb : & ProtectBlock ,
31
+ handler : @Handler ,
32
+ drop {
33
+ unsafe {
34
+ task:: local_data:: local_data_set ( self . pb . cond . key ,
35
+ self . handler ) ;
36
+ let _pop = PopHandler { cond : self . pb . cond } ;
37
+ // transmutation to avoid copying non-copyable, should
38
+ // be fixable by tracking closure pointees in regionck.
39
+ let f : & fn ( ) = :: cast:: transmute ( self . pb . inner ) ;
40
+ f ( ) ;
41
+ }
42
+ }
43
+ }
44
+
45
+ impl ProtectBlock {
46
+ fn handle < T , U : Copy > ( & self , h : & self /fn ( & T ) ->U ) -> HandleBlock /& self {
47
+ unsafe {
48
+ let p : * RustClosure = :: cast:: transmute ( & h) ;
49
+ HandleBlock { pb : self ,
50
+ handler : @Handler { handle : * p} }
51
+ }
52
+ }
53
+ }
54
+
55
+
56
+ impl Condition {
57
+
58
+ fn protect ( & self , inner : & self /fn ( ) ) -> ProtectBlock /& self {
59
+ unsafe {
60
+ // transmutation to avoid copying non-copyable, should
61
+ // be fixable by tracking closure pointees in regionck.
62
+ let p : * RustClosure = :: cast:: transmute ( & inner) ;
63
+ ProtectBlock { cond : self ,
64
+ inner : * p } }
65
+ }
66
+
67
+ fn raise < T , U : Copy > ( t : & T ) -> U {
68
+ unsafe {
69
+ match task:: local_data:: local_data_get ( self . key ) {
70
+ None => fail,
71
+ Some ( handler) => {
72
+ io:: println ( "got handler" ) ;
73
+ let f : & fn ( & T ) -> U = :: cast:: transmute ( handler. handle ) ;
74
+ f ( t)
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+
82
+ #[ test]
83
+ fn happiness_key ( _x : @Handler ) { }
84
+
85
+ #[ test]
86
+ fn sadness_key ( _x : @Handler ) { }
87
+
88
+ #[ test]
89
+ fn trouble ( i : int ) {
90
+ // Condition should work as a const, just limitations in consts.
91
+ let sadness_condition : Condition = Condition { key : sadness_key } ;
92
+ io:: println ( "raising" ) ;
93
+ let j = sadness_condition. raise ( & i) ;
94
+ io:: println ( fmt ! ( "handler recovered with %d" , j) ) ;
95
+ }
96
+
97
+ #[ test]
98
+ fn test ( ) {
99
+
100
+ let sadness_condition : Condition = Condition { key : sadness_key } ;
101
+
102
+ let mut i = 10 ;
103
+
104
+ let b = do sadness_condition. protect {
105
+ io:: println ( "in protected block" ) ;
106
+ trouble ( 1 ) ;
107
+ trouble ( 2 ) ;
108
+ trouble ( 3 ) ;
109
+ } ;
110
+
111
+ do b. handle |j| {
112
+ i += * j;
113
+ i
114
+ } ;
115
+
116
+ assert i == 16 ;
117
+ }
0 commit comments