OLD | NEW |
---|---|
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // Dart core library. | 2 // Dart core library. |
3 | 3 |
4 class FutureImpl<T> implements Future<T> { | 4 class FutureImpl<T> implements Future<T> { |
5 | 5 |
6 bool _isComplete = false; | 6 bool _isComplete = false; |
7 | 7 |
8 /** | 8 /** |
9 * Value that was provided to this Future by the Completer | 9 * Value that was provided to this Future by the Completer |
10 */ | 10 */ |
11 T _value; | 11 T _value; |
12 | 12 |
13 /** | 13 /** |
14 * Exception that occured, if there was a problem providing | 14 * Exception that occured, if there was a problem providing |
15 * Value. | 15 * Value. |
16 */ | 16 */ |
17 Object _exception; | 17 Object _exception; |
18 | 18 |
19 /** | 19 /** |
20 * true, if any onException handler handled the exception. | 20 * true, if any onException handler handled the exception. |
21 */ | 21 */ |
22 bool _exceptionHandled = false; | 22 bool _exceptionHandled = false; |
23 | 23 |
24 /** | 24 /** |
25 * Listeners waiting to receive the value of this future. | 25 * Listeners waiting to receive the value of this future. |
26 */ | 26 */ |
27 final List<Function> _listeners; | 27 final List<Function> _successListeners; |
28 | 28 |
29 /** | 29 /** |
30 * Exception handlers waiting for exceptions. | 30 * Exception handlers waiting for exceptions. |
31 */ | 31 */ |
32 final List<Function> _exceptionHandlers; | 32 final List<Function> _exceptionHandlers; |
33 | 33 |
34 /** | |
35 * Listeners waiting to be called when the future completes. | |
36 */ | |
37 final List<Function> _completionListeners; | |
38 | |
34 FutureImpl() | 39 FutureImpl() |
35 : _listeners = [], | 40 : _successListeners = [], |
36 _exceptionHandlers = []; | 41 _exceptionHandlers = [], |
42 _completionListeners = []; | |
37 | 43 |
38 factory FutureImpl.immediate(T value) { | 44 factory FutureImpl.immediate(T value) { |
39 final res = new FutureImpl(); | 45 final res = new FutureImpl(); |
40 res._setValue(value); | 46 res._setValue(value); |
41 return res; | 47 return res; |
42 } | 48 } |
43 | 49 |
44 T get value() { | 50 T get value() { |
45 if (!isComplete) { | 51 if (!isComplete) { |
46 throw new FutureNotCompleteException(); | 52 throw new FutureNotCompleteException(); |
(...skipping 12 matching lines...) Expand all Loading... | |
59 } | 65 } |
60 | 66 |
61 bool get isComplete() { | 67 bool get isComplete() { |
62 return _isComplete; | 68 return _isComplete; |
63 } | 69 } |
64 | 70 |
65 bool get hasValue() { | 71 bool get hasValue() { |
66 return isComplete && _exception === null; | 72 return isComplete && _exception === null; |
67 } | 73 } |
68 | 74 |
69 void then(void onComplete(T value)) { | 75 void then(void onSuccess(T value)) { |
70 if (hasValue) { | 76 if (hasValue) { |
71 onComplete(value); | 77 onSuccess(value); |
72 } else if (!isComplete) { | 78 } else if (!isComplete) { |
73 _listeners.add(onComplete); | 79 _successListeners.add(onSuccess); |
74 } else if (!_exceptionHandled) { | 80 } else if (!_exceptionHandled) { |
75 throw _exception; | 81 throw _exception; |
76 } | 82 } |
77 } | 83 } |
78 | 84 |
79 void handleException(bool onException(Object exception)) { | 85 void handleException(bool onException(Object exception)) { |
80 if (_exceptionHandled) return; | 86 if (_exceptionHandled) return; |
81 if (_isComplete) { | 87 if (_isComplete) { |
82 if (_exception != null) { | 88 if (_exception != null) { |
83 _exceptionHandled = onException(_exception); | 89 _exceptionHandled = onException(_exception); |
84 } | 90 } |
85 } else { | 91 } else { |
86 _exceptionHandlers.add(onException); | 92 _exceptionHandlers.add(onException); |
87 } | 93 } |
88 } | 94 } |
89 | 95 |
96 void onComplete(void complete(Future<T> future)) { | |
97 if (_isComplete) { | |
98 try { | |
99 complete(this); | |
100 } catch (final e) {} | |
101 } else { | |
102 _completionListeners.add(complete); | |
103 } | |
104 } | |
105 | |
90 void _complete() { | 106 void _complete() { |
91 _isComplete = true; | 107 _isComplete = true; |
108 | |
109 for (Function listener in _completionListeners) { | |
Jennifer Messerly
2012/06/04 20:11:17
shouldn't this come after we run _exceptionHandler
Bob Nystrom
2012/06/04 20:20:40
+1
sam.mccall
2012/06/04 21:35:57
Yeah, that's probably less surprising. When e.g. a
| |
110 try { | |
111 listener(this); | |
112 } catch (final e) {} | |
113 } | |
114 | |
92 if (_exception !== null) { | 115 if (_exception !== null) { |
93 for (Function handler in _exceptionHandlers) { | 116 for (Function handler in _exceptionHandlers) { |
94 // Explicitly check for true here so that if the handler returns null, | 117 // Explicitly check for true here so that if the handler returns null, |
95 // we don't get an exception in checked mode. | 118 // we don't get an exception in checked mode. |
96 if (handler(_exception) == true) { | 119 if (handler(_exception) == true) { |
97 _exceptionHandled = true; | 120 _exceptionHandled = true; |
98 break; | 121 break; |
99 } | 122 } |
100 } | 123 } |
101 } | 124 } |
102 | 125 |
103 if (hasValue) { | 126 if (hasValue) { |
104 for (Function listener in _listeners) { | 127 for (Function listener in _successListeners) { |
105 listener(value); | 128 listener(value); |
106 } | 129 } |
107 } else { | 130 } else { |
108 if (!_exceptionHandled && _listeners.length > 0) { | 131 if (!_exceptionHandled && _successListeners.length > 0) { |
109 throw _exception; | 132 throw _exception; |
110 } | 133 } |
111 } | 134 } |
112 } | 135 } |
113 | 136 |
114 void _setValue(T value) { | 137 void _setValue(T value) { |
115 if (_isComplete) { | 138 if (_isComplete) { |
116 throw new FutureAlreadyCompleteException(); | 139 throw new FutureAlreadyCompleteException(); |
117 } | 140 } |
118 _value = value; | 141 _value = value; |
119 _complete(); | 142 _complete(); |
120 } | 143 } |
121 | 144 |
122 void _setException(var exception) { | 145 void _setException(var exception) { |
123 if (exception === null) { | 146 if (exception === null) { |
124 // null is not a legal value for the exception of a Future | 147 // null is not a legal value for the exception of a Future |
125 throw new IllegalArgumentException(null); | 148 throw new IllegalArgumentException(null); |
126 } | 149 } |
127 if (_isComplete) { | 150 if (_isComplete) { |
128 throw new FutureAlreadyCompleteException(); | 151 throw new FutureAlreadyCompleteException(); |
129 } | 152 } |
130 _exception = exception; | 153 _exception = exception; |
131 _complete(); | 154 _complete(); |
132 } | 155 } |
133 | 156 |
134 Future transform(Function transformation) { | 157 Future transform(Function transformation) { |
135 final completer = new Completer(); | 158 final completer = new Completer(); |
136 handleException((e) { | 159 this.onComplete((f) { |
Jennifer Messerly
2012/06/04 20:11:17
do you need "this." here?
sam.mccall
2012/06/04 21:35:57
Nope, oops
| |
137 completer.completeException(e); | 160 if (!f.hasValue) { |
138 return true; | 161 completer.completeException(f.exception); |
139 }); | 162 return; |
140 then((v) { | 163 } |
141 var transformed = null; | 164 var transformed = null; |
142 try { | 165 try { |
143 transformed = transformation(v); | 166 transformed = transformation(f.value); |
144 } catch (final e) { | 167 } catch (final e) { |
145 completer.completeException(e); | 168 completer.completeException(e); |
146 return; | 169 return; |
147 } | 170 } |
148 completer.complete(transformed); | 171 completer.complete(transformed); |
149 }); | 172 }); |
150 return completer.future; | 173 return completer.future; |
151 } | 174 } |
152 | 175 |
153 Future chain(Function transformation) { | 176 Future chain(Function transformation) { |
154 final completer = new Completer(); | 177 final completer = new Completer(); |
155 handleException((e) { | 178 onComplete((f) { |
156 completer.completeException(e); | 179 if (!f.hasValue) { |
157 return true; | 180 completer.completeException(f.exception); |
158 }); | 181 return; |
159 then((v) { | 182 } |
160 var future = null; | 183 var future = null; |
161 try { | 184 try { |
162 future = transformation(v); | 185 future = transformation(f.value); |
163 } catch (final e) { | 186 } catch (final e) { |
164 completer.completeException(e); | 187 completer.completeException(e); |
165 return; | 188 return; |
166 } | 189 } |
167 future.handleException((e) { | 190 future.onComplete((g) { |
168 completer.completeException(e); | 191 if (g.hasValue) completer.complete(g.value); |
169 return true; | 192 else completer.completeException(g.exception); |
Jennifer Messerly
2012/06/04 20:22:28
This is interesting ... it almost suggests we shou
sam.mccall
2012/06/04 21:35:57
Yeah, I can't see any obvious other uses, so I'm n
Jennifer Messerly
2012/06/04 22:12:49
sgtm
| |
170 }); | 193 }); |
171 future.then((b) => completer.complete(b)); | |
172 }); | 194 }); |
173 return completer.future; | 195 return completer.future; |
174 } | 196 } |
175 } | 197 } |
176 | 198 |
177 class CompleterImpl<T> implements Completer<T> { | 199 class CompleterImpl<T> implements Completer<T> { |
178 | 200 |
179 final FutureImpl<T> _futureImpl; | 201 final FutureImpl<T> _futureImpl; |
180 | 202 |
181 CompleterImpl() : _futureImpl = new FutureImpl() {} | 203 CompleterImpl() : _futureImpl = new FutureImpl() {} |
182 | 204 |
183 Future<T> get future() { | 205 Future<T> get future() { |
184 return _futureImpl; | 206 return _futureImpl; |
185 } | 207 } |
186 | 208 |
187 void complete(T value) { | 209 void complete(T value) { |
188 _futureImpl._setValue(value); | 210 _futureImpl._setValue(value); |
189 } | 211 } |
190 | 212 |
191 void completeException(var exception) { | 213 void completeException(var exception) { |
192 _futureImpl._setException(exception); | 214 _futureImpl._setException(exception); |
193 } | 215 } |
194 } | 216 } |
OLD | NEW |