|  | // Copyright (c) 2012, 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.core; | 
|  |  | 
|  | // Examples can assume: | 
|  | // class DBConnection { | 
|  | //   DBConnection._(); | 
|  | //   factory DBConnection.connect() => DBConnection._(); | 
|  | //   void close() {} | 
|  | // } | 
|  |  | 
|  | /// An [Expando] allows adding new properties to objects. | 
|  | /// | 
|  | /// Does not work on numbers, strings, booleans, records, `null`, | 
|  | /// `dart:ffi` pointers, `dart:ffi` structs, or `dart:ffi` unions. | 
|  | /// | 
|  | /// An `Expando` does not hold on to the added property value after an object | 
|  | /// becomes inaccessible. | 
|  | /// | 
|  | /// Since you can always create a new number that is identical to an existing | 
|  | /// number, it means that an expando property on a number could never be | 
|  | /// released. To avoid this, expando properties cannot be added to numbers. | 
|  | /// The same argument applies to strings, booleans and `null`, which also have | 
|  | /// literals that evaluate to identical values when they occur more than once. | 
|  | /// In addition, expando properties can not be added to records because | 
|  | /// records do not have a well-defined persistent identity. | 
|  | /// | 
|  | /// There is no restriction on other classes, even for compile time constant | 
|  | /// objects. Be careful if adding expando properties to compile time constants, | 
|  | /// since they will stay alive forever. | 
|  | final class Expando<T extends Object> { | 
|  | /// The name of the this [Expando] as passed to the constructor. | 
|  | /// | 
|  | /// If no name was passed to the constructor, the value is the `null` value. | 
|  | final String? name; | 
|  |  | 
|  | /// Creates a new [Expando]. The optional name is only used for | 
|  | /// debugging purposes and creating two different [Expando]s with the | 
|  | /// same name yields two [Expando]s that work on different properties | 
|  | /// of the objects they are used on. | 
|  | external Expando([String? name]); | 
|  |  | 
|  | /// Expando toString method override. | 
|  | String toString() => "Expando:$name"; | 
|  |  | 
|  | /// Gets the value of this [Expando]'s property on the given object. | 
|  | /// | 
|  | /// If the object hasn't been expanded, the result is the `null` value. | 
|  | /// | 
|  | /// The object must not be a number, a string, a boolean, a record, `null`, | 
|  | /// a `dart:ffi` pointer, a `dart:ffi` struct, or a `dart:ffi` union. | 
|  | external T? operator [](Object object); | 
|  |  | 
|  | /// Sets this [Expando]'s property value on the given object to [value]. | 
|  | /// | 
|  | /// Properties can effectively be removed again | 
|  | /// by setting their value to `null`. | 
|  | /// | 
|  | /// The object must not be a number, a string, a boolean, a record, `null`, | 
|  | /// a `dart:ffi` pointer, a `dart:ffi` struct, or a `dart:ffi` union. | 
|  | external void operator []=(Object object, T? value); | 
|  | } | 
|  |  | 
|  | /// A weak reference to a Dart object. | 
|  | /// | 
|  | /// A _weak_ reference to the [target] object which may be cleared | 
|  | /// (set to reference `null` instead) at any time | 
|  | /// when there is no other way for the program to access the target object. | 
|  | /// | 
|  | /// _Being the target of a weak reference does not keep an object | 
|  | /// from being garbage collected._ | 
|  | /// | 
|  | /// There are no guarantees that a weak reference will ever be cleared | 
|  | /// even if all references to its target are weak references. | 
|  | /// | 
|  | /// Not all objects are supported as targets for weak references. | 
|  | /// The [WeakReference] constructor will reject any object that is not | 
|  | /// supported as an [Expando] key. | 
|  | /// | 
|  | /// Use-cases like caching can benefit from using weak references. Example: | 
|  | /// | 
|  | /// ```dart | 
|  | /// /// [CachedComputation] caches the computation result, weakly holding | 
|  | /// /// on to the cache. | 
|  | /// /// | 
|  | /// /// If nothing else in the program is holding on the result, and the | 
|  | /// /// garbage collector runs, the cache is purged, freeing the memory. | 
|  | /// /// | 
|  | /// /// Until the cache is purged, the computation will not run again on | 
|  | /// /// a subsequent request. | 
|  | /// /// | 
|  | /// /// Example use: | 
|  | /// /// ``` | 
|  | /// /// final cached = CachedComputation( | 
|  | /// ///     () => jsonDecode(someJsonSource) as Object); | 
|  | /// /// print(cached.result); // Executes computation. | 
|  | /// /// print(cached.result); // Most likely uses cache. | 
|  | /// /// ``` | 
|  | /// class CachedComputation<R extends Object> { | 
|  | ///   final R Function() computation; | 
|  | /// | 
|  | ///   WeakReference<R>? _cache; | 
|  | /// | 
|  | ///   CachedComputation(this.computation); | 
|  | /// | 
|  | ///   R get result { | 
|  | ///     final cachedResult = _cache?.target; | 
|  | ///     if (cachedResult != null) { | 
|  | ///       return cachedResult; | 
|  | ///     } | 
|  | /// | 
|  | ///     final result = computation(); | 
|  | /// | 
|  | ///     // WeakReferences do not support nulls, bools, numbers, and strings. | 
|  | ///     if (result is! bool && result is! num && result is! String) { | 
|  | ///       _cache = WeakReference(result); | 
|  | ///     } | 
|  | /// | 
|  | ///     return result; | 
|  | ///   } | 
|  | /// } | 
|  | /// ``` | 
|  | @Since("2.17") | 
|  | abstract final class WeakReference<T extends Object> { | 
|  | /// Creates a [WeakReference] pointing to the given [target]. | 
|  | /// | 
|  | /// The [target] must be an object supported as an [Expando] key, | 
|  | /// which means [target] cannot be a number, a string, a boolean, a record, | 
|  | /// the `null` value, or certain other types of special objects. | 
|  | external factory WeakReference(T target); | 
|  |  | 
|  | /// The current object weakly referenced by this [WeakReference], if any. | 
|  | /// | 
|  | /// The value is either the object supplied in the constructor, | 
|  | /// or `null` if the weak reference has been cleared. | 
|  | T? get target; | 
|  | } | 
|  |  | 
|  | /// A finalizer which can be attached to Dart objects. | 
|  | /// | 
|  | /// A finalizer can create attachments between | 
|  | /// the finalizer and any number of Dart values, | 
|  | /// by calling [attach] with the value, along with a | 
|  | /// _finalization token_ and an optional _attach key_, | 
|  | /// which are part of the attachment. | 
|  | /// | 
|  | /// When a Dart value becomes inaccessible to the program, | 
|  | /// any finalizer that currently has an attachment to | 
|  | /// the value *may* have its callback function called | 
|  | /// with the attachment's finalization token. | 
|  | /// | 
|  | /// Example: | 
|  | /// ```dart | 
|  | /// class Database { | 
|  | ///   // Keeps the finalizer itself reachable, otherwise it might be disposed | 
|  | ///   // before the finalizer callback gets a chance to run. | 
|  | ///   static final Finalizer<DBConnection> _finalizer = | 
|  | ///       Finalizer((connection) => connection.close()); | 
|  | /// | 
|  | ///   final DBConnection _connection; | 
|  | /// | 
|  | ///   Database._fromConnection(this._connection); | 
|  | /// | 
|  | ///   factory Database.connect() { | 
|  | ///     // Wraps the connection in a nice user API, | 
|  | ///     // *and* closes connection if the user forgets to. | 
|  | ///     final connection = DBConnection.connect(); | 
|  | ///     final wrapper = Database._fromConnection(connection); | 
|  | ///     // Calls finalizer callback when `wrapper` is no longer reachable. | 
|  | ///     _finalizer.attach(wrapper, connection, detach: wrapper); | 
|  | ///     return wrapper; | 
|  | ///   } | 
|  | /// | 
|  | ///   void close() { | 
|  | ///     // User requested close. | 
|  | ///     _connection.close(); | 
|  | ///     // Detach from finalizer, no longer needed. | 
|  | ///     _finalizer.detach(this); | 
|  | ///   } | 
|  | /// | 
|  | ///   // Some useful methods. | 
|  | /// } | 
|  | /// ``` | 
|  | /// This example has an example of an external resource that needs clean-up. | 
|  | /// The finalizer is used to clean up an external connection when the | 
|  | /// user of the API no longer has access to that connection. | 
|  | /// The example uses the same object as attached object and detach key, | 
|  | /// which is a useful approach when each attached object can be detached | 
|  | /// individually. Being a detachment key doesn't keep an object alive. | 
|  | /// | 
|  | /// No promises are made that the callback will ever be called. | 
|  | /// The only thing that is guaranteed is that if a finalizer's callback | 
|  | /// is called with a specific finalization token as argument, | 
|  | /// then at least one value with an attachment to the finalizer | 
|  | /// that has that finalization token, | 
|  | /// is no longer accessible to the program. | 
|  | /// | 
|  | /// If the finalizer *itself* becomes unreachable, | 
|  | /// it's allowed to be garbage collected | 
|  | /// and then it won't trigger any further callbacks. | 
|  | /// Always make sure to keep the finalizer itself reachable while it's needed. | 
|  | /// | 
|  | /// If multiple finalizers are attached to a single object, | 
|  | /// or the same finalizer is attached multiple times to an object, | 
|  | /// and that object becomes inaccessible to the program, | 
|  | /// then any number (including zero) of those attachments may trigger | 
|  | /// their associated finalizer's callback. | 
|  | /// It will not necessarily be all or none of them. | 
|  | /// | 
|  | /// Finalization callbacks will happen as *events*. | 
|  | /// They will not happen during execution of other code, | 
|  | /// and not as a microtask, | 
|  | /// but as high-level events similar to timer events. | 
|  | /// | 
|  | /// Finalization callbacks must not throw. | 
|  | /// | 
|  | /// When running on the Dart native runtime, and the callback is a native | 
|  | /// function rather than a Dart function, use `dart:ffi`'s [NativeFinalizer] | 
|  | /// instead. | 
|  | @Since("2.17") | 
|  | abstract final class Finalizer<T> { | 
|  | /// Creates a finalizer with the given finalization callback. | 
|  | /// | 
|  | /// The [callback] is bound to the current zone | 
|  | /// when the [Finalizer] is created, and will run in that zone when called. | 
|  | external factory Finalizer(void Function(T) callback); | 
|  |  | 
|  | /// Attaches this finalizer to [value]. | 
|  | /// | 
|  | /// When [value] is no longer accessible to the program, | 
|  | /// while still having an attachment to this finalizer, | 
|  | /// the callback of this finalizer *may* be called | 
|  | /// with [finalizationToken] as argument. | 
|  | /// The callback may be called at most once per active attachment, | 
|  | /// ones which have not been detached by calling [Finalizer.detach]. | 
|  | /// | 
|  | /// The [detach] value is only used by the finalizer to identify the current | 
|  | /// attachment. If a non-`null` [detach] value is provided, the same | 
|  | /// (identical) value can be passed to [Finalizer.detach] to remove the | 
|  | /// attachment. If no (non-`null`) value is provided, the attachment cannot | 
|  | /// be removed again. | 
|  | /// | 
|  | /// The [value] and [detach] arguments do not count towards those | 
|  | /// objects being accessible to the program. | 
|  | /// Both must be objects supported as an [Expando] key. | 
|  | /// They may be the *same* object. | 
|  | /// | 
|  | /// Example: | 
|  | /// ```dart | 
|  | /// class Database { | 
|  | ///   // Keeps the finalizer itself reachable, otherwise it might be disposed | 
|  | ///   // before the finalizer callback gets a chance to run. | 
|  | ///   static final Finalizer<DBConnection> _finalizer = | 
|  | ///       Finalizer((connection) => connection.close()); | 
|  | /// | 
|  | ///   factory Database.connect() { | 
|  | ///     // Wraps the connection in a nice user API, | 
|  | ///     // *and* closes connection if the user forgets to. | 
|  | ///     final connection = DBConnection.connect(); | 
|  | ///     final wrapper = Database._fromConnection(); | 
|  | ///     // Calls finalizer callback when `wrapper` is no longer reachable. | 
|  | ///     _finalizer.attach(wrapper, connection, detach: wrapper); | 
|  | ///     return wrapper; | 
|  | ///   } | 
|  | /// | 
|  | ///   Database._fromConnection(); | 
|  | /// | 
|  | ///   // Some useful methods. | 
|  | /// } | 
|  | /// ``` | 
|  | /// | 
|  | /// Multiple objects may be attached using the same finalization token, | 
|  | /// and the finalizer can be attached multiple times to the same object | 
|  | /// with different, or the same, finalization token. | 
|  | void attach(Object value, T finalizationToken, {Object? detach}); | 
|  |  | 
|  | /// Detaches this finalizer from values attached with [detach]. | 
|  | /// | 
|  | /// Each attachment between this finalizer and a value, | 
|  | /// which was created by calling [attach] with the [detach] object as | 
|  | /// `detach` argument, is removed. | 
|  | /// | 
|  | /// If the finalizer was attached multiple times to the same value | 
|  | /// with different detachment keys, | 
|  | /// only those attachments which used [detach] are removed. | 
|  | /// | 
|  | /// After detaching, an attachment won't cause any callbacks to happen | 
|  | /// if the object become inaccessible. | 
|  | /// | 
|  | /// Example: | 
|  | /// ```dart | 
|  | /// class Database { | 
|  | ///   // Keeps the finalizer itself reachable, otherwise it might be disposed | 
|  | ///   // before the finalizer callback gets a chance to run. | 
|  | ///   static final Finalizer<DBConnection> _finalizer = | 
|  | ///       Finalizer((connection) => connection.close()); | 
|  | /// | 
|  | ///   final DBConnection _connection; | 
|  | /// | 
|  | ///   Database._fromConnection(this._connection); | 
|  | /// | 
|  | ///   void close() { | 
|  | ///     // User requested close. | 
|  | ///     _connection.close(); | 
|  | ///     // Detach from finalizer, no longer needed. | 
|  | ///     // Was attached using this object as `detach` token. | 
|  | ///     _finalizer.detach(this); | 
|  | ///   } | 
|  | /// | 
|  | ///   // Some useful methods. | 
|  | /// } | 
|  | /// ``` | 
|  | void detach(Object detach); | 
|  | } |