mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:21:07 +00:00
5642199dd0
Change-Id: I35bb926e53e92fd02e264fb5b14feadf063fb8db Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/257961 Reviewed-by: Michael Thomsen <mit@google.com> Commit-Queue: Lasse Nielsen <lrn@google.com>
185 lines
4.2 KiB
Dart
185 lines
4.2 KiB
Dart
// 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.
|
|
|
|
library event_helper;
|
|
|
|
import 'dart:async';
|
|
|
|
abstract class Event {
|
|
void replay(EventSink sink);
|
|
}
|
|
|
|
class DataEvent implements Event {
|
|
final data;
|
|
|
|
DataEvent(this.data);
|
|
|
|
void replay(EventSink sink) {
|
|
sink.add(data);
|
|
}
|
|
|
|
int get hashCode => data.hashCode;
|
|
|
|
bool operator ==(Object other) {
|
|
if (other is! DataEvent) return false;
|
|
DataEvent otherEvent = other;
|
|
return data == otherEvent.data;
|
|
}
|
|
|
|
String toString() => "DataEvent: $data";
|
|
}
|
|
|
|
class ErrorEvent implements Event {
|
|
final error;
|
|
|
|
ErrorEvent(this.error);
|
|
|
|
void replay(EventSink sink) {
|
|
sink.addError(error);
|
|
}
|
|
|
|
int get hashCode => error.error.hashCode;
|
|
|
|
bool operator ==(Object other) {
|
|
if (other is! ErrorEvent) return false;
|
|
ErrorEvent otherEvent = other;
|
|
return error == otherEvent.error;
|
|
}
|
|
|
|
String toString() => "ErrorEvent: ${error}";
|
|
}
|
|
|
|
class DoneEvent implements Event {
|
|
const DoneEvent();
|
|
|
|
void replay(EventSink sink) {
|
|
sink.close();
|
|
}
|
|
|
|
int get hashCode => 42;
|
|
|
|
bool operator ==(Object other) => other is DoneEvent;
|
|
|
|
String toString() => "DoneEvent";
|
|
}
|
|
|
|
/** Collector of events. */
|
|
class Events implements EventSink {
|
|
final List<Event> events = [];
|
|
bool trace = false;
|
|
Completer onDoneSignal = new Completer();
|
|
|
|
Events();
|
|
|
|
Events.fromIterable(Iterable iterable) {
|
|
for (var value in iterable) add(value);
|
|
close();
|
|
}
|
|
|
|
/** Capture events from a stream into a new [Events] object. */
|
|
factory Events.capture(Stream stream, {bool cancelOnError}) = CaptureEvents;
|
|
|
|
// EventSink interface.
|
|
void add(var value) {
|
|
if (trace) print("Events#$hashCode: add($value)");
|
|
events.add(new DataEvent(value));
|
|
}
|
|
|
|
void addError(error, [StackTrace? stackTrace]) {
|
|
if (trace) print("Events#$hashCode: addError($error)");
|
|
events.add(new ErrorEvent(error));
|
|
}
|
|
|
|
void close() {
|
|
if (trace) print("Events#$hashCode: close()");
|
|
events.add(const DoneEvent());
|
|
onDoneSignal.complete();
|
|
}
|
|
|
|
/**
|
|
* Error shorthand, for writing events manually.
|
|
*/
|
|
void error(var value, [StackTrace? stackTrace]) {
|
|
addError(value, stackTrace);
|
|
}
|
|
|
|
/** Replay the captured events on a sink. */
|
|
void replay(EventSink sink) {
|
|
for (int i = 0; i < events.length; i++) {
|
|
events[i].replay(sink);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new [Events] with the same captured events.
|
|
*
|
|
* This does not copy a subscription.
|
|
*/
|
|
Events copy() {
|
|
Events result = new Events();
|
|
replay(result);
|
|
return result;
|
|
}
|
|
|
|
// Operations that only work when there is a subscription feeding the Events.
|
|
|
|
/**
|
|
* Pauses the subscription that feeds this [Events].
|
|
*
|
|
* Should only be used when there is a subscription. That is, after a
|
|
* call to [subscribeTo].
|
|
*/
|
|
void pause([Future? resumeSignal]) {
|
|
throw new StateError("Not capturing events.");
|
|
}
|
|
|
|
/** Resumes after a call to [pause]. */
|
|
void resume() {
|
|
throw new StateError("Not capturing events.");
|
|
}
|
|
|
|
/**
|
|
* Sets an action to be called when this [Events] receives a 'done' event.
|
|
*
|
|
* The action will also be called if capturing events from a stream with
|
|
* `cancelOnError` set to true and receiving an error.
|
|
*/
|
|
void onDone(void action()) {
|
|
onDoneSignal.future.whenComplete(action);
|
|
}
|
|
}
|
|
|
|
class CaptureEvents extends Events {
|
|
late StreamSubscription subscription;
|
|
bool cancelOnError = false;
|
|
|
|
CaptureEvents(Stream stream, {bool cancelOnError = false}) {
|
|
this.cancelOnError = cancelOnError;
|
|
subscription = stream.listen(add,
|
|
onError: addError, onDone: close, cancelOnError: cancelOnError);
|
|
}
|
|
|
|
void addError(error, [StackTrace? stackTrace]) {
|
|
super.addError(error, stackTrace);
|
|
if (cancelOnError) {
|
|
onDoneSignal.complete();
|
|
}
|
|
}
|
|
|
|
void pause([Future? resumeSignal]) {
|
|
if (trace) print("Events#$hashCode: pause");
|
|
subscription.pause(resumeSignal);
|
|
}
|
|
|
|
void resume() {
|
|
if (trace) print("Events#$hashCode: resume");
|
|
subscription.resume();
|
|
}
|
|
|
|
void onDone(void action()) {
|
|
if (trace) print("Events#$hashCode: onDone");
|
|
super.onDone(action);
|
|
}
|
|
}
|