| // Copyright (c) 2017, 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. |
| |
| import 'dart:async'; |
| |
| import 'recording.dart'; |
| import 'result_reference.dart'; |
| |
| /// Base class for recordable file system invocation events. |
| /// |
| /// Instances of this class will be aggregated in a [Recording] |
| abstract class InvocationEvent<T> { |
| /// The object on which the invocation occurred. Will always be non-null. |
| Object get object; |
| |
| /// The return value of the invocation. This may be null (and will always be |
| /// `null` for setters). |
| T get result; |
| |
| /// The stopwatch value (in milliseconds) when the invocation occurred. |
| /// |
| /// This value is recorded when the invocation first occurs, not when the |
| /// delegate returns. |
| int get timestamp; |
| } |
| |
| /// A recordable invocation of a property getter on a file system object. |
| abstract class PropertyGetEvent<T> extends InvocationEvent<T> { |
| /// The property that was retrieved. |
| Symbol get property; |
| } |
| |
| /// A recordable invocation of a property setter on a file system object. |
| abstract class PropertySetEvent<T> extends InvocationEvent<Null> { |
| /// The property that was set. |
| /// |
| /// All setter property symbols will have a trailing equals sign. For example, |
| /// if the `foo` property was set, this value will be a symbol of `foo=`. |
| Symbol get property; |
| |
| /// The value to which [property] was set. This is distinct from [result], |
| /// which is always `null` for setters. |
| T get value; |
| } |
| |
| /// A recordable invocation of a method on a file system object. |
| abstract class MethodEvent<T> extends InvocationEvent<T> { |
| /// The method that was invoked. |
| Symbol get method; |
| |
| /// The positional arguments that were passed to the method. |
| List<dynamic> get positionalArguments; |
| |
| /// The named arguments that were passed to the method. |
| Map<Symbol, dynamic> get namedArguments; |
| } |
| |
| /// An [InvocationEvent] that's in the process of being recorded. |
| abstract class LiveInvocationEvent<T> implements InvocationEvent<T> { |
| /// Creates a new `LiveInvocationEvent`. |
| LiveInvocationEvent(this.object, this._result, this.timestamp); |
| |
| final dynamic _result; |
| |
| @override |
| final Object object; |
| |
| @override |
| T get result { |
| dynamic result = _result; |
| while (result is ResultReference) { |
| ResultReference<dynamic> reference = result; |
| result = reference.recordedValue; |
| } |
| return result; |
| } |
| |
| @override |
| final int timestamp; |
| |
| /// A [Future] that completes once [result] is ready for serialization. |
| /// |
| /// If [result] is a [Future], this future completes when [result] completes. |
| /// If [result] is a [Stream], this future completes when the stream sends a |
| /// "done" event. If [result] is neither a future nor a stream, this future |
| /// completes immediately. |
| /// |
| /// It is legal for [serialize] to be called before this future completes, |
| /// but doing so will cause incomplete results to be serialized. Results that |
| /// are unfinished futures will be serialized as `null`, and results that are |
| /// unfinished streams will be serialized as the data that has been received |
| /// thus far. |
| Future<Null> get done async { |
| dynamic result = _result; |
| while (result is ResultReference) { |
| ResultReference<dynamic> reference = result; |
| await reference.complete; |
| result = reference.recordedValue; |
| } |
| } |
| |
| /// Returns this event as a JSON-serializable object. |
| Map<String, dynamic> serialize() => <String, dynamic>{ |
| 'object': object, |
| 'result': _result, |
| 'timestamp': timestamp, |
| }; |
| |
| @override |
| String toString() => serialize().toString(); |
| } |
| |
| /// A [PropertyGetEvent] that's in the process of being recorded. |
| class LivePropertyGetEvent<T> extends LiveInvocationEvent<T> |
| implements PropertyGetEvent<T> { |
| /// Creates a new `LivePropertyGetEvent`. |
| LivePropertyGetEvent(Object object, this.property, T result, int timestamp) |
| : super(object, result, timestamp); |
| |
| @override |
| final Symbol property; |
| |
| @override |
| Map<String, dynamic> serialize() => <String, dynamic>{ |
| 'type': 'get', |
| 'property': property, |
| }..addAll(super.serialize()); |
| } |
| |
| /// A [PropertySetEvent] that's in the process of being recorded. |
| class LivePropertySetEvent<T> extends LiveInvocationEvent<Null> |
| implements PropertySetEvent<T> { |
| /// Creates a new `LivePropertySetEvent`. |
| LivePropertySetEvent(Object object, this.property, this.value, int timestamp) |
| : super(object, null, timestamp); |
| |
| @override |
| final Symbol property; |
| |
| @override |
| final T value; |
| |
| @override |
| Map<String, dynamic> serialize() => <String, dynamic>{ |
| 'type': 'set', |
| 'property': property, |
| 'value': value, |
| }..addAll(super.serialize()); |
| } |
| |
| /// A [MethodEvent] that's in the process of being recorded. |
| class LiveMethodEvent<T> extends LiveInvocationEvent<T> |
| implements MethodEvent<T> { |
| /// Creates a new `LiveMethodEvent`. |
| LiveMethodEvent( |
| Object object, |
| this.method, |
| List<dynamic> positionalArguments, |
| Map<Symbol, dynamic> namedArguments, |
| T result, |
| int timestamp, |
| ) |
| : this.positionalArguments = |
| new List<dynamic>.unmodifiable(positionalArguments), |
| this.namedArguments = |
| new Map<Symbol, dynamic>.unmodifiable(namedArguments), |
| super(object, result, timestamp); |
| |
| @override |
| final Symbol method; |
| |
| @override |
| final List<dynamic> positionalArguments; |
| |
| @override |
| final Map<Symbol, dynamic> namedArguments; |
| |
| @override |
| Map<String, dynamic> serialize() => <String, dynamic>{ |
| 'type': 'invoke', |
| 'method': method, |
| 'positionalArguments': positionalArguments, |
| 'namedArguments': namedArguments, |
| }..addAll(super.serialize()); |
| } |