OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.async; | |
6 | |
7 typedef R ZoneCallback<R>(); | |
8 typedef R ZoneUnaryCallback<R, T>(T arg); | |
9 typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2); | |
10 | |
11 // TODO(floitsch): we are abusing generic typedefs as typedefs for generic | |
12 // functions. | |
13 /*ABUSE*/ | |
14 typedef R HandleUncaughtErrorHandler<R>( | |
15 Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace); | |
16 /*ABUSE*/ | |
17 typedef R RunHandler<R>(Zone self, ZoneDelegate parent, Zone zone, R f()); | |
18 /*ABUSE*/ | |
19 typedef R RunUnaryHandler<R, T>( | |
20 Zone self, ZoneDelegate parent, Zone zone, R f(T arg), T arg); | |
21 /*ABUSE*/ | |
22 typedef R RunBinaryHandler<R, T1, T2>( | |
23 Zone self, ZoneDelegate parent, Zone zone, | |
24 R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2); | |
25 /*ABUSE*/ | |
26 typedef ZoneCallback<R> RegisterCallbackHandler<R>( | |
27 Zone self, ZoneDelegate parent, Zone zone, R f()); | |
28 /*ABUSE*/ | |
29 typedef ZoneUnaryCallback<R, T> RegisterUnaryCallbackHandler<R, T>( | |
30 Zone self, ZoneDelegate parent, Zone zone, R f(T arg)); | |
31 /*ABUSE*/ | |
32 typedef ZoneBinaryCallback<R, T1, T2> RegisterBinaryCallbackHandler<R, T1, T2>( | |
33 Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2)); | |
34 typedef AsyncError ErrorCallbackHandler(Zone self, ZoneDelegate parent, | |
35 Zone zone, Object error, StackTrace stackTrace); | |
36 typedef void ScheduleMicrotaskHandler( | |
37 Zone self, ZoneDelegate parent, Zone zone, void f()); | |
38 typedef Timer CreateTimerHandler( | |
39 Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f()); | |
40 typedef Timer CreatePeriodicTimerHandler( | |
41 Zone self, ZoneDelegate parent, Zone zone, | |
42 Duration period, void f(Timer timer)); | |
43 typedef void PrintHandler( | |
44 Zone self, ZoneDelegate parent, Zone zone, String line); | |
45 typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone, | |
46 ZoneSpecification specification, | |
47 Map zoneValues); | |
48 | |
49 /** Pair of error and stack trace. Returned by [Zone.errorCallback]. */ | |
50 class AsyncError implements Error { | |
51 final Object error; | |
52 final StackTrace stackTrace; | |
53 | |
54 AsyncError(this.error, this.stackTrace); | |
55 | |
56 String toString() => '$error'; | |
57 } | |
58 | |
59 | |
60 class _ZoneFunction<T extends Function> { | |
61 final _Zone zone; | |
62 final T function; | |
63 const _ZoneFunction(this.zone, this.function); | |
64 } | |
65 | |
66 /** | |
67 * This class provides the specification for a forked zone. | |
68 * | |
69 * When forking a new zone (see [Zone.fork]) one can override the default | |
70 * behavior of the zone by providing callbacks. These callbacks must be | |
71 * given in an instance of this class. | |
72 * | |
73 * Handlers have the same signature as the same-named methods on [Zone] but | |
74 * receive three additional arguments: | |
75 * | |
76 * 1. the zone the handlers are attached to (the "self" zone). | |
77 * 2. a [ZoneDelegate] to the parent zone. | |
78 * 3. the zone that first received the request (before the request was | |
79 * bubbled up). | |
80 * | |
81 * Handlers can either stop propagation the request (by simply not calling the | |
82 * parent handler), or forward to the parent zone, potentially modifying the | |
83 * arguments on the way. | |
84 */ | |
85 abstract class ZoneSpecification { | |
86 /** | |
87 * Creates a specification with the provided handlers. | |
88 */ | |
89 const factory ZoneSpecification({ | |
90 HandleUncaughtErrorHandler handleUncaughtError, | |
91 RunHandler run, | |
92 RunUnaryHandler runUnary, | |
93 RunBinaryHandler runBinary, | |
94 RegisterCallbackHandler registerCallback, | |
95 RegisterUnaryCallbackHandler registerUnaryCallback, | |
96 RegisterBinaryCallbackHandler registerBinaryCallback, | |
97 ErrorCallbackHandler errorCallback, | |
98 ScheduleMicrotaskHandler scheduleMicrotask, | |
99 CreateTimerHandler createTimer, | |
100 CreatePeriodicTimerHandler createPeriodicTimer, | |
101 PrintHandler print, | |
102 ForkHandler fork | |
103 }) = _ZoneSpecification; | |
104 | |
105 /** | |
106 * Creates a specification from [other] with the provided handlers overriding | |
107 * the ones in [other]. | |
108 */ | |
109 factory ZoneSpecification.from(ZoneSpecification other, { | |
110 HandleUncaughtErrorHandler handleUncaughtError: null, | |
111 RunHandler run: null, | |
112 RunUnaryHandler runUnary: null, | |
113 RunBinaryHandler runBinary: null, | |
114 RegisterCallbackHandler registerCallback: null, | |
115 RegisterUnaryCallbackHandler registerUnaryCallback: null, | |
116 RegisterBinaryCallbackHandler registerBinaryCallback: null, | |
117 ErrorCallbackHandler errorCallback: null, | |
118 ScheduleMicrotaskHandler scheduleMicrotask: null, | |
119 CreateTimerHandler createTimer: null, | |
120 CreatePeriodicTimerHandler createPeriodicTimer: null, | |
121 PrintHandler print: null, | |
122 ForkHandler fork: null | |
123 }) { | |
124 return new ZoneSpecification( | |
125 handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError, | |
126 run: run ?? other.run, | |
127 runUnary: runUnary ?? other.runUnary, | |
128 runBinary: runBinary ?? other.runBinary, | |
129 registerCallback: registerCallback ?? other.registerCallback, | |
130 registerUnaryCallback: registerUnaryCallback ?? | |
131 other.registerUnaryCallback, | |
132 registerBinaryCallback: registerBinaryCallback ?? | |
133 other.registerBinaryCallback, | |
134 errorCallback: errorCallback ?? other.errorCallback, | |
135 scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask, | |
136 createTimer : createTimer ?? other.createTimer, | |
137 createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer, | |
138 print : print ?? other.print, | |
139 fork: fork ?? other.fork); | |
140 } | |
141 | |
142 HandleUncaughtErrorHandler get handleUncaughtError; | |
143 RunHandler get run; | |
144 RunUnaryHandler get runUnary; | |
145 RunBinaryHandler get runBinary; | |
146 RegisterCallbackHandler get registerCallback; | |
147 RegisterUnaryCallbackHandler get registerUnaryCallback; | |
148 RegisterBinaryCallbackHandler get registerBinaryCallback; | |
149 ErrorCallbackHandler get errorCallback; | |
150 ScheduleMicrotaskHandler get scheduleMicrotask; | |
151 CreateTimerHandler get createTimer; | |
152 CreatePeriodicTimerHandler get createPeriodicTimer; | |
153 PrintHandler get print; | |
154 ForkHandler get fork; | |
155 } | |
156 | |
157 /** | |
158 * Internal [ZoneSpecification] class. | |
159 * | |
160 * The implementation wants to rely on the fact that the getters cannot change | |
161 * dynamically. We thus require users to go through the redirecting | |
162 * [ZoneSpecification] constructor which instantiates this class. | |
163 */ | |
164 class _ZoneSpecification implements ZoneSpecification { | |
165 const _ZoneSpecification({ | |
166 this.handleUncaughtError: null, | |
167 this.run: null, | |
168 this.runUnary: null, | |
169 this.runBinary: null, | |
170 this.registerCallback: null, | |
171 this.registerUnaryCallback: null, | |
172 this.registerBinaryCallback: null, | |
173 this.errorCallback: null, | |
174 this.scheduleMicrotask: null, | |
175 this.createTimer: null, | |
176 this.createPeriodicTimer: null, | |
177 this.print: null, | |
178 this.fork: null | |
179 }); | |
180 | |
181 final HandleUncaughtErrorHandler handleUncaughtError; | |
182 final RunHandler run; | |
183 final RunUnaryHandler runUnary; | |
184 final RunBinaryHandler runBinary; | |
185 final RegisterCallbackHandler registerCallback; | |
186 final RegisterUnaryCallbackHandler registerUnaryCallback; | |
187 final RegisterBinaryCallbackHandler registerBinaryCallback; | |
188 final ErrorCallbackHandler errorCallback; | |
189 final ScheduleMicrotaskHandler scheduleMicrotask; | |
190 final CreateTimerHandler createTimer; | |
191 final CreatePeriodicTimerHandler createPeriodicTimer; | |
192 final PrintHandler print; | |
193 final ForkHandler fork; | |
194 } | |
195 | |
196 /** | |
197 * This class wraps zones for delegation. | |
198 * | |
199 * When forwarding to parent zones one can't just invoke the parent zone's | |
200 * exposed functions (like [Zone.run]), but one needs to provide more | |
201 * information (like the zone the `run` was initiated). Zone callbacks thus | |
202 * receive more information including this [ZoneDelegate] class. When delegating | |
203 * to the parent zone one should go through the given instance instead of | |
204 * directly invoking the parent zone. | |
205 */ | |
206 abstract class ZoneDelegate { | |
207 /*=R*/ handleUncaughtError/*<R>*/( | |
208 Zone zone, error, StackTrace stackTrace); | |
209 /*=R*/ run/*<R>*/(Zone zone, /*=R*/ f()); | |
210 /*=R*/ runUnary/*<R, T>*/(Zone zone, /*=R*/ f(/*=T*/ arg), /*=T*/ arg); | |
211 /*=R*/ runBinary/*<R, T1, T2>*/(Zone zone, | |
212 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2); | |
213 ZoneCallback/*<R>*/ registerCallback/*<R>*/(Zone zone, /*=R*/ f()); | |
214 ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/( | |
215 Zone zone, /*=R*/ f(/*=T*/ arg)); | |
216 ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/( | |
217 Zone zone, /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)); | |
218 AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace); | |
219 void scheduleMicrotask(Zone zone, void f()); | |
220 Timer createTimer(Zone zone, Duration duration, void f()); | |
221 Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)); | |
222 void print(Zone zone, String line); | |
223 Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues); | |
224 } | |
225 | |
226 /** | |
227 * A Zone represents the asynchronous version of a dynamic extent. Asynchronous | |
228 * callbacks are executed in the zone they have been queued in. For example, | |
229 * the callback of a `future.then` is executed in the same zone as the one where | |
230 * the `then` was invoked. | |
231 */ | |
232 abstract class Zone { | |
233 // Private constructor so that it is not possible instantiate a Zone class. | |
234 Zone._(); | |
235 | |
236 /** The root zone that is implicitly created. */ | |
237 static const Zone ROOT = _ROOT_ZONE; | |
238 | |
239 /** The currently running zone. */ | |
240 static Zone _current = _ROOT_ZONE; | |
241 | |
242 static Zone get current => _current; | |
243 | |
244 /*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace); | |
245 | |
246 /** | |
247 * Returns the parent zone. | |
248 * | |
249 * Returns `null` if `this` is the [ROOT] zone. | |
250 */ | |
251 Zone get parent; | |
252 | |
253 /** | |
254 * The error zone is the one that is responsible for dealing with uncaught | |
255 * errors. | |
256 * Errors are not allowed to cross between zones with different error-zones. | |
257 * | |
258 * This is the closest parent or ancestor zone of this zone that has a custom | |
259 * [handleUncaughtError] method. | |
260 */ | |
261 Zone get errorZone; | |
262 | |
263 /** | |
264 * Returns true if `this` and [otherZone] are in the same error zone. | |
265 * | |
266 * Two zones are in the same error zone if they inherit their | |
267 * [handleUncaughtError] callback from the same [errorZone]. | |
268 */ | |
269 bool inSameErrorZone(Zone otherZone); | |
270 | |
271 /** | |
272 * Creates a new zone as a child of `this`. | |
273 * | |
274 * The new zone will have behavior like the current zone, except where | |
275 * overridden by functions in [specification]. | |
276 * | |
277 * The new zone will have the same stored values (accessed through | |
278 * `operator []`) as this zone, but updated with the keys and values | |
279 * in [zoneValues]. If a key is in both this zone's values and in | |
280 * `zoneValues`, the new zone will use the value from `zoneValues``. | |
281 */ | |
282 Zone fork({ ZoneSpecification specification, | |
283 Map zoneValues }); | |
284 | |
285 /** | |
286 * Executes the given function [f] in this zone. | |
287 */ | |
288 /*=R*/ run/*<R>*/(/*=R*/ f()); | |
289 | |
290 /** | |
291 * Executes the given callback [f] with argument [arg] in this zone. | |
292 */ | |
293 /*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg); | |
294 | |
295 /** | |
296 * Executes the given callback [f] with argument [arg1] and [arg2] in this | |
297 * zone. | |
298 */ | |
299 /*=R*/ runBinary/*<R, T1, T2>*/( | |
300 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2); | |
301 | |
302 /** | |
303 * Executes the given function [f] in this zone. | |
304 * | |
305 * Same as [run] but catches uncaught errors and gives them to | |
306 * [handleUncaughtError]. | |
307 */ | |
308 /*=R*/ runGuarded/*<R>*/(/*=R*/ f()); | |
309 | |
310 /** | |
311 * Executes the given callback [f] in this zone. | |
312 * | |
313 * Same as [runUnary] but catches uncaught errors and gives them to | |
314 * [handleUncaughtError]. | |
315 */ | |
316 /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg); | |
317 | |
318 /** | |
319 * Executes the given callback [f] in this zone. | |
320 * | |
321 * Same as [runBinary] but catches uncaught errors and gives them to | |
322 * [handleUncaughtError]. | |
323 */ | |
324 /*=R*/ runBinaryGuarded/*<R, T1, T2>*/( | |
325 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2); | |
326 | |
327 /** | |
328 * Registers the given callback in this zone. | |
329 * | |
330 * It is good practice to register asynchronous or delayed callbacks before | |
331 * invoking [run]. This gives the zone a chance to wrap the callback and | |
332 * to store information with the callback. For example, a zone may decide | |
333 * to store the stack trace (at the time of the registration) with the | |
334 * callback. | |
335 * | |
336 * Returns a potentially new callback that should be used in place of the | |
337 * given [callback]. | |
338 */ | |
339 ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback()); | |
340 | |
341 /** | |
342 * Registers the given callback in this zone. | |
343 * | |
344 * Similar to [registerCallback] but with a unary callback. | |
345 */ | |
346 ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/( | |
347 /*=R*/ callback(/*=T*/ arg)); | |
348 | |
349 /** | |
350 * Registers the given callback in this zone. | |
351 * | |
352 * Similar to [registerCallback] but with a unary callback. | |
353 */ | |
354 ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/( | |
355 /*=R*/ callback(/*=T1*/ arg1, /*=T2*/ arg2)); | |
356 | |
357 /** | |
358 * Equivalent to: | |
359 * | |
360 * ZoneCallback registered = registerCallback(f); | |
361 * if (runGuarded) return () => this.runGuarded(registered); | |
362 * return () => this.run(registered); | |
363 * | |
364 */ | |
365 ZoneCallback/*<R>*/ bindCallback/*<R>*/( | |
366 /*=R*/ f(), { bool runGuarded: true }); | |
367 | |
368 /** | |
369 * Equivalent to: | |
370 * | |
371 * ZoneCallback registered = registerUnaryCallback(f); | |
372 * if (runGuarded) return (arg) => this.runUnaryGuarded(registered, arg); | |
373 * return (arg) => thin.runUnary(registered, arg); | |
374 */ | |
375 ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/( | |
376 /*=R*/ f(/*=T*/ arg), { bool runGuarded: true }); | |
377 | |
378 /** | |
379 * Equivalent to: | |
380 * | |
381 * ZoneCallback registered = registerBinaryCallback(f); | |
382 * if (runGuarded) { | |
383 * return (arg1, arg2) => this.runBinaryGuarded(registered, arg); | |
384 * } | |
385 * return (arg1, arg2) => thin.runBinary(registered, arg1, arg2); | |
386 */ | |
387 ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/( | |
388 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true }); | |
389 | |
390 /** | |
391 * Intercepts errors when added programmatically to a `Future` or `Stream`. | |
392 * | |
393 * When caling [Completer.completeError], [Stream.addError], | |
394 * or [Future] constructors that take an error or a callback that may throw, | |
395 * the current zone is allowed to intercept and replace the error. | |
396 * | |
397 * When other libraries use intermediate controllers or completers, such | |
398 * calls may contain errors that have already been processed. | |
399 * | |
400 * Return `null` if no replacement is desired. | |
401 * The original error is used unchanged in that case. | |
402 * Otherwise return an instance of [AsyncError] holding | |
403 * the new pair of error and stack trace. | |
404 * If the [AsyncError.error] is `null`, it is replaced by a [NullThrownError]. | |
405 */ | |
406 AsyncError errorCallback(Object error, StackTrace stackTrace); | |
407 | |
408 /** | |
409 * Runs [f] asynchronously in this zone. | |
410 */ | |
411 void scheduleMicrotask(void f()); | |
412 | |
413 /** | |
414 * Creates a Timer where the callback is executed in this zone. | |
415 */ | |
416 Timer createTimer(Duration duration, void callback()); | |
417 | |
418 /** | |
419 * Creates a periodic Timer where the callback is executed in this zone. | |
420 */ | |
421 Timer createPeriodicTimer(Duration period, void callback(Timer timer)); | |
422 | |
423 /** | |
424 * Prints the given [line]. | |
425 */ | |
426 void print(String line); | |
427 | |
428 /** | |
429 * Call to enter the Zone. | |
430 * | |
431 * The previous current zone is returned. | |
432 */ | |
433 static Zone _enter(Zone zone) { | |
434 assert(zone != null); | |
435 assert(!identical(zone, _current)); | |
436 Zone previous = _current; | |
437 _current = zone; | |
438 return previous; | |
439 } | |
440 | |
441 /** | |
442 * Call to leave the Zone. | |
443 * | |
444 * The previous Zone must be provided as `previous`. | |
445 */ | |
446 static void _leave(Zone previous) { | |
447 assert(previous != null); | |
448 Zone._current = previous; | |
449 } | |
450 | |
451 /** | |
452 * Retrieves the zone-value associated with [key]. | |
453 * | |
454 * If this zone does not contain the value looks up the same key in the | |
455 * parent zone. If the [key] is not found returns `null`. | |
456 * | |
457 * Any object can be used as key, as long as it has compatible `operator ==` | |
458 * and `hashCode` implementations. | |
459 * By controlling access to the key, a zone can grant or deny access to the | |
460 * zone value. | |
461 */ | |
462 operator [](Object key); | |
463 } | |
464 | |
465 ZoneDelegate _parentDelegate(_Zone zone) { | |
466 if (zone.parent == null) return null; | |
467 return zone.parent._delegate; | |
468 } | |
469 | |
470 class _ZoneDelegate implements ZoneDelegate { | |
471 final _Zone _delegationTarget; | |
472 | |
473 _ZoneDelegate(this._delegationTarget); | |
474 | |
475 /*=R*/ handleUncaughtError/*<R>*/( | |
476 Zone zone, error, StackTrace stackTrace) { | |
477 var implementation = _delegationTarget._handleUncaughtError; | |
478 _Zone implZone = implementation.zone; | |
479 HandleUncaughtErrorHandler handler = implementation.function; | |
480 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
481 // supported. Remove the unnecessary cast. | |
482 return handler( | |
483 implZone, _parentDelegate(implZone), zone, error, stackTrace) | |
484 as Object/*=R*/; | |
485 } | |
486 | |
487 /*=R*/ run/*<R>*/(Zone zone, /*=R*/ f()) { | |
488 var implementation = _delegationTarget._run; | |
489 _Zone implZone = implementation.zone; | |
490 RunHandler handler = implementation.function; | |
491 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
492 // supported. Remove the unnecessary cast. | |
493 return handler(implZone, _parentDelegate(implZone), zone, f) | |
494 as Object/*=R*/; | |
495 } | |
496 | |
497 /*=R*/ runUnary/*<R, T>*/(Zone zone, /*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
498 var implementation = _delegationTarget._runUnary; | |
499 _Zone implZone = implementation.zone; | |
500 RunUnaryHandler handler = implementation.function; | |
501 // TODO(floitsch): make this a generic method call on '<R, T>' once it's | |
502 // supported. Remove the unnecessary cast. | |
503 return handler( | |
504 implZone, _parentDelegate(implZone), zone, f, arg) as Object/*=R*/; | |
505 } | |
506 | |
507 /*=R*/ runBinary/*<R, T1, T2>*/(Zone zone, | |
508 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
509 var implementation = _delegationTarget._runBinary; | |
510 _Zone implZone = implementation.zone; | |
511 RunBinaryHandler handler = implementation.function; | |
512 // TODO(floitsch): make this a generic method call on '<R, T1, T2>' once | |
513 // it's supported. Remove the unnecessary cast. | |
514 return handler( | |
515 implZone, _parentDelegate(implZone), zone, f, arg1, arg2) | |
516 as Object/*=R*/; | |
517 } | |
518 | |
519 ZoneCallback/*<R>*/ registerCallback/*<R>*/(Zone zone, /*=R*/ f()) { | |
520 var implementation = _delegationTarget._registerCallback; | |
521 _Zone implZone = implementation.zone; | |
522 RegisterCallbackHandler handler = implementation.function; | |
523 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
524 // supported. Remove the unnecessary cast. | |
525 return handler(implZone, _parentDelegate(implZone), zone, f) | |
526 as Object/*=ZoneCallback<R>*/; | |
527 } | |
528 | |
529 ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/( | |
530 Zone zone, /*=R*/ f(/*=T*/ arg)) { | |
531 var implementation = _delegationTarget._registerUnaryCallback; | |
532 _Zone implZone = implementation.zone; | |
533 RegisterUnaryCallbackHandler handler = implementation.function; | |
534 // TODO(floitsch): make this a generic method call on '<R, T>' once it's | |
535 // supported. Remove the unnecessary cast. | |
536 return handler(implZone, _parentDelegate(implZone), zone, f) | |
537 as Object/*=ZoneUnaryCallback<R, T>*/; | |
538 } | |
539 | |
540 ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/( | |
541 Zone zone, /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) { | |
542 var implementation = _delegationTarget._registerBinaryCallback; | |
543 _Zone implZone = implementation.zone; | |
544 RegisterBinaryCallbackHandler handler = implementation.function; | |
545 // TODO(floitsch): make this a generic method call on '<R, T1, T2>' once | |
546 // it's supported. Remove the unnecessary cast. | |
547 return handler(implZone, _parentDelegate(implZone), zone, f) | |
548 as Object/*=ZoneBinaryCallback<R, T1, T2>*/; | |
549 } | |
550 | |
551 AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace) { | |
552 var implementation = _delegationTarget._errorCallback; | |
553 _Zone implZone = implementation.zone; | |
554 if (identical(implZone, _ROOT_ZONE)) return null; | |
555 ErrorCallbackHandler handler = implementation.function; | |
556 return handler(implZone, _parentDelegate(implZone), zone, | |
557 error, stackTrace); | |
558 } | |
559 | |
560 void scheduleMicrotask(Zone zone, f()) { | |
561 var implementation = _delegationTarget._scheduleMicrotask; | |
562 _Zone implZone = implementation.zone; | |
563 ScheduleMicrotaskHandler handler = implementation.function; | |
564 handler(implZone, _parentDelegate(implZone), zone, f); | |
565 } | |
566 | |
567 Timer createTimer(Zone zone, Duration duration, void f()) { | |
568 var implementation = _delegationTarget._createTimer; | |
569 _Zone implZone = implementation.zone; | |
570 CreateTimerHandler handler = implementation.function; | |
571 return handler(implZone, _parentDelegate(implZone), zone, duration, f); | |
572 } | |
573 | |
574 Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) { | |
575 var implementation = _delegationTarget._createPeriodicTimer; | |
576 _Zone implZone = implementation.zone; | |
577 CreatePeriodicTimerHandler handler = implementation.function; | |
578 return handler(implZone, _parentDelegate(implZone), zone, period, f); | |
579 } | |
580 | |
581 void print(Zone zone, String line) { | |
582 var implementation = _delegationTarget._print; | |
583 _Zone implZone = implementation.zone; | |
584 PrintHandler handler = implementation.function; | |
585 handler(implZone, _parentDelegate(implZone), zone, line); | |
586 } | |
587 | |
588 Zone fork(Zone zone, ZoneSpecification specification, | |
589 Map zoneValues) { | |
590 var implementation = _delegationTarget._fork; | |
591 _Zone implZone = implementation.zone; | |
592 ForkHandler handler = implementation.function; | |
593 return handler( | |
594 implZone, _parentDelegate(implZone), zone, specification, zoneValues); | |
595 } | |
596 } | |
597 | |
598 | |
599 /** | |
600 * Base class for Zone implementations. | |
601 */ | |
602 abstract class _Zone implements Zone { | |
603 const _Zone(); | |
604 | |
605 _ZoneFunction<RunHandler> get _run; | |
606 _ZoneFunction<RunUnaryHandler> get _runUnary; | |
607 _ZoneFunction<RunBinaryHandler> get _runBinary; | |
608 _ZoneFunction<RegisterCallbackHandler> get _registerCallback; | |
609 _ZoneFunction<RegisterUnaryCallbackHandler> get _registerUnaryCallback; | |
610 _ZoneFunction<RegisterBinaryCallbackHandler> get _registerBinaryCallback; | |
611 _ZoneFunction<ErrorCallbackHandler> get _errorCallback; | |
612 _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask; | |
613 _ZoneFunction<CreateTimerHandler> get _createTimer; | |
614 _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer; | |
615 _ZoneFunction<PrintHandler> get _print; | |
616 _ZoneFunction<ForkHandler> get _fork; | |
617 _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError; | |
618 _Zone get parent; | |
619 ZoneDelegate get _delegate; | |
620 Map get _map; | |
621 | |
622 bool inSameErrorZone(Zone otherZone) { | |
623 return identical(this, otherZone) || | |
624 identical(errorZone, otherZone.errorZone); | |
625 } | |
626 } | |
627 | |
628 class _CustomZone extends _Zone { | |
629 // The actual zone and implementation of each of these | |
630 // inheritable zone functions. | |
631 _ZoneFunction<RunHandler> _run; | |
632 _ZoneFunction<RunUnaryHandler> _runUnary; | |
633 _ZoneFunction<RunBinaryHandler> _runBinary; | |
634 _ZoneFunction<RegisterCallbackHandler> _registerCallback; | |
635 _ZoneFunction<RegisterUnaryCallbackHandler> _registerUnaryCallback; | |
636 _ZoneFunction<RegisterBinaryCallbackHandler> _registerBinaryCallback; | |
637 _ZoneFunction<ErrorCallbackHandler> _errorCallback; | |
638 _ZoneFunction<ScheduleMicrotaskHandler> _scheduleMicrotask; | |
639 _ZoneFunction<CreateTimerHandler> _createTimer; | |
640 _ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer; | |
641 _ZoneFunction<PrintHandler> _print; | |
642 _ZoneFunction<ForkHandler> _fork; | |
643 _ZoneFunction<HandleUncaughtErrorHandler> _handleUncaughtError; | |
644 | |
645 // A cached delegate to this zone. | |
646 ZoneDelegate _delegateCache; | |
647 | |
648 /// The parent zone. | |
649 final _Zone parent; | |
650 | |
651 /// The zone's scoped value declaration map. | |
652 /// | |
653 /// This is always a [HashMap]. | |
654 final Map _map; | |
655 | |
656 ZoneDelegate get _delegate { | |
657 if (_delegateCache != null) return _delegateCache; | |
658 _delegateCache = new _ZoneDelegate(this); | |
659 return _delegateCache; | |
660 } | |
661 | |
662 _CustomZone(this.parent, ZoneSpecification specification, this._map) { | |
663 // The root zone will have implementations of all parts of the | |
664 // specification, so it will never try to access the (null) parent. | |
665 // All other zones have a non-null parent. | |
666 _run = (specification.run != null) | |
667 ? new _ZoneFunction<RunHandler>(this, specification.run) | |
668 : parent._run; | |
669 _runUnary = (specification.runUnary != null) | |
670 ? new _ZoneFunction<RunUnaryHandler>(this, specification.runUnary) | |
671 : parent._runUnary; | |
672 _runBinary = (specification.runBinary != null) | |
673 ? new _ZoneFunction<RunBinaryHandler>(this, specification.runBinary) | |
674 : parent._runBinary; | |
675 _registerCallback = (specification.registerCallback != null) | |
676 ? new _ZoneFunction<RegisterCallbackHandler>( | |
677 this, specification.registerCallback) | |
678 : parent._registerCallback; | |
679 _registerUnaryCallback = (specification.registerUnaryCallback != null) | |
680 ? new _ZoneFunction<RegisterUnaryCallbackHandler>( | |
681 this, specification.registerUnaryCallback) | |
682 : parent._registerUnaryCallback; | |
683 _registerBinaryCallback = (specification.registerBinaryCallback != null) | |
684 ? new _ZoneFunction<RegisterBinaryCallbackHandler>( | |
685 this, specification.registerBinaryCallback) | |
686 : parent._registerBinaryCallback; | |
687 _errorCallback = (specification.errorCallback != null) | |
688 ? new _ZoneFunction<ErrorCallbackHandler>( | |
689 this, specification.errorCallback) | |
690 : parent._errorCallback; | |
691 _scheduleMicrotask = (specification.scheduleMicrotask != null) | |
692 ? new _ZoneFunction<ScheduleMicrotaskHandler>( | |
693 this, specification.scheduleMicrotask) | |
694 : parent._scheduleMicrotask; | |
695 _createTimer = (specification.createTimer != null) | |
696 ? new _ZoneFunction<CreateTimerHandler>(this, specification.createTimer) | |
697 : parent._createTimer; | |
698 _createPeriodicTimer = (specification.createPeriodicTimer != null) | |
699 ? new _ZoneFunction<CreatePeriodicTimerHandler>( | |
700 this, specification.createPeriodicTimer) | |
701 : parent._createPeriodicTimer; | |
702 _print = (specification.print != null) | |
703 ? new _ZoneFunction<PrintHandler>(this, specification.print) | |
704 : parent._print; | |
705 _fork = (specification.fork != null) | |
706 ? new _ZoneFunction<ForkHandler>(this, specification.fork) | |
707 : parent._fork; | |
708 _handleUncaughtError = (specification.handleUncaughtError != null) | |
709 ? new _ZoneFunction<HandleUncaughtErrorHandler>( | |
710 this, specification.handleUncaughtError) | |
711 : parent._handleUncaughtError; | |
712 } | |
713 | |
714 /** | |
715 * The closest error-handling zone. | |
716 * | |
717 * Returns `this` if `this` has an error-handler. Otherwise returns the | |
718 * parent's error-zone. | |
719 */ | |
720 Zone get errorZone => _handleUncaughtError.zone; | |
721 | |
722 /*=R*/ runGuarded/*<R>*/(/*=R*/ f()) { | |
723 try { | |
724 return run(f); | |
725 } catch (e, s) { | |
726 return handleUncaughtError(e, s); | |
727 } | |
728 } | |
729 | |
730 /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
731 try { | |
732 return runUnary(f, arg); | |
733 } catch (e, s) { | |
734 return handleUncaughtError(e, s); | |
735 } | |
736 } | |
737 | |
738 /*=R*/ runBinaryGuarded/*<R, T1, T2>*/( | |
739 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
740 try { | |
741 return runBinary(f, arg1, arg2); | |
742 } catch (e, s) { | |
743 return handleUncaughtError(e, s); | |
744 } | |
745 } | |
746 | |
747 ZoneCallback/*<R>*/ bindCallback/*<R>*/( | |
748 /*=R*/ f(), { bool runGuarded: true }) { | |
749 var registered = registerCallback(f); | |
750 if (runGuarded) { | |
751 return () => this.runGuarded(registered); | |
752 } else { | |
753 return () => this.run(registered); | |
754 } | |
755 } | |
756 | |
757 ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/( | |
758 /*=R*/ f(/*=T*/ arg), { bool runGuarded: true }) { | |
759 var registered = registerUnaryCallback(f); | |
760 if (runGuarded) { | |
761 return (arg) => this.runUnaryGuarded(registered, arg); | |
762 } else { | |
763 return (arg) => this.runUnary(registered, arg); | |
764 } | |
765 } | |
766 | |
767 ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/( | |
768 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true }) { | |
769 var registered = registerBinaryCallback(f); | |
770 if (runGuarded) { | |
771 return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2); | |
772 } else { | |
773 return (arg1, arg2) => this.runBinary(registered, arg1, arg2); | |
774 } | |
775 } | |
776 | |
777 operator [](Object key) { | |
778 var result = _map[key]; | |
779 if (result != null || _map.containsKey(key)) return result; | |
780 // If we are not the root zone, look up in the parent zone. | |
781 if (parent != null) { | |
782 // We do not optimize for repeatedly looking up a key which isn't | |
783 // there. That would require storing the key and keeping it alive. | |
784 // Copying the key/value from the parent does not keep any new values | |
785 // alive. | |
786 var value = parent[key]; | |
787 if (value != null) { | |
788 _map[key] = value; | |
789 } | |
790 return value; | |
791 } | |
792 assert(this == _ROOT_ZONE); | |
793 return null; | |
794 } | |
795 | |
796 // Methods that can be customized by the zone specification. | |
797 | |
798 /*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace) { | |
799 var implementation = this._handleUncaughtError; | |
800 assert(implementation != null); | |
801 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
802 HandleUncaughtErrorHandler handler = implementation.function; | |
803 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
804 // supported. Remove the unnecessary cast. | |
805 return handler( | |
806 implementation.zone, parentDelegate, this, error, stackTrace) | |
807 as Object/*=R*/; | |
808 } | |
809 | |
810 Zone fork({ZoneSpecification specification, Map zoneValues}) { | |
811 var implementation = this._fork; | |
812 assert(implementation != null); | |
813 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
814 ForkHandler handler = implementation.function; | |
815 return handler(implementation.zone, parentDelegate, this, | |
816 specification, zoneValues); | |
817 } | |
818 | |
819 /*=R*/ run/*<R>*/(/*=R*/ f()) { | |
820 var implementation = this._run; | |
821 assert(implementation != null); | |
822 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
823 RunHandler handler = implementation.function; | |
824 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
825 // supported. Remove the unnecessary cast. | |
826 return handler(implementation.zone, parentDelegate, this, f) | |
827 as Object/*=R*/; | |
828 } | |
829 | |
830 /*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
831 var implementation = this._runUnary; | |
832 assert(implementation != null); | |
833 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
834 RunUnaryHandler handler = implementation.function; | |
835 // TODO(floitsch): make this a generic method call on '<R, T>' once it's | |
836 // supported. Remove the unnecessary cast. | |
837 return handler(implementation.zone, parentDelegate, this, f, arg) | |
838 as Object/*=R*/; | |
839 } | |
840 | |
841 /*=R*/ runBinary/*<R, T1, T2>*/( | |
842 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
843 var implementation = this._runBinary; | |
844 assert(implementation != null); | |
845 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
846 RunBinaryHandler handler = implementation.function; | |
847 // TODO(floitsch): make this a generic method call on '<R, T1, T2>' once | |
848 // it's supported. Remove the unnecessary cast. | |
849 return handler( | |
850 implementation.zone, parentDelegate, this, f, arg1, arg2) | |
851 as Object/*=R*/; | |
852 } | |
853 | |
854 ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback()) { | |
855 var implementation = this._registerCallback; | |
856 assert(implementation != null); | |
857 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
858 RegisterCallbackHandler handler = implementation.function; | |
859 // TODO(floitsch): make this a generic method call on '<R>' once it's | |
860 // supported. Remove the unnecessary cast. | |
861 return handler(implementation.zone, parentDelegate, this, callback) | |
862 as Object/*=ZoneCallback<R>*/; | |
863 } | |
864 | |
865 ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/( | |
866 /*=R*/ callback(/*=T*/ arg)) { | |
867 var implementation = this._registerUnaryCallback; | |
868 assert(implementation != null); | |
869 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
870 RegisterUnaryCallbackHandler handler = implementation.function; | |
871 // TODO(floitsch): make this a generic method call on '<R, T>' once it's | |
872 // supported. Remove the unnecessary cast. | |
873 return handler(implementation.zone, parentDelegate, this, callback) | |
874 as Object/*=ZoneUnaryCallback<R, T>*/; | |
875 } | |
876 | |
877 ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/( | |
878 /*=R*/ callback(/*=T1*/ arg1, /*=T2*/ arg2)) { | |
879 var implementation = this._registerBinaryCallback; | |
880 assert(implementation != null); | |
881 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
882 RegisterBinaryCallbackHandler handler = implementation.function; | |
883 // TODO(floitsch): make this a generic method call on '<R, T1, T2>' once | |
884 // it's supported. Remove the unnecessary cast. | |
885 return handler(implementation.zone, parentDelegate, this, callback) | |
886 as Object/*=ZoneBinaryCallback<R, T1, T2>*/; | |
887 } | |
888 | |
889 AsyncError errorCallback(Object error, StackTrace stackTrace) { | |
890 var implementation = this._errorCallback; | |
891 assert(implementation != null); | |
892 final Zone implementationZone = implementation.zone; | |
893 if (identical(implementationZone, _ROOT_ZONE)) return null; | |
894 final ZoneDelegate parentDelegate = _parentDelegate(implementationZone); | |
895 ErrorCallbackHandler handler = implementation.function; | |
896 return handler( | |
897 implementationZone, parentDelegate, this, error, stackTrace); | |
898 } | |
899 | |
900 void scheduleMicrotask(void f()) { | |
901 var implementation = this._scheduleMicrotask; | |
902 assert(implementation != null); | |
903 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
904 ScheduleMicrotaskHandler handler = implementation.function; | |
905 return handler(implementation.zone, parentDelegate, this, f); | |
906 } | |
907 | |
908 Timer createTimer(Duration duration, void f()) { | |
909 var implementation = this._createTimer; | |
910 assert(implementation != null); | |
911 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
912 CreateTimerHandler handler = implementation.function; | |
913 return handler(implementation.zone, parentDelegate, this, duration, f); | |
914 } | |
915 | |
916 Timer createPeriodicTimer(Duration duration, void f(Timer timer)) { | |
917 var implementation = this._createPeriodicTimer; | |
918 assert(implementation != null); | |
919 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
920 CreatePeriodicTimerHandler handler = implementation.function; | |
921 return handler( | |
922 implementation.zone, parentDelegate, this, duration, f); | |
923 } | |
924 | |
925 void print(String line) { | |
926 var implementation = this._print; | |
927 assert(implementation != null); | |
928 ZoneDelegate parentDelegate = _parentDelegate(implementation.zone); | |
929 PrintHandler handler = implementation.function; | |
930 return handler(implementation.zone, parentDelegate, this, line); | |
931 } | |
932 } | |
933 | |
934 /*=R*/ _rootHandleUncaughtError/*<R>*/( | |
935 Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) { | |
936 _schedulePriorityAsyncCallback(() { | |
937 if (error == null) error = new NullThrownError(); | |
938 if (stackTrace == null) throw error; | |
939 _rethrow(error, stackTrace); | |
940 }); | |
941 } | |
942 | |
943 external void _rethrow(Object error, StackTrace stackTrace); | |
944 | |
945 /*=R*/ _rootRun/*<R>*/(Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f()) { | |
946 if (Zone._current == zone) return f(); | |
947 | |
948 Zone old = Zone._enter(zone); | |
949 try { | |
950 return f(); | |
951 } finally { | |
952 Zone._leave(old); | |
953 } | |
954 } | |
955 | |
956 /*=R*/ _rootRunUnary/*<R, T>*/(Zone self, ZoneDelegate parent, Zone zone, | |
957 /*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
958 if (Zone._current == zone) return f(arg); | |
959 | |
960 Zone old = Zone._enter(zone); | |
961 try { | |
962 return f(arg); | |
963 } finally { | |
964 Zone._leave(old); | |
965 } | |
966 } | |
967 | |
968 /*=R*/ _rootRunBinary/*<R, T1, T2>*/(Zone self, ZoneDelegate parent, Zone zone, | |
969 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
970 if (Zone._current == zone) return f(arg1, arg2); | |
971 | |
972 Zone old = Zone._enter(zone); | |
973 try { | |
974 return f(arg1, arg2); | |
975 } finally { | |
976 Zone._leave(old); | |
977 } | |
978 } | |
979 | |
980 ZoneCallback/*<R>*/ _rootRegisterCallback/*<R>*/( | |
981 Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f()) { | |
982 return f; | |
983 } | |
984 | |
985 ZoneUnaryCallback/*<R, T>*/ _rootRegisterUnaryCallback/*<R, T>*/( | |
986 Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f(/*=T*/ arg)) { | |
987 return f; | |
988 } | |
989 | |
990 ZoneBinaryCallback/*<R, T1, T2>*/ _rootRegisterBinaryCallback/*<R, T1, T2>*/( | |
991 Zone self, ZoneDelegate parent, Zone zone, | |
992 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) { | |
993 return f; | |
994 } | |
995 | |
996 AsyncError _rootErrorCallback(Zone self, ZoneDelegate parent, Zone zone, | |
997 Object error, StackTrace stackTrace) => null; | |
998 | |
999 void _rootScheduleMicrotask(Zone self, ZoneDelegate parent, Zone zone, f()) { | |
1000 if (!identical(_ROOT_ZONE, zone)) { | |
1001 bool hasErrorHandler = !_ROOT_ZONE.inSameErrorZone(zone); | |
1002 f = zone.bindCallback(f, runGuarded: hasErrorHandler); | |
1003 // Use root zone as event zone if the function is already bound. | |
1004 zone = _ROOT_ZONE; | |
1005 } | |
1006 _scheduleAsyncCallback(f); | |
1007 } | |
1008 | |
1009 Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone, | |
1010 Duration duration, void callback()) { | |
1011 if (!identical(_ROOT_ZONE, zone)) { | |
1012 callback = zone.bindCallback(callback); | |
1013 } | |
1014 return Timer._createTimer(duration, callback); | |
1015 } | |
1016 | |
1017 Timer _rootCreatePeriodicTimer( | |
1018 Zone self, ZoneDelegate parent, Zone zone, | |
1019 Duration duration, void callback(Timer timer)) { | |
1020 if (!identical(_ROOT_ZONE, zone)) { | |
1021 // TODO(floitsch): the return type should be 'void'. | |
1022 callback = zone.bindUnaryCallback/*<dynamic, Timer>*/(callback); | |
1023 } | |
1024 return Timer._createPeriodicTimer(duration, callback); | |
1025 } | |
1026 | |
1027 void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) { | |
1028 printToConsole(line); | |
1029 } | |
1030 | |
1031 void _printToZone(String line) { | |
1032 Zone.current.print(line); | |
1033 } | |
1034 | |
1035 Zone _rootFork(Zone self, ZoneDelegate parent, Zone zone, | |
1036 ZoneSpecification specification, | |
1037 Map zoneValues) { | |
1038 // TODO(floitsch): it would be nice if we could get rid of this hack. | |
1039 // Change the static zoneOrDirectPrint function to go through zones | |
1040 // from now on. | |
1041 printToZone = _printToZone; | |
1042 | |
1043 if (specification == null) { | |
1044 specification = const ZoneSpecification(); | |
1045 } else if (specification is! _ZoneSpecification) { | |
1046 throw new ArgumentError("ZoneSpecifications must be instantiated" | |
1047 " with the provided constructor."); | |
1048 } | |
1049 Map valueMap; | |
1050 if (zoneValues == null) { | |
1051 if (zone is _Zone) { | |
1052 valueMap = zone._map; | |
1053 } else { | |
1054 valueMap = new HashMap(); | |
1055 } | |
1056 } else { | |
1057 valueMap = new HashMap.from(zoneValues); | |
1058 } | |
1059 return new _CustomZone(zone, specification, valueMap); | |
1060 } | |
1061 | |
1062 class _RootZone extends _Zone { | |
1063 const _RootZone(); | |
1064 | |
1065 _ZoneFunction<RunHandler> get _run => | |
1066 const _ZoneFunction<RunHandler>(_ROOT_ZONE, _rootRun); | |
1067 _ZoneFunction<RunUnaryHandler> get _runUnary => | |
1068 const _ZoneFunction<RunUnaryHandler>(_ROOT_ZONE, _rootRunUnary); | |
1069 _ZoneFunction<RunBinaryHandler> get _runBinary => | |
1070 const _ZoneFunction<RunBinaryHandler>(_ROOT_ZONE, _rootRunBinary); | |
1071 _ZoneFunction<RegisterCallbackHandler> get _registerCallback => | |
1072 const _ZoneFunction<RegisterCallbackHandler>( | |
1073 _ROOT_ZONE, _rootRegisterCallback); | |
1074 _ZoneFunction<RegisterUnaryCallbackHandler> get _registerUnaryCallback => | |
1075 const _ZoneFunction<RegisterUnaryCallbackHandler>( | |
1076 _ROOT_ZONE, _rootRegisterUnaryCallback); | |
1077 _ZoneFunction<RegisterBinaryCallbackHandler> get _registerBinaryCallback => | |
1078 const _ZoneFunction<RegisterBinaryCallbackHandler>( | |
1079 _ROOT_ZONE, _rootRegisterBinaryCallback); | |
1080 _ZoneFunction<ErrorCallbackHandler> get _errorCallback => | |
1081 const _ZoneFunction<ErrorCallbackHandler>(_ROOT_ZONE, _rootErrorCallback); | |
1082 _ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask => | |
1083 const _ZoneFunction<ScheduleMicrotaskHandler>( | |
1084 _ROOT_ZONE, _rootScheduleMicrotask); | |
1085 _ZoneFunction<CreateTimerHandler> get _createTimer => | |
1086 const _ZoneFunction<CreateTimerHandler>(_ROOT_ZONE, _rootCreateTimer); | |
1087 _ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer => | |
1088 const _ZoneFunction<CreatePeriodicTimerHandler>(_ROOT_ZONE, _rootCreatePer
iodicTimer); | |
1089 _ZoneFunction<PrintHandler> get _print => | |
1090 const _ZoneFunction<PrintHandler>(_ROOT_ZONE, _rootPrint); | |
1091 _ZoneFunction<ForkHandler> get _fork => | |
1092 const _ZoneFunction<ForkHandler>(_ROOT_ZONE, _rootFork); | |
1093 _ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError => | |
1094 const _ZoneFunction<HandleUncaughtErrorHandler>( | |
1095 _ROOT_ZONE, _rootHandleUncaughtError); | |
1096 | |
1097 // The parent zone. | |
1098 _Zone get parent => null; | |
1099 | |
1100 /// The zone's scoped value declaration map. | |
1101 /// | |
1102 /// This is always a [HashMap]. | |
1103 Map get _map => _rootMap; | |
1104 | |
1105 static Map _rootMap = new HashMap(); | |
1106 | |
1107 static ZoneDelegate _rootDelegate; | |
1108 | |
1109 ZoneDelegate get _delegate { | |
1110 if (_rootDelegate != null) return _rootDelegate; | |
1111 return _rootDelegate = new _ZoneDelegate(this); | |
1112 } | |
1113 | |
1114 /** | |
1115 * The closest error-handling zone. | |
1116 * | |
1117 * Returns `this` if `this` has an error-handler. Otherwise returns the | |
1118 * parent's error-zone. | |
1119 */ | |
1120 Zone get errorZone => this; | |
1121 | |
1122 // Zone interface. | |
1123 | |
1124 /*=R*/ runGuarded/*<R>*/(/*=R*/ f()) { | |
1125 try { | |
1126 if (identical(_ROOT_ZONE, Zone._current)) { | |
1127 return f(); | |
1128 } | |
1129 return _rootRun/*<R>*/(null, null, this, f); | |
1130 } catch (e, s) { | |
1131 return handleUncaughtError/*<R>*/(e, s); | |
1132 } | |
1133 } | |
1134 | |
1135 /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
1136 try { | |
1137 if (identical(_ROOT_ZONE, Zone._current)) { | |
1138 return f(arg); | |
1139 } | |
1140 return _rootRunUnary/*<R, T>*/(null, null, this, f, arg); | |
1141 } catch (e, s) { | |
1142 return handleUncaughtError/*<R>*/(e, s); | |
1143 } | |
1144 } | |
1145 | |
1146 /*=R*/ runBinaryGuarded/*<R, T1, T2>*/( | |
1147 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
1148 try { | |
1149 if (identical(_ROOT_ZONE, Zone._current)) { | |
1150 return f(arg1, arg2); | |
1151 } | |
1152 return _rootRunBinary/*<R, T1, T2>*/(null, null, this, f, arg1, arg2); | |
1153 } catch (e, s) { | |
1154 return handleUncaughtError/*<R>*/(e, s); | |
1155 } | |
1156 } | |
1157 | |
1158 ZoneCallback/*<R>*/ bindCallback/*<R>*/( | |
1159 /*=R*/ f(), { bool runGuarded: true }) { | |
1160 if (runGuarded) { | |
1161 return () => this.runGuarded/*<R>*/(f); | |
1162 } else { | |
1163 return () => this.run/*<R>*/(f); | |
1164 } | |
1165 } | |
1166 | |
1167 ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/( | |
1168 /*=R*/ f(/*=T*/ arg), { bool runGuarded: true }) { | |
1169 if (runGuarded) { | |
1170 return (arg) => this.runUnaryGuarded/*<R, T>*/(f, arg); | |
1171 } else { | |
1172 return (arg) => this.runUnary/*<R, T>*/(f, arg); | |
1173 } | |
1174 } | |
1175 | |
1176 ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/( | |
1177 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true }) { | |
1178 if (runGuarded) { | |
1179 return (arg1, arg2) => | |
1180 this.runBinaryGuarded/*<R, T1, T2>*/(f, arg1, arg2); | |
1181 } else { | |
1182 return (arg1, arg2) => this.runBinary/*<R, T1, T2>*/(f, arg1, arg2); | |
1183 } | |
1184 } | |
1185 | |
1186 operator [](Object key) => null; | |
1187 | |
1188 // Methods that can be customized by the zone specification. | |
1189 | |
1190 /*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace) { | |
1191 return _rootHandleUncaughtError(null, null, this, error, stackTrace); | |
1192 } | |
1193 | |
1194 Zone fork({ZoneSpecification specification, Map zoneValues}) { | |
1195 return _rootFork(null, null, this, specification, zoneValues); | |
1196 } | |
1197 | |
1198 /*=R*/ run/*<R>*/(/*=R*/ f()) { | |
1199 if (identical(Zone._current, _ROOT_ZONE)) return f(); | |
1200 return _rootRun(null, null, this, f); | |
1201 } | |
1202 | |
1203 /*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) { | |
1204 if (identical(Zone._current, _ROOT_ZONE)) return f(arg); | |
1205 return _rootRunUnary(null, null, this, f, arg); | |
1206 } | |
1207 | |
1208 /*=R*/ runBinary/*<R, T1, T2>*/( | |
1209 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) { | |
1210 if (identical(Zone._current, _ROOT_ZONE)) return f(arg1, arg2); | |
1211 return _rootRunBinary(null, null, this, f, arg1, arg2); | |
1212 } | |
1213 | |
1214 ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ f()) => f; | |
1215 | |
1216 ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/( | |
1217 /*=R*/ f(/*=T*/ arg)) => f; | |
1218 | |
1219 ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/( | |
1220 /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) => f; | |
1221 | |
1222 AsyncError errorCallback(Object error, StackTrace stackTrace) => null; | |
1223 | |
1224 void scheduleMicrotask(void f()) { | |
1225 _rootScheduleMicrotask(null, null, this, f); | |
1226 } | |
1227 | |
1228 Timer createTimer(Duration duration, void f()) { | |
1229 return Timer._createTimer(duration, f); | |
1230 } | |
1231 | |
1232 Timer createPeriodicTimer(Duration duration, void f(Timer timer)) { | |
1233 return Timer._createPeriodicTimer(duration, f); | |
1234 } | |
1235 | |
1236 void print(String line) { | |
1237 printToConsole(line); | |
1238 } | |
1239 } | |
1240 | |
1241 const _ROOT_ZONE = const _RootZone(); | |
1242 | |
1243 /** | |
1244 * Runs [body] in its own zone. | |
1245 * | |
1246 * If [onError] is non-null the zone is considered an error zone. All uncaught | |
1247 * errors, synchronous or asynchronous, in the zone are caught and handled | |
1248 * by the callback. | |
1249 * | |
1250 * Errors may never cross error-zone boundaries. This is intuitive for leaving | |
1251 * a zone, but it also applies for errors that would enter an error-zone. | |
1252 * Errors that try to cross error-zone boundaries are considered uncaught. | |
1253 * | |
1254 * var future = new Future.value(499); | |
1255 * runZoned(() { | |
1256 * future = future.then((_) { throw "error in first error-zone"; }); | |
1257 * runZoned(() { | |
1258 * future = future.catchError((e) { print("Never reached!"); }); | |
1259 * }, onError: (e) { print("unused error handler"); }); | |
1260 * }, onError: (e) { print("catches error of first error-zone."); }); | |
1261 * | |
1262 * Example: | |
1263 * | |
1264 * runZoned(() { | |
1265 * new Future(() { throw "asynchronous error"; }); | |
1266 * }, onError: print); // Will print "asynchronous error". | |
1267 */ | |
1268 /*=R*/ runZoned/*<R>*/(/*=R*/ body(), | |
1269 { Map zoneValues, | |
1270 ZoneSpecification zoneSpecification, | |
1271 Function onError }) { | |
1272 HandleUncaughtErrorHandler errorHandler; | |
1273 if (onError != null) { | |
1274 errorHandler = (Zone self, ZoneDelegate parent, Zone zone, | |
1275 error, StackTrace stackTrace) { | |
1276 try { | |
1277 // Change this is check back to | |
1278 // onError is ZoneBinaryCallback<dynamic/*=R*/, dynamic, StackTrace> | |
1279 // once is checks for that type are handled correctly. | |
1280 if (onError is ZoneBinaryCallback<dynamic, dynamic, StackTrace>) { | |
1281 return self.parent.runBinary(onError, error, stackTrace) as Object/*=R
*/; | |
1282 } | |
1283 return self.parent.runUnary(onError, error); | |
1284 } catch(e, s) { | |
1285 if (identical(e, error)) { | |
1286 return parent.handleUncaughtError(zone, error, stackTrace); | |
1287 } else { | |
1288 return parent.handleUncaughtError(zone, e, s); | |
1289 } | |
1290 } | |
1291 }; | |
1292 } | |
1293 if (zoneSpecification == null) { | |
1294 zoneSpecification = | |
1295 new ZoneSpecification(handleUncaughtError: errorHandler); | |
1296 } else if (errorHandler != null) { | |
1297 zoneSpecification = | |
1298 new ZoneSpecification.from(zoneSpecification, | |
1299 handleUncaughtError: errorHandler); | |
1300 } | |
1301 Zone zone = Zone.current.fork(specification: zoneSpecification, | |
1302 zoneValues: zoneValues); | |
1303 if (onError != null) { | |
1304 return zone.runGuarded(body); | |
1305 } else { | |
1306 return zone.run(body); | |
1307 } | |
1308 } | |
OLD | NEW |