blob: e0c3e4bdac4be043465dd6760a85c226d3035e8d [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.async;
typedef R ZoneCallback<R>();
typedef R ZoneUnaryCallback<R, T>(T arg);
typedef R ZoneBinaryCallback<R, T1, T2>(T1 arg1, T2 arg2);
/// *Experimental*. Might disappear without warning.
typedef T TaskCreate<T, S extends TaskSpecification>(
S specification, Zone zone);
/// *Experimental*. Might disappear without warning.
typedef void TaskRun<T, A>(T task, A arg);
// TODO(floitsch): we are abusing generic typedefs as typedefs for generic
// functions.
/*ABUSE*/
typedef R HandleUncaughtErrorHandler<R>(
Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace);
/*ABUSE*/
typedef R RunHandler<R>(Zone self, ZoneDelegate parent, Zone zone, R f());
/*ABUSE*/
typedef R RunUnaryHandler<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R f(T arg), T arg);
/*ABUSE*/
typedef R RunBinaryHandler<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone,
R f(T1 arg1, T2 arg2), T1 arg1, T2 arg2);
/*ABUSE*/
typedef ZoneCallback<R> RegisterCallbackHandler<R>(
Zone self, ZoneDelegate parent, Zone zone, R f());
/*ABUSE*/
typedef ZoneUnaryCallback<R, T> RegisterUnaryCallbackHandler<R, T>(
Zone self, ZoneDelegate parent, Zone zone, R f(T arg));
/*ABUSE*/
typedef ZoneBinaryCallback<R, T1, T2> RegisterBinaryCallbackHandler<R, T1, T2>(
Zone self, ZoneDelegate parent, Zone zone, R f(T1 arg1, T2 arg2));
typedef AsyncError ErrorCallbackHandler(Zone self, ZoneDelegate parent,
Zone zone, Object error, StackTrace stackTrace);
/// *Experimental*. Might disappear without warning.
/*ABUSE*/
typedef T CreateTaskHandler<T, S extends TaskSpecification>(
Zone self, ZoneDelegate parent, Zone zone,
TaskCreate<T, S> create, S taskSpecification);
/// *Experimental*. Might disappear without warning.
/*ABUSE*/
typedef void RunTaskHandler<T, A>(Zone self, ZoneDelegate parent, Zone zone,
TaskRun<T, A> run, T task, A arg);
typedef void ScheduleMicrotaskHandler(
Zone self, ZoneDelegate parent, Zone zone, void f());
typedef void PrintHandler(
Zone self, ZoneDelegate parent, Zone zone, String line);
typedef Zone ForkHandler(Zone self, ZoneDelegate parent, Zone zone,
ZoneSpecification specification,
Map zoneValues);
// The following typedef declarations are used by functionality which
// will be removed and replaced by tasksif the task experiment is successful.
typedef Timer CreateTimerHandler(
Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f());
typedef Timer CreatePeriodicTimerHandler(
Zone self, ZoneDelegate parent, Zone zone,
Duration period, void f(Timer timer));
/** Pair of error and stack trace. Returned by [Zone.errorCallback]. */
class AsyncError implements Error {
final Object error;
final StackTrace stackTrace;
AsyncError(this.error, this.stackTrace);
String toString() => '$error';
}
/**
* A task specification contains the necessary information to create a task.
*
* See [Zone.createTask] for how a specification is used to create a task.
*
* Task specifications should be public and it should be possible to create
* new instances as a user. That is, custom zones should be able to replace
* an existing specification with a modified one.
*
* *Experimental*. This class might disappear without warning.
*/
abstract class TaskSpecification {
/**
* Description of the task.
*
* This string is unused by the root-zone, but might be used for debugging,
* and testing. As such, it should be relatively unique in its category.
*
* As a general guideline we recommend: "package-name.library.action".
*/
String get name;
/**
* Whether the scheduled task triggers at most once.
*
* If the task is not a one-shot task, it may need to be canceled to prevent
* further iterations of the task.
*/
bool get isOneShot;
}
class _ZoneFunction<T extends Function> {
final _Zone zone;
final T function;
const _ZoneFunction(this.zone, this.function);
}
/**
* This class provides the specification for a forked zone.
*
* When forking a new zone (see [Zone.fork]) one can override the default
* behavior of the zone by providing callbacks. These callbacks must be
* given in an instance of this class.
*
* Handlers have the same signature as the same-named methods on [Zone] but
* receive three additional arguments:
*
* 1. the zone the handlers are attached to (the "self" zone).
* 2. a [ZoneDelegate] to the parent zone.
* 3. the zone that first received the request (before the request was
* bubbled up).
*
* Handlers can either stop propagation the request (by simply not calling the
* parent handler), or forward to the parent zone, potentially modifying the
* arguments on the way.
*/
abstract class ZoneSpecification {
/**
* Creates a specification with the provided handlers.
*
* The task-related parameters ([createTask] and [runTask]) are experimental
* and might be removed without warning.
*/
const factory ZoneSpecification({
HandleUncaughtErrorHandler handleUncaughtError,
RunHandler run,
RunUnaryHandler runUnary,
RunBinaryHandler runBinary,
RegisterCallbackHandler registerCallback,
RegisterUnaryCallbackHandler registerUnaryCallback,
RegisterBinaryCallbackHandler registerBinaryCallback,
ErrorCallbackHandler errorCallback,
ScheduleMicrotaskHandler scheduleMicrotask,
CreateTaskHandler createTask,
RunTaskHandler runTask,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreateTimerHandler createTimer,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreatePeriodicTimerHandler createPeriodicTimer,
PrintHandler print,
ForkHandler fork
}) = _ZoneSpecification;
/**
* Creates a specification from [other] with the provided handlers overriding
* the ones in [other].
*
* The task-related parameters ([createTask] and [runTask]) are experimental
* and might be removed without warning.
*/
factory ZoneSpecification.from(ZoneSpecification other, {
HandleUncaughtErrorHandler handleUncaughtError: null,
RunHandler run: null,
RunUnaryHandler runUnary: null,
RunBinaryHandler runBinary: null,
RegisterCallbackHandler registerCallback: null,
RegisterUnaryCallbackHandler registerUnaryCallback: null,
RegisterBinaryCallbackHandler registerBinaryCallback: null,
ErrorCallbackHandler errorCallback: null,
ScheduleMicrotaskHandler scheduleMicrotask: null,
CreateTaskHandler createTask: null,
RunTaskHandler runTask: null,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreateTimerHandler createTimer: null,
// TODO(floitsch): mark as deprecated once tasks are non-experimental.
CreatePeriodicTimerHandler createPeriodicTimer: null,
PrintHandler print: null,
ForkHandler fork: null
}) {
return new ZoneSpecification(
handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
run: run ?? other.run,
runUnary: runUnary ?? other.runUnary,
runBinary: runBinary ?? other.runBinary,
registerCallback: registerCallback ?? other.registerCallback,
registerUnaryCallback: registerUnaryCallback ??
other.registerUnaryCallback,
registerBinaryCallback: registerBinaryCallback ??
other.registerBinaryCallback,
errorCallback: errorCallback ?? other.errorCallback,
createTask: createTask ?? other.createTask,
runTask: runTask ?? other.runTask,
print : print ?? other.print,
fork: fork ?? other.fork,
scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
createTimer : createTimer ?? other.createTimer,
createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer);
}
HandleUncaughtErrorHandler get handleUncaughtError;
RunHandler get run;
RunUnaryHandler get runUnary;
RunBinaryHandler get runBinary;
RegisterCallbackHandler get registerCallback;
RegisterUnaryCallbackHandler get registerUnaryCallback;
RegisterBinaryCallbackHandler get registerBinaryCallback;
ErrorCallbackHandler get errorCallback;
ScheduleMicrotaskHandler get scheduleMicrotask;
/// *Experimental*. Might disappear without warning.
CreateTaskHandler get createTask;
/// *Experimental*. Might disappear without warning.
RunTaskHandler get runTask;
PrintHandler get print;
ForkHandler get fork;
// TODO(floitsch): deprecate once tasks are non-experimental.
CreateTimerHandler get createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
CreatePeriodicTimerHandler get createPeriodicTimer;
}
/**
* Internal [ZoneSpecification] class.
*
* The implementation wants to rely on the fact that the getters cannot change
* dynamically. We thus require users to go through the redirecting
* [ZoneSpecification] constructor which instantiates this class.
*/
class _ZoneSpecification implements ZoneSpecification {
const _ZoneSpecification({
this.handleUncaughtError: null,
this.run: null,
this.runUnary: null,
this.runBinary: null,
this.registerCallback: null,
this.registerUnaryCallback: null,
this.registerBinaryCallback: null,
this.errorCallback: null,
this.scheduleMicrotask: null,
this.createTask: null,
this.runTask: null,
this.print: null,
this.fork: null,
// TODO(floitsch): deprecate once tasks are non-experimental.
this.createTimer: null,
// TODO(floitsch): deprecate once tasks are non-experimental.
this.createPeriodicTimer: null
});
final HandleUncaughtErrorHandler handleUncaughtError;
final RunHandler run;
final RunUnaryHandler runUnary;
final RunBinaryHandler runBinary;
final RegisterCallbackHandler registerCallback;
final RegisterUnaryCallbackHandler registerUnaryCallback;
final RegisterBinaryCallbackHandler registerBinaryCallback;
final ErrorCallbackHandler errorCallback;
final ScheduleMicrotaskHandler scheduleMicrotask;
final CreateTaskHandler createTask;
final RunTaskHandler runTask;
final PrintHandler print;
final ForkHandler fork;
// TODO(floitsch): deprecate once tasks are non-experimental.
final CreateTimerHandler createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
final CreatePeriodicTimerHandler createPeriodicTimer;
}
/**
* This class wraps zones for delegation.
*
* When forwarding to parent zones one can't just invoke the parent zone's
* exposed functions (like [Zone.run]), but one needs to provide more
* information (like the zone the `run` was initiated). Zone callbacks thus
* receive more information including this [ZoneDelegate] class. When delegating
* to the parent zone one should go through the given instance instead of
* directly invoking the parent zone.
*/
abstract class ZoneDelegate {
/*=R*/ handleUncaughtError/*<R>*/(
Zone zone, error, StackTrace stackTrace);
/*=R*/ run/*<R>*/(Zone zone, /*=R*/ f());
/*=R*/ runUnary/*<R, T>*/(Zone zone, /*=R*/ f(/*=T*/ arg), /*=T*/ arg);
/*=R*/ runBinary/*<R, T1, T2>*/(Zone zone,
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
ZoneCallback/*<R>*/ registerCallback/*<R>*/(Zone zone, /*=R*/ f());
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
Zone zone, /*=R*/ f(/*=T*/ arg));
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
Zone zone, /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2));
AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace);
void scheduleMicrotask(Zone zone, void f());
/// *Experimental*. Might disappear without notice.
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
Zone zone, TaskCreate/*<T, S>*/ create,
TaskSpecification/*=S*/ specification);
/// *Experimental*. Might disappear without notice.
void runTask/*<T, A>*/(
Zone zone, TaskRun/*<T, A>*/ run, Object/*=T*/ task,
Object/*=A*/ argument);
void print(Zone zone, String line);
Zone fork(Zone zone, ZoneSpecification specification, Map zoneValues);
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Zone zone, Duration duration, void f());
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer));
}
/**
* A Zone represents the asynchronous version of a dynamic extent. Asynchronous
* callbacks are executed in the zone they have been queued in. For example,
* the callback of a `future.then` is executed in the same zone as the one where
* the `then` was invoked.
*/
abstract class Zone {
// Private constructor so that it is not possible instantiate a Zone class.
Zone._();
/** The root zone that is implicitly created. */
static const Zone ROOT = _ROOT_ZONE;
/** The currently running zone. */
static Zone _current = _ROOT_ZONE;
static Zone get current => _current;
/*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace);
/**
* Returns the parent zone.
*
* Returns `null` if `this` is the [ROOT] zone.
*/
Zone get parent;
/**
* The error zone is the one that is responsible for dealing with uncaught
* errors.
* Errors are not allowed to cross between zones with different error-zones.
*
* This is the closest parent or ancestor zone of this zone that has a custom
* [handleUncaughtError] method.
*/
Zone get errorZone;
/**
* Returns true if `this` and [otherZone] are in the same error zone.
*
* Two zones are in the same error zone if they inherit their
* [handleUncaughtError] callback from the same [errorZone].
*/
bool inSameErrorZone(Zone otherZone);
/**
* Creates a new zone as a child of `this`.
*
* The new zone will have behavior like the current zone, except where
* overridden by functions in [specification].
*
* The new zone will have the same stored values (accessed through
* `operator []`) as this zone, but updated with the keys and values
* in [zoneValues]. If a key is in both this zone's values and in
* `zoneValues`, the new zone will use the value from `zoneValues``.
*/
Zone fork({ ZoneSpecification specification,
Map zoneValues });
/**
* Executes the given function [f] in this zone.
*/
/*=R*/ run/*<R>*/(/*=R*/ f());
/**
* Executes the given callback [f] with argument [arg] in this zone.
*/
/*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
/**
* Executes the given callback [f] with argument [arg1] and [arg2] in this
* zone.
*/
/*=R*/ runBinary/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
/**
* Executes the given function [f] in this zone.
*
* Same as [run] but catches uncaught errors and gives them to
* [handleUncaughtError].
*/
/*=R*/ runGuarded/*<R>*/(/*=R*/ f());
/**
* Executes the given callback [f] in this zone.
*
* Same as [runUnary] but catches uncaught errors and gives them to
* [handleUncaughtError].
*/
/*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
/**
* Executes the given callback [f] in this zone.
*
* Same as [runBinary] but catches uncaught errors and gives them to
* [handleUncaughtError].
*/
/*=R*/ runBinaryGuarded/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
/**
* Registers the given callback in this zone.
*
* It is good practice to register asynchronous or delayed callbacks before
* invoking [run]. This gives the zone a chance to wrap the callback and
* to store information with the callback. For example, a zone may decide
* to store the stack trace (at the time of the registration) with the
* callback.
*
* Returns a potentially new callback that should be used in place of the
* given [callback].
*/
ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback());
/**
* Registers the given callback in this zone.
*
* Similar to [registerCallback] but with a unary callback.
*/
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
/*=R*/ callback(/*=T*/ arg));
/**
* Registers the given callback in this zone.
*
* Similar to [registerCallback] but with a unary callback.
*/
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
/*=R*/ callback(/*=T1*/ arg1, /*=T2*/ arg2));
/**
* Equivalent to:
*
* ZoneCallback registered = registerCallback(f);
* if (runGuarded) return () => this.runGuarded(registered);
* return () => this.run(registered);
*
*/
ZoneCallback/*<R>*/ bindCallback/*<R>*/(
/*=R*/ f(), { bool runGuarded: true });
/**
* Equivalent to:
*
* ZoneCallback registered = registerUnaryCallback(f);
* if (runGuarded) return (arg) => this.runUnaryGuarded(registered, arg);
* return (arg) => thin.runUnary(registered, arg);
*/
ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/(
/*=R*/ f(/*=T*/ arg), { bool runGuarded: true });
/**
* Equivalent to:
*
* ZoneCallback registered = registerBinaryCallback(f);
* if (runGuarded) {
* return (arg1, arg2) => this.runBinaryGuarded(registered, arg);
* }
* return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
*/
ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true });
/**
* Intercepts errors when added programmatically to a `Future` or `Stream`.
*
* When caling [Completer.completeError], [Stream.addError],
* or [Future] constructors that take an error or a callback that may throw,
* the current zone is allowed to intercept and replace the error.
*
* When other libraries use intermediate controllers or completers, such
* calls may contain errors that have already been processed.
*
* Return `null` if no replacement is desired.
* The original error is used unchanged in that case.
* Otherwise return an instance of [AsyncError] holding
* the new pair of error and stack trace.
* If the [AsyncError.error] is `null`, it is replaced by a [NullThrownError].
*/
AsyncError errorCallback(Object error, StackTrace stackTrace);
/**
* Runs [f] asynchronously in this zone.
*/
void scheduleMicrotask(void f());
/**
* Creates a task in the current zone.
*
* A task represents an asynchronous operation or process that reports back
* through the event loop.
*
* This function allows the zone to intercept the initialization of the
* task while the [runTask] function is invoked when the task reports back.
*
* By default, in the root zone, the [create] function is invoked with the
* [specification] as argument. It returns a task object which is used for all
* future interactions between the zone and the task. The object is
* a unique instance representing the task. It is generally returned to
* whoever initiated the task.
* For example, the HTML library uses the returned [StreamSubscription] as
* task object when users register an event listener.
*
* Tasks are created when the program starts an operation that reports back
* through the event loop. For example, a timer or an HTTP request both
* return through the event loop and are therefore tasks.
*
* If the [create] function is not invoked (because a custom zone has
* replaced or intercepted it), then the operation is *not* started. This
* means that a custom zone can intercept tasks, like HTTP requests.
*
* A task goes through the following steps:
* - a user invokes a library function that should eventually return through
* the event loop.
* - the library function creates a [TaskSpecification] that contains the
* necessary information to start the operation, and invokes
* `Zone.current.createTask` with the specification and a [create] closure.
* The closure, when invoked, uses the specification to start the operation
* (usually by interacting with the underlying system, or as a native
* extension), and returns a task object that identifies the running task.
* - custom zones handle the request and (unless completely intercepted and
* aborted), end up calling the root zone's [createTask] which runs the
* provided `create` closure, which may have been replaced at this point.
* - later, the asynchronous operation returns through the event loop.
* It invokes [Zone.runTask] on the zone in which the task should run
* (and which was originally passed to the `create` function by
* `createTask`). The [runTask] function receives the
* task object, a `run` function and an argument. As before, custom zones
* may intercept this call. Eventually (unless aborted), the `run` function
* is invoked. This last step may happen multiple times for tasks that are
* not oneshot tasks (see [ZoneSpecification.isOneShot]).
*
* Custom zones may replace the [specification] with a different one, thus
* modifying the task parameters. An operation that wishes to be an
* interceptable task must publicly specify the types that intercepting code
* sees:
* - The specification type (extending [TaskSpecification]) which holds the
* information available when intercepting the `createTask` call.
* - The task object type, returned by `createTask` and [create]. This object
* may simply be typed as [Object].
* - The argument type, if [runTask] takes a meaningful argument.
*
* *Experimental*. Might disappear without notice.
*/
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
/*=T*/ create(TaskSpecification/*=S*/ specification, Zone zone),
TaskSpecification/*=S*/ specification);
/**
* Runs a task callback.
*
* This function is invoked when an operation, started through [createTask],
* generates an event.
*
* Generally, tasks schedule Dart code in the global event loop when the
* [createTask] function is invoked. Since the
* event loop does not expect any return value from the code it runs, the
* [runTask] function is a void function.
*
* The [task] object must be the same as the one created with [createTask].
*
* It is good practice that task operations provide a meaningful [argument],
* so that custom zones can interact with it. They might want to log or
* replace the argument before calling the [run] function.
*
* See [createTask].
*
* *Experimental*. Might disappear without notice.
*/
void runTask/*<T, A>*/(
/*=T*/ run(/*=T*/ task, /*=A*/ argument), Object/*=T*/ task,
Object/*=A*/ argument);
/**
* Creates a Timer where the callback is executed in this zone.
*/
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Duration duration, void callback());
/**
* Creates a periodic Timer where the callback is executed in this zone.
*/
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Duration period, void callback(Timer timer));
/**
* Prints the given [line].
*/
void print(String line);
/**
* Call to enter the Zone.
*
* The previous current zone is returned.
*/
static Zone _enter(Zone zone) {
assert(zone != null);
assert(!identical(zone, _current));
Zone previous = _current;
_current = zone;
return previous;
}
/**
* Call to leave the Zone.
*
* The previous Zone must be provided as `previous`.
*/
static void _leave(Zone previous) {
assert(previous != null);
Zone._current = previous;
}
/**
* Retrieves the zone-value associated with [key].
*
* If this zone does not contain the value looks up the same key in the
* parent zone. If the [key] is not found returns `null`.
*
* Any object can be used as key, as long as it has compatible `operator ==`
* and `hashCode` implementations.
* By controlling access to the key, a zone can grant or deny access to the
* zone value.
*/
operator [](Object key);
}
ZoneDelegate _parentDelegate(_Zone zone) {
if (zone.parent == null) return null;
return zone.parent._delegate;
}
class _ZoneDelegate implements ZoneDelegate {
final _Zone _delegationTarget;
_ZoneDelegate(this._delegationTarget);
/*=R*/ handleUncaughtError/*<R>*/(
Zone zone, error, StackTrace stackTrace) {
var implementation = _delegationTarget._handleUncaughtError;
_Zone implZone = implementation.zone;
HandleUncaughtErrorHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(
implZone, _parentDelegate(implZone), zone, error, stackTrace)
as Object/*=R*/;
}
/*=R*/ run/*<R>*/(Zone zone, /*=R*/ f()) {
var implementation = _delegationTarget._run;
_Zone implZone = implementation.zone;
RunHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as Object/*=R*/;
}
/*=R*/ runUnary/*<R, T>*/(Zone zone, /*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
var implementation = _delegationTarget._runUnary;
_Zone implZone = implementation.zone;
RunUnaryHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(
implZone, _parentDelegate(implZone), zone, f, arg) as Object/*=R*/;
}
/*=R*/ runBinary/*<R, T1, T2>*/(Zone zone,
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
var implementation = _delegationTarget._runBinary;
_Zone implZone = implementation.zone;
RunBinaryHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(
implZone, _parentDelegate(implZone), zone, f, arg1, arg2)
as Object/*=R*/;
}
ZoneCallback/*<R>*/ registerCallback/*<R>*/(Zone zone, /*=R*/ f()) {
var implementation = _delegationTarget._registerCallback;
_Zone implZone = implementation.zone;
RegisterCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneCallback<R>*/;
}
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
Zone zone, /*=R*/ f(/*=T*/ arg)) {
var implementation = _delegationTarget._registerUnaryCallback;
_Zone implZone = implementation.zone;
RegisterUnaryCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneUnaryCallback<R, T>*/;
}
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
Zone zone, /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) {
var implementation = _delegationTarget._registerBinaryCallback;
_Zone implZone = implementation.zone;
RegisterBinaryCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(implZone, _parentDelegate(implZone), zone, f)
as dynamic/*=ZoneBinaryCallback<R, T1, T2>*/;
}
AsyncError errorCallback(Zone zone, Object error, StackTrace stackTrace) {
var implementation = _delegationTarget._errorCallback;
_Zone implZone = implementation.zone;
if (identical(implZone, _ROOT_ZONE)) return null;
ErrorCallbackHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone,
error, stackTrace);
}
void scheduleMicrotask(Zone zone, f()) {
var implementation = _delegationTarget._scheduleMicrotask;
_Zone implZone = implementation.zone;
ScheduleMicrotaskHandler handler = implementation.function;
handler(implZone, _parentDelegate(implZone), zone, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
Zone zone, TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
var implementation = _delegationTarget._createTask;
_Zone implZone = implementation.zone;
// TODO(floitsch): make the handler call a generic method call on '<T, S>'
// once it's supported. Remove the unnecessary cast.
var handler =
implementation.function as CreateTaskHandler/*<T, S>*/;
return handler(
implZone, _parentDelegate(implZone), zone, create, specification);
}
void runTask/*<T, A>*/(Zone zone, TaskRun run, Object /*=T*/ task,
Object /*=A*/ argument) {
var implementation = _delegationTarget._runTask;
_Zone implZone = implementation.zone;
RunTaskHandler handler = implementation.function;
// TODO(floitsch): make this a generic call on '<T, A>'.
handler(implZone, _parentDelegate(implZone), zone, run, task, argument);
}
void print(Zone zone, String line) {
var implementation = _delegationTarget._print;
_Zone implZone = implementation.zone;
PrintHandler handler = implementation.function;
handler(implZone, _parentDelegate(implZone), zone, line);
}
Zone fork(Zone zone, ZoneSpecification specification,
Map zoneValues) {
var implementation = _delegationTarget._fork;
_Zone implZone = implementation.zone;
ForkHandler handler = implementation.function;
return handler(
implZone, _parentDelegate(implZone), zone, specification, zoneValues);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Zone zone, Duration duration, void f()) {
var implementation = _delegationTarget._createTimer;
_Zone implZone = implementation.zone;
CreateTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, duration, f);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Zone zone, Duration period, void f(Timer timer)) {
var implementation = _delegationTarget._createPeriodicTimer;
_Zone implZone = implementation.zone;
CreatePeriodicTimerHandler handler = implementation.function;
return handler(implZone, _parentDelegate(implZone), zone, period, f);
}
}
/**
* Base class for Zone implementations.
*/
abstract class _Zone implements Zone {
const _Zone();
_ZoneFunction<RunHandler> get _run;
_ZoneFunction<RunUnaryHandler> get _runUnary;
_ZoneFunction<RunBinaryHandler> get _runBinary;
_ZoneFunction<RegisterCallbackHandler> get _registerCallback;
_ZoneFunction<RegisterUnaryCallbackHandler> get _registerUnaryCallback;
_ZoneFunction<RegisterBinaryCallbackHandler> get _registerBinaryCallback;
_ZoneFunction<ErrorCallbackHandler> get _errorCallback;
_ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask;
_ZoneFunction<CreateTaskHandler> get _createTask;
_ZoneFunction<RunTaskHandler> get _runTask;
_ZoneFunction<PrintHandler> get _print;
_ZoneFunction<ForkHandler> get _fork;
_ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> get _createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer;
_Zone get parent;
ZoneDelegate get _delegate;
Map get _map;
bool inSameErrorZone(Zone otherZone) {
return identical(this, otherZone) ||
identical(errorZone, otherZone.errorZone);
}
}
class _CustomZone extends _Zone {
// The actual zone and implementation of each of these
// inheritable zone functions.
_ZoneFunction<RunHandler> _run;
_ZoneFunction<RunUnaryHandler> _runUnary;
_ZoneFunction<RunBinaryHandler> _runBinary;
_ZoneFunction<RegisterCallbackHandler> _registerCallback;
_ZoneFunction<RegisterUnaryCallbackHandler> _registerUnaryCallback;
_ZoneFunction<RegisterBinaryCallbackHandler> _registerBinaryCallback;
_ZoneFunction<ErrorCallbackHandler> _errorCallback;
_ZoneFunction<ScheduleMicrotaskHandler> _scheduleMicrotask;
_ZoneFunction<CreateTaskHandler> _createTask;
_ZoneFunction<RunTaskHandler> _runTask;
_ZoneFunction<PrintHandler> _print;
_ZoneFunction<ForkHandler> _fork;
_ZoneFunction<HandleUncaughtErrorHandler> _handleUncaughtError;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> _createTimer;
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> _createPeriodicTimer;
// A cached delegate to this zone.
ZoneDelegate _delegateCache;
/// The parent zone.
final _Zone parent;
/// The zone's scoped value declaration map.
///
/// This is always a [HashMap].
final Map _map;
ZoneDelegate get _delegate {
if (_delegateCache != null) return _delegateCache;
_delegateCache = new _ZoneDelegate(this);
return _delegateCache;
}
_CustomZone(this.parent, ZoneSpecification specification, this._map) {
// The root zone will have implementations of all parts of the
// specification, so it will never try to access the (null) parent.
// All other zones have a non-null parent.
_run = (specification.run != null)
? new _ZoneFunction<RunHandler>(this, specification.run)
: parent._run;
_runUnary = (specification.runUnary != null)
? new _ZoneFunction<RunUnaryHandler>(this, specification.runUnary)
: parent._runUnary;
_runBinary = (specification.runBinary != null)
? new _ZoneFunction<RunBinaryHandler>(this, specification.runBinary)
: parent._runBinary;
_registerCallback = (specification.registerCallback != null)
? new _ZoneFunction<RegisterCallbackHandler>(
this, specification.registerCallback)
: parent._registerCallback;
_registerUnaryCallback = (specification.registerUnaryCallback != null)
? new _ZoneFunction<RegisterUnaryCallbackHandler>(
this, specification.registerUnaryCallback)
: parent._registerUnaryCallback;
_registerBinaryCallback = (specification.registerBinaryCallback != null)
? new _ZoneFunction<RegisterBinaryCallbackHandler>(
this, specification.registerBinaryCallback)
: parent._registerBinaryCallback;
_errorCallback = (specification.errorCallback != null)
? new _ZoneFunction<ErrorCallbackHandler>(
this, specification.errorCallback)
: parent._errorCallback;
_scheduleMicrotask = (specification.scheduleMicrotask != null)
? new _ZoneFunction<ScheduleMicrotaskHandler>(
this, specification.scheduleMicrotask)
: parent._scheduleMicrotask;
_createTask = (specification.createTask != null)
? new _ZoneFunction<CreateTaskHandler>(
this, specification.createTask)
: parent._createTask;
_runTask = (specification.runTask != null)
? new _ZoneFunction<RunTaskHandler>(
this, specification.runTask)
: parent._runTask;
_print = (specification.print != null)
? new _ZoneFunction<PrintHandler>(this, specification.print)
: parent._print;
_fork = (specification.fork != null)
? new _ZoneFunction<ForkHandler>(this, specification.fork)
: parent._fork;
_handleUncaughtError = (specification.handleUncaughtError != null)
? new _ZoneFunction<HandleUncaughtErrorHandler>(
this, specification.handleUncaughtError)
: parent._handleUncaughtError;
// Deprecated fields, once tasks are non-experimental.
_createTimer = (specification.createTimer != null)
? new _ZoneFunction<CreateTimerHandler>(
this, specification.createTimer)
: parent._createTimer;
_createPeriodicTimer = (specification.createPeriodicTimer != null)
? new _ZoneFunction<CreatePeriodicTimerHandler>(
this, specification.createPeriodicTimer)
: parent._createPeriodicTimer;
}
/**
* The closest error-handling zone.
*
* Returns `this` if `this` has an error-handler. Otherwise returns the
* parent's error-zone.
*/
Zone get errorZone => _handleUncaughtError.zone;
/*=R*/ runGuarded/*<R>*/(/*=R*/ f()) {
try {
return run(f);
} catch (e, s) {
return handleUncaughtError(e, s);
}
}
/*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
try {
return runUnary(f, arg);
} catch (e, s) {
return handleUncaughtError(e, s);
}
}
/*=R*/ runBinaryGuarded/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
try {
return runBinary(f, arg1, arg2);
} catch (e, s) {
return handleUncaughtError(e, s);
}
}
ZoneCallback/*<R>*/ bindCallback/*<R>*/(
/*=R*/ f(), { bool runGuarded: true }) {
var registered = registerCallback(f);
if (runGuarded) {
return () => this.runGuarded(registered);
} else {
return () => this.run(registered);
}
}
ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/(
/*=R*/ f(/*=T*/ arg), { bool runGuarded: true }) {
var registered = registerUnaryCallback(f);
if (runGuarded) {
return (arg) => this.runUnaryGuarded(registered, arg);
} else {
return (arg) => this.runUnary(registered, arg);
}
}
ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true }) {
var registered = registerBinaryCallback(f);
if (runGuarded) {
return (arg1, arg2) => this.runBinaryGuarded(registered, arg1, arg2);
} else {
return (arg1, arg2) => this.runBinary(registered, arg1, arg2);
}
}
operator [](Object key) {
var result = _map[key];
if (result != null || _map.containsKey(key)) return result;
// If we are not the root zone, look up in the parent zone.
if (parent != null) {
// We do not optimize for repeatedly looking up a key which isn't
// there. That would require storing the key and keeping it alive.
// Copying the key/value from the parent does not keep any new values
// alive.
var value = parent[key];
if (value != null) {
_map[key] = value;
}
return value;
}
assert(this == _ROOT_ZONE);
return null;
}
// Methods that can be customized by the zone specification.
/*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace) {
var implementation = this._handleUncaughtError;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
HandleUncaughtErrorHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(
implementation.zone, parentDelegate, this, error, stackTrace)
as Object/*=R*/;
}
Zone fork({ZoneSpecification specification, Map zoneValues}) {
var implementation = this._fork;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
ForkHandler handler = implementation.function;
return handler(implementation.zone, parentDelegate, this,
specification, zoneValues);
}
/*=R*/ run/*<R>*/(/*=R*/ f()) {
var implementation = this._run;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RunHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, f)
as Object/*=R*/;
}
/*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
var implementation = this._runUnary;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RunUnaryHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, f, arg)
as Object/*=R*/;
}
/*=R*/ runBinary/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
var implementation = this._runBinary;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RunBinaryHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(
implementation.zone, parentDelegate, this, f, arg1, arg2)
as Object/*=R*/;
}
ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback()) {
var implementation = this._registerCallback;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RegisterCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneCallback<R>*/;
}
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
/*=R*/ callback(/*=T*/ arg)) {
var implementation = this._registerUnaryCallback;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RegisterUnaryCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T>' once it's
// supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneUnaryCallback<R, T>*/;
}
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
/*=R*/ callback(/*=T1*/ arg1, /*=T2*/ arg2)) {
var implementation = this._registerBinaryCallback;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RegisterBinaryCallbackHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<R, T1, T2>' once
// it's supported. Remove the unnecessary cast.
return handler(implementation.zone, parentDelegate, this, callback)
as dynamic/*=ZoneBinaryCallback<R, T1, T2>*/;
}
AsyncError errorCallback(Object error, StackTrace stackTrace) {
var implementation = this._errorCallback;
assert(implementation != null);
final Zone implementationZone = implementation.zone;
if (identical(implementationZone, _ROOT_ZONE)) return null;
final ZoneDelegate parentDelegate = _parentDelegate(implementationZone);
ErrorCallbackHandler handler = implementation.function;
return handler(
implementationZone, parentDelegate, this, error, stackTrace);
}
void scheduleMicrotask(void f()) {
var implementation = this._scheduleMicrotask;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
ScheduleMicrotaskHandler handler = implementation.function;
handler(implementation.zone, parentDelegate, this, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
var implementation = this._createTask;
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
// TODO(floitsch): make the handler call a generic method call on '<T, S>'
// once it's supported. Remove the unnecessary cast.
var handler =
implementation.function as CreateTaskHandler/*<T, S>*/;
return handler(
implementation.zone, parentDelegate, this, create, specification);
}
void runTask/*<T, A>*/(
TaskRun/*<T, A>*/ run, Object/*=T*/ task, Object/*=A*/ arg1) {
var implementation = this._runTask;
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
RunTaskHandler handler = implementation.function;
// TODO(floitsch): make this a generic method call on '<T, A>' once it's
// supported.
handler(implementation.zone, parentDelegate, this, run, task, arg1);
}
void print(String line) {
var implementation = this._print;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
PrintHandler handler = implementation.function;
return handler(implementation.zone, parentDelegate, this, line);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createTimer(Duration duration, void f()) {
var implementation = this._createTimer;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
CreateTimerHandler handler = implementation.function;
return handler(implementation.zone, parentDelegate, this, duration, f);
}
// TODO(floitsch): deprecate once tasks are non-experimental.
Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
var implementation = this._createPeriodicTimer;
assert(implementation != null);
ZoneDelegate parentDelegate = _parentDelegate(implementation.zone);
CreatePeriodicTimerHandler handler = implementation.function;
return handler(
implementation.zone, parentDelegate, this, duration, f);
}
}
/*=R*/ _rootHandleUncaughtError/*<R>*/(
Zone self, ZoneDelegate parent, Zone zone, error, StackTrace stackTrace) {
_schedulePriorityAsyncCallback(() {
if (error == null) error = new NullThrownError();
if (stackTrace == null) throw error;
_rethrow(error, stackTrace);
});
}
external void _rethrow(Object error, StackTrace stackTrace);
/*=R*/ _rootRun/*<R>*/(Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f()) {
if (Zone._current == zone) return f();
Zone old = Zone._enter(zone);
try {
return f();
} finally {
Zone._leave(old);
}
}
/*=R*/ _rootRunUnary/*<R, T>*/(Zone self, ZoneDelegate parent, Zone zone,
/*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
if (Zone._current == zone) return f(arg);
Zone old = Zone._enter(zone);
try {
return f(arg);
} finally {
Zone._leave(old);
}
}
/*=R*/ _rootRunBinary/*<R, T1, T2>*/(Zone self, ZoneDelegate parent, Zone zone,
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
if (Zone._current == zone) return f(arg1, arg2);
Zone old = Zone._enter(zone);
try {
return f(arg1, arg2);
} finally {
Zone._leave(old);
}
}
ZoneCallback/*<R>*/ _rootRegisterCallback/*<R>*/(
Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f()) {
return f;
}
ZoneUnaryCallback/*<R, T>*/ _rootRegisterUnaryCallback/*<R, T>*/(
Zone self, ZoneDelegate parent, Zone zone, /*=R*/ f(/*=T*/ arg)) {
return f;
}
ZoneBinaryCallback/*<R, T1, T2>*/ _rootRegisterBinaryCallback/*<R, T1, T2>*/(
Zone self, ZoneDelegate parent, Zone zone,
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) {
return f;
}
AsyncError _rootErrorCallback(Zone self, ZoneDelegate parent, Zone zone,
Object error, StackTrace stackTrace) => null;
void _rootScheduleMicrotask(Zone self, ZoneDelegate parent, Zone zone, f()) {
if (!identical(_ROOT_ZONE, zone)) {
bool hasErrorHandler = !_ROOT_ZONE.inSameErrorZone(zone);
f = zone.bindCallback(f, runGuarded: hasErrorHandler);
// Use root zone as event zone if the function is already bound.
zone = _ROOT_ZONE;
}
_scheduleAsyncCallback(f);
}
Object/*=T*/ _rootCreateTask/*<T, S extends TaskSpecification>*/(
Zone self, ZoneDelegate parent, Zone zone,
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
return create(specification, zone);
}
void _rootRunTask/*<T, A>*/(
Zone self, ZoneDelegate parent, Zone zone, TaskRun run/*<T, A>*/,
Object/*=T*/ task, Object/*=A*/ arg) {
if (Zone._current == zone) {
run(task, arg);
return;
}
Zone old = Zone._enter(zone);
try {
run(task, arg);
} catch (e, s) {
zone.handleUncaughtError/*<dynamic>*/(e, s);
} finally {
Zone._leave(old);
}
}
Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
Duration duration, void callback()) {
return new Timer._task(zone, duration, callback);
}
Timer _rootCreatePeriodicTimer(
Zone self, ZoneDelegate parent, Zone zone,
Duration duration, void callback(Timer timer)) {
return new Timer._periodicTask(zone, duration, callback);
}
void _rootPrint(Zone self, ZoneDelegate parent, Zone zone, String line) {
printToConsole(line);
}
void _printToZone(String line) {
Zone.current.print(line);
}
Zone _rootFork(Zone self, ZoneDelegate parent, Zone zone,
ZoneSpecification specification,
Map zoneValues) {
// TODO(floitsch): it would be nice if we could get rid of this hack.
// Change the static zoneOrDirectPrint function to go through zones
// from now on.
printToZone = _printToZone;
if (specification == null) {
specification = const ZoneSpecification();
} else if (specification is! _ZoneSpecification) {
throw new ArgumentError("ZoneSpecifications must be instantiated"
" with the provided constructor.");
}
Map valueMap;
if (zoneValues == null) {
if (zone is _Zone) {
valueMap = zone._map;
} else {
valueMap = new HashMap();
}
} else {
valueMap = new HashMap.from(zoneValues);
}
return new _CustomZone(zone, specification, valueMap);
}
class _RootZone extends _Zone {
const _RootZone();
_ZoneFunction<RunHandler> get _run =>
const _ZoneFunction<RunHandler>(_ROOT_ZONE, _rootRun);
_ZoneFunction<RunUnaryHandler> get _runUnary =>
const _ZoneFunction<RunUnaryHandler>(_ROOT_ZONE, _rootRunUnary);
_ZoneFunction<RunBinaryHandler> get _runBinary =>
const _ZoneFunction<RunBinaryHandler>(_ROOT_ZONE, _rootRunBinary);
_ZoneFunction<RegisterCallbackHandler> get _registerCallback =>
const _ZoneFunction<RegisterCallbackHandler>(
_ROOT_ZONE, _rootRegisterCallback);
_ZoneFunction<RegisterUnaryCallbackHandler> get _registerUnaryCallback =>
const _ZoneFunction<RegisterUnaryCallbackHandler>(
_ROOT_ZONE, _rootRegisterUnaryCallback);
_ZoneFunction<RegisterBinaryCallbackHandler> get _registerBinaryCallback =>
const _ZoneFunction<RegisterBinaryCallbackHandler>(
_ROOT_ZONE, _rootRegisterBinaryCallback);
_ZoneFunction<ErrorCallbackHandler> get _errorCallback =>
const _ZoneFunction<ErrorCallbackHandler>(_ROOT_ZONE, _rootErrorCallback);
_ZoneFunction<ScheduleMicrotaskHandler> get _scheduleMicrotask =>
const _ZoneFunction<ScheduleMicrotaskHandler>(
_ROOT_ZONE, _rootScheduleMicrotask);
_ZoneFunction<CreateTaskHandler> get _createTask =>
const _ZoneFunction<CreateTaskHandler>(_ROOT_ZONE, _rootCreateTask);
_ZoneFunction<RunTaskHandler> get _runTask =>
const _ZoneFunction<RunTaskHandler>(_ROOT_ZONE, _rootRunTask);
_ZoneFunction<PrintHandler> get _print =>
const _ZoneFunction<PrintHandler>(_ROOT_ZONE, _rootPrint);
_ZoneFunction<ForkHandler> get _fork =>
const _ZoneFunction<ForkHandler>(_ROOT_ZONE, _rootFork);
_ZoneFunction<HandleUncaughtErrorHandler> get _handleUncaughtError =>
const _ZoneFunction<HandleUncaughtErrorHandler>(
_ROOT_ZONE, _rootHandleUncaughtError);
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreateTimerHandler> get _createTimer =>
const _ZoneFunction<CreateTimerHandler>(_ROOT_ZONE, _rootCreateTimer);
// TODO(floitsch): deprecate once tasks are non-experimental.
_ZoneFunction<CreatePeriodicTimerHandler> get _createPeriodicTimer =>
const _ZoneFunction<CreatePeriodicTimerHandler>(
_ROOT_ZONE, _rootCreatePeriodicTimer);
// The parent zone.
_Zone get parent => null;
/// The zone's scoped value declaration map.
///
/// This is always a [HashMap].
Map get _map => _rootMap;
static Map _rootMap = new HashMap();
static ZoneDelegate _rootDelegate;
ZoneDelegate get _delegate {
if (_rootDelegate != null) return _rootDelegate;
return _rootDelegate = new _ZoneDelegate(this);
}
/**
* The closest error-handling zone.
*
* Returns `this` if `this` has an error-handler. Otherwise returns the
* parent's error-zone.
*/
Zone get errorZone => this;
// Zone interface.
/*=R*/ runGuarded/*<R>*/(/*=R*/ f()) {
try {
if (identical(_ROOT_ZONE, Zone._current)) {
return f();
}
return _rootRun/*<R>*/(null, null, this, f);
} catch (e, s) {
return handleUncaughtError/*<R>*/(e, s);
}
}
/*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
try {
if (identical(_ROOT_ZONE, Zone._current)) {
return f(arg);
}
return _rootRunUnary/*<R, T>*/(null, null, this, f, arg);
} catch (e, s) {
return handleUncaughtError/*<R>*/(e, s);
}
}
/*=R*/ runBinaryGuarded/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
try {
if (identical(_ROOT_ZONE, Zone._current)) {
return f(arg1, arg2);
}
return _rootRunBinary/*<R, T1, T2>*/(null, null, this, f, arg1, arg2);
} catch (e, s) {
return handleUncaughtError/*<R>*/(e, s);
}
}
ZoneCallback/*<R>*/ bindCallback/*<R>*/(
/*=R*/ f(), { bool runGuarded: true }) {
if (runGuarded) {
return () => this.runGuarded/*<R>*/(f);
} else {
return () => this.run/*<R>*/(f);
}
}
ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/(
/*=R*/ f(/*=T*/ arg), { bool runGuarded: true }) {
if (runGuarded) {
return (arg) => this.runUnaryGuarded/*<R, T>*/(f, arg);
} else {
return (arg) => this.runUnary/*<R, T>*/(f, arg);
}
}
ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true }) {
if (runGuarded) {
return (arg1, arg2) =>
this.runBinaryGuarded/*<R, T1, T2>*/(f, arg1, arg2);
} else {
return (arg1, arg2) => this.runBinary/*<R, T1, T2>*/(f, arg1, arg2);
}
}
operator [](Object key) => null;
// Methods that can be customized by the zone specification.
/*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace) {
return _rootHandleUncaughtError(null, null, this, error, stackTrace);
}
Zone fork({ZoneSpecification specification, Map zoneValues}) {
return _rootFork(null, null, this, specification, zoneValues);
}
/*=R*/ run/*<R>*/(/*=R*/ f()) {
if (identical(Zone._current, _ROOT_ZONE)) return f();
return _rootRun(null, null, this, f);
}
/*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg) {
if (identical(Zone._current, _ROOT_ZONE)) return f(arg);
return _rootRunUnary(null, null, this, f, arg);
}
/*=R*/ runBinary/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2) {
if (identical(Zone._current, _ROOT_ZONE)) return f(arg1, arg2);
return _rootRunBinary(null, null, this, f, arg1, arg2);
}
ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ f()) => f;
ZoneUnaryCallback/*<R, T>*/ registerUnaryCallback/*<R, T>*/(
/*=R*/ f(/*=T*/ arg)) => f;
ZoneBinaryCallback/*<R, T1, T2>*/ registerBinaryCallback/*<R, T1, T2>*/(
/*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2)) => f;
AsyncError errorCallback(Object error, StackTrace stackTrace) => null;
void scheduleMicrotask(void f()) {
_rootScheduleMicrotask(null, null, this, f);
}
Object/*=T*/ createTask/*<T, S extends TaskSpecification>*/(
TaskCreate/*<T, S>*/ create, TaskSpecification/*=S*/ specification) {
return _rootCreateTask/*<T, S>*/(null, null, this, create, specification);
}
void runTask/*<T, A>*/(
TaskRun/*<T, A>*/ run, Object/*=T*/ task, Object/*=A*/ arg) {
_rootRunTask/*<T, A>*/(null, null, this, run, task, arg);
}
Timer createTimer(Duration duration, void f()) {
return Timer._createTimer(duration, f);
}
Timer createPeriodicTimer(Duration duration, void f(Timer timer)) {
return Timer._createPeriodicTimer(duration, f);
}
void print(String line) {
printToConsole(line);
}
}
const _ROOT_ZONE = const _RootZone();
/**
* Runs [body] in its own zone.
*
* If [onError] is non-null the zone is considered an error zone. All uncaught
* errors, synchronous or asynchronous, in the zone are caught and handled
* by the callback.
*
* Errors may never cross error-zone boundaries. This is intuitive for leaving
* a zone, but it also applies for errors that would enter an error-zone.
* Errors that try to cross error-zone boundaries are considered uncaught.
*
* var future = new Future.value(499);
* runZoned(() {
* future = future.then((_) { throw "error in first error-zone"; });
* runZoned(() {
* future = future.catchError((e) { print("Never reached!"); });
* }, onError: (e) { print("unused error handler"); });
* }, onError: (e) { print("catches error of first error-zone."); });
*
* Example:
*
* runZoned(() {
* new Future(() { throw "asynchronous error"; });
* }, onError: print); // Will print "asynchronous error".
*/
/*=R*/ runZoned/*<R>*/(/*=R*/ body(),
{ Map zoneValues,
ZoneSpecification zoneSpecification,
Function onError }) {
HandleUncaughtErrorHandler errorHandler;
if (onError != null) {
errorHandler = (Zone self, ZoneDelegate parent, Zone zone,
error, StackTrace stackTrace) {
try {
if (onError is ZoneBinaryCallback<dynamic/*=R*/, dynamic, StackTrace>) {
return self.parent.runBinary(onError, error, stackTrace);
}
return self.parent.runUnary(onError, error);
} catch(e, s) {
if (identical(e, error)) {
return parent.handleUncaughtError(zone, error, stackTrace);
} else {
return parent.handleUncaughtError(zone, e, s);
}
}
};
}
if (zoneSpecification == null) {
zoneSpecification =
new ZoneSpecification(handleUncaughtError: errorHandler);
} else if (errorHandler != null) {
zoneSpecification =
new ZoneSpecification.from(zoneSpecification,
handleUncaughtError: errorHandler);
}
Zone zone = Zone.current.fork(specification: zoneSpecification,
zoneValues: zoneValues);
if (onError != null) {
return zone.runGuarded(body);
} else {
return zone.run(body);
}
}