blob: cb4ec2cea533d3da255f52cc85fcc5f008bc9ec2 [file] [log] [blame] [edit]
// Copyright (c) 2025, 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';
/// A parameter object with custom zone function handlers for [Zone.fork].
///
/// A zone specification is a parameter object passed to [Zone.fork]
/// and any underlying [ForkHandler] custom implementations.
/// The individual handlers, if set to a non-null value,
/// will be the implementation of the corresponding [Zone] methods
/// for a forked zone created using this zone specification.
///
/// 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).
/// This is the zone created by [Zone.fork] where the handler is
/// passed as part of the zone delegation.
/// 2. A [ZoneDelegate] to the parent zone.
/// 3. The "current" zone at the time the request was made.
/// The self zone is always a parent zone of the current zone.
///
/// Handlers can either stop propagating the request (by simply not calling the
/// parent handler), or forward to the parent zone, potentially modifying the
/// arguments on the way.
abstract final class ZoneSpecification {
/// Creates a specification with the provided handlers.
///
/// If the [handleUncaughtError] is provided, the new zone will be a new
/// "error zone" which will prevent errors from flowing into other
/// error zones (see [Zone.errorZone], [Zone.inSameErrorZone]).
const factory ZoneSpecification({
HandleUncaughtErrorHandler? handleUncaughtError,
RunHandler? run,
RunUnaryHandler? runUnary,
RunBinaryHandler? runBinary,
RegisterCallbackHandler? registerCallback,
RegisterUnaryCallbackHandler? registerUnaryCallback,
RegisterBinaryCallbackHandler? registerBinaryCallback,
ErrorCallbackHandler? errorCallback,
ScheduleMicrotaskHandler? scheduleMicrotask,
CreateTimerHandler? createTimer,
CreatePeriodicTimerHandler? createPeriodicTimer,
PrintHandler? print,
ForkHandler? fork,
}) = _ZoneSpecification;
/// Creates a specification from [other] and provided handlers.
///
/// The created zone specification has the handlers of [other]
/// and any individually provided handlers.
/// If a handler is provided both through [other] and individually,
/// the individually provided handler overrides the one from [other].
factory ZoneSpecification.from(
ZoneSpecification other, {
HandleUncaughtErrorHandler? handleUncaughtError,
RunHandler? run,
RunUnaryHandler? runUnary,
RunBinaryHandler? runBinary,
RegisterCallbackHandler? registerCallback,
RegisterUnaryCallbackHandler? registerUnaryCallback,
RegisterBinaryCallbackHandler? registerBinaryCallback,
ErrorCallbackHandler? errorCallback,
ScheduleMicrotaskHandler? scheduleMicrotask,
CreateTimerHandler? createTimer,
CreatePeriodicTimerHandler? createPeriodicTimer,
PrintHandler? print,
ForkHandler? fork,
}) {
return 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,
scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
createTimer: createTimer ?? other.createTimer,
createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
print: print ?? other.print,
fork: fork ?? other.fork,
);
}
/// A custom [Zone.handleUncaughtError] implementation for a new zone.
HandleUncaughtErrorHandler? get handleUncaughtError;
/// A custom [Zone.run] implementation for a new zone.
RunHandler? get run;
/// A custom [Zone.runUnary] implementation for a new zone.
RunUnaryHandler? get runUnary;
/// A custom [Zone.runBinary] implementation for a new zone.
RunBinaryHandler? get runBinary;
/// A custom [Zone.registerCallback] implementation for a new zone.
RegisterCallbackHandler? get registerCallback;
/// A custom [Zone.registerUnaryCallback] implementation for a new zone.
RegisterUnaryCallbackHandler? get registerUnaryCallback;
/// A custom [Zone.registerBinaryCallback] implementation for a new zone.
RegisterBinaryCallbackHandler? get registerBinaryCallback;
/// A custom [Zone.errorCallback] implementation for a new zone.
ErrorCallbackHandler? get errorCallback;
/// A custom [Zone.scheduleMicrotask] implementation for a new zone.
ScheduleMicrotaskHandler? get scheduleMicrotask;
/// A custom [Zone.createTimer] implementation for a new zone.
CreateTimerHandler? get createTimer;
/// A custom [Zone.createPeriodicTimer] implementation for a new zone.
CreatePeriodicTimerHandler? get createPeriodicTimer;
/// A custom [Zone.print] implementation for a new zone.
PrintHandler? get print;
/// A custom [Zone.handleUncaughtError] implementation for a new zone.
ForkHandler? get fork;
}
/// 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.
base class _ZoneSpecification implements ZoneSpecification {
const _ZoneSpecification({
this.handleUncaughtError,
this.run,
this.runUnary,
this.runBinary,
this.registerCallback,
this.registerUnaryCallback,
this.registerBinaryCallback,
this.errorCallback,
this.scheduleMicrotask,
this.createTimer,
this.createPeriodicTimer,
this.print,
this.fork,
});
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 CreateTimerHandler? createTimer;
final CreatePeriodicTimerHandler? createPeriodicTimer;
final PrintHandler? print;
final ForkHandler? fork;
}
// Names and documentation for the functions of a ZoneSpecification.
/// The type of a custom [Zone.handleUncaughtError] implementation function.
///
/// A function used as [ZoneSpecification.handleUncaughtError]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The [error] and [stackTrace] are the error and stack trace that
/// was uncaught in [zone].
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
///
/// If the uncaught error handler throws, the error will be passed
/// to `parent.handleUncaughtError`. If the thrown object is [error],
/// the throw is considered a re-throw and the original [stackTrace]
/// is retained. This allows an asynchronous error to leave the error zone.
typedef HandleUncaughtErrorHandler =
void Function(
Zone self,
ZoneDelegate parent,
Zone zone,
Object error,
StackTrace stackTrace,
);
/// The type of a custom [Zone.run] implementation function.
///
/// A function used as [ZoneSpecification.run]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] is the function which was passed to the
/// [Zone.run] of [zone].
///
/// The default behavior of [Zone.run] is
/// to call [f] in the current zone, [zone].
/// A custom handler can do things before, after or instead of
/// calling [f].
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef RunHandler =
R Function<R>(Zone self, ZoneDelegate parent, Zone zone, R Function() f);
/// The type of a custom [Zone.runUnary] implementation function.
///
/// A function used as [ZoneSpecification.runUnary]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] and value [arg] are the function and argument
/// which was passed to the [Zone.runUnary] of [zone].
///
/// The default behavior of [Zone.runUnary] is
/// to call [f] with argument [arg] in the current zone, [zone].
/// A custom handler can do things before, after or instead of
/// calling [f].
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef RunUnaryHandler =
R Function<R, T>(
Zone self,
ZoneDelegate parent,
Zone zone,
R Function(T arg) f,
T arg,
);
/// The type of a custom [Zone.runBinary] implementation function.
///
/// A function used as [ZoneSpecification.runBinary]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] and values [arg1] and [arg2] are the function and arguments
/// which was passed to the [Zone.runBinary] of [zone].
///
/// The default behavior of [Zone.runUnary] is
/// to call [f] with arguments [arg1] and [arg2] in the current zone, [zone].
/// A custom handler can do things before, after or instead of
/// calling [f].
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef RunBinaryHandler =
R Function<R, T1, T2>(
Zone self,
ZoneDelegate parent,
Zone zone,
R Function(T1 arg1, T2 arg2) f,
T1 arg1,
T2 arg2,
);
/// The type of a custom [Zone.registerCallback] implementation function.
///
/// A function used as [ZoneSpecification.registerCallback]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] is the function which was passed to the
/// [Zone.registerCallback] of [zone].
///
/// The handler should return either the function [f]
/// or another function replacing [f],
/// typically by wrapping [f] in a function
/// which does something extra before and after invoking [f]
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef RegisterCallbackHandler =
ZoneCallback<R> Function<R>(
Zone self,
ZoneDelegate parent,
Zone zone,
R Function() f,
);
/// The type of a custom [Zone.registerUnaryCallback] implementation function.
///
/// A function used as [ZoneSpecification.registerUnaryCallback]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] is the function which was passed to the
/// which was passed to the [Zone.registerUnaryCallback] of [zone].
///
/// The handler should return either the function [f]
/// or another function replacing [f],
/// typically by wrapping [f] in a function
/// which does something extra before and after invoking [f]
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef RegisterUnaryCallbackHandler =
ZoneUnaryCallback<R, T> Function<R, T>(
Zone self,
ZoneDelegate parent,
Zone zone,
R Function(T arg) f,
);
/// The type of a custom [Zone.registerBinaryCallback] implementation function.
///
/// A function used as [ZoneSpecification.registerBinaryCallback]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] is the function which was passed to the
/// which was passed to the [Zone.registerBinaryCallback] of [zone].
///
/// The handler should return either the function [f]
/// or another function replacing [f],
/// typically by wrapping [f] in a function
/// which does something extra before and after invoking [f]
typedef RegisterBinaryCallbackHandler =
ZoneBinaryCallback<R, T1, T2> Function<R, T1, T2>(
Zone self,
ZoneDelegate parent,
Zone zone,
R Function(T1 arg1, T2 arg2) f,
);
/// The type of a custom [Zone.errorCallback] implementation function.
///
/// A function used as [ZoneSpecification.errorCallback]
/// to specialize the behavior of a new zone.
///
/// The [error] and [stackTrace] are the error and stack trace
/// passed to [Zone.errorCallback] of [zone].
///
/// The function will be called when a synchronous error becomes an
/// asynchronous error, either by being caught, for example by a `Future.then`
/// callback throwing, or when used to create an asynchronous error
/// programmatically, for example using `Future.error` or `Completer.complete`.
///
/// If the function does not want to replace the error or stack trace,
/// it should just return `parent.errorCallback(zone, error, stackTrace)`,
/// giving the parent zone the chance to intercept.
///
/// If the function does want to replace the error and/or stack trace,
/// say with `error2` and `stackTrace2`, it should still allow the
/// parent zone to intercept those errors, for examples as:
/// ```dart
/// return parent.errorCallback(zone, error, stackTrace) ??
/// AsyncError(error, stackTrace);
/// ```
///
/// The function returns either `null` if the original error and stack trace
/// is unchanged, avoiding any allocation in the most common case,
/// or an [AsyncError] containing a replacement error and stack trace
/// which will be used in place of the originals as the asynchronous error.
///
/// The [self] [Zone] is the zone the handler was registered on,
/// the [parent] delegate forwards to the handlers of [self]'s parent zone,
/// and [zone] is the current zone where the error was uncaught,
/// which will have [self] as an ancestor zone.
///
/// The error callback handler **must not** throw.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef ErrorCallbackHandler =
AsyncError? Function(
Zone self,
ZoneDelegate parent,
Zone zone,
Object error,
StackTrace? stackTrace,
);
/// The type of a custom [Zone.scheduleMicrotask] implementation function.
///
/// A function used as [ZoneSpecification.scheduleMicrotask]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The function [f] is the function which was
/// passed to [Zone.scheduleMicrotask] of [zone].
///
/// The custom handler can choose to replace the function [f]
/// with one that does something before, after or instead of calling [f],
/// and then call `parent.scheduleMicrotask(zone, replacement)`.
/// or it can implement its own microtask scheduling queue, which typically
/// still depends on `parent.scheduleMicrotask` to as a way to get started.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef ScheduleMicrotaskHandler =
void Function(Zone self, ZoneDelegate parent, Zone zone, void Function() f);
/// The type of a custom [Zone.createTimer] implementation function.
///
/// A function used as [ZoneSpecification.createTimer]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The callback function [f] and [duration] are the ones which were
/// passed to [Zone.createTimer] of [zone]
/// (possibly through the [Timer] constructor).
///
/// The custom handler can choose to replace the function [f]
/// with one that does something before, after or instead of calling [f],
/// and then call `parent.createTimer(zone, replacement)`.
/// or it can implement its own timer queue, which typically
/// still depends on `parent.createTimer` to as a way to get started.
///
/// The function should return a [Timer] object which can be used
/// to inspect and control the scheduled timer callback.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef CreateTimerHandler =
Timer Function(
Zone self,
ZoneDelegate parent,
Zone zone,
Duration duration,
void Function() f,
);
/// The type of a custom [Zone.createPeriodicTimer] implementation function.
///
/// A function used as [ZoneSpecification.createPeriodicTimer]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The callback function [f] and [period] are the ones which were
/// passed to [Zone.createPeriodicTimer] of [zone]
/// (possibly through the [Timer.periodic] constructor).
///
/// The custom handler can choose to replace the function [f]
/// with one that does something before, after or instead of calling [f],
/// and then call `parent.createTimer(zone, replacement)`.
/// or it can implement its own timer queue, which typically
/// still depends on `parent.createTimer` to as a way to get started.
///
/// The function should return a [Timer] object which can be used
/// to inspect and control the scheduled timer callbacks.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef CreatePeriodicTimerHandler =
Timer Function(
Zone self,
ZoneDelegate parent,
Zone zone,
Duration period,
void Function(Timer timer) f,
);
/// The type of a custom [Zone.print] implementation function.
///
/// A function used as [ZoneSpecification.print]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The string [line] is the one which was passed to [Zone.print] of [zone],
/// (possibly through the global [print] function).
///
/// The custom handler can intercept print operations and
/// redirect them to other targets than the console.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef PrintHandler =
void Function(Zone self, ZoneDelegate parent, Zone zone, String line);
/// The type of a custom [Zone.fork] implementation function.
///
/// A function used as [ZoneSpecification.fork]
/// to specialize the behavior of a new zone.
///
/// Receives the [Zone] that the handler was registered on as [self],
/// a delegate forwarding to the handlers of [self]'s parent zone as [parent],
/// and the current zone where the error was uncaught as [zone],
/// which will have [self] as a parent zone.
///
/// The handler should create a new zone with [zone] as its
/// immediate parent zone.
///
/// The [specification] and [zoneValues] are the ones which were
/// passed to [Zone.fork] of [zone]. They specify the custom zone
/// handlers and zone variables that the new zone should have.
///
/// The custom handler can change the specification or zone
/// values before calling `parent.fork(zone, specification, zoneValues)`,
/// but it has to call the [parent]'s [ZoneDelegate.fork] in order
/// to create a valid [Zone] object.
///
/// The function must only access zone-related functionality through
/// [self], [parent] or [zone].
/// It should not depend on the current zone ([Zone.current]).
typedef ForkHandler =
Zone Function(
Zone self,
ZoneDelegate parent,
Zone zone,
ZoneSpecification? specification,
Map<Object?, Object?>? zoneValues,
);