OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library event_helper; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 abstract class Event { | |
10 void replay(EventSink sink); | |
11 } | |
12 | |
13 class DataEvent implements Event { | |
14 final data; | |
15 | |
16 DataEvent(this.data); | |
17 | |
18 void replay(EventSink sink) { | |
19 sink.add(data); | |
20 } | |
21 | |
22 int get hashCode => data.hashCode; | |
23 | |
24 bool operator ==(Object other) { | |
25 if (other is! DataEvent) return false; | |
26 DataEvent otherEvent = other; | |
27 return data == otherEvent.data; | |
28 } | |
29 | |
30 String toString() => "DataEvent: $data"; | |
31 } | |
32 | |
33 class ErrorEvent implements Event { | |
34 final error; | |
35 | |
36 ErrorEvent(this.error); | |
37 | |
38 void replay(EventSink sink) { | |
39 sink.addError(error); | |
40 } | |
41 | |
42 int get hashCode => error.error.hashCode; | |
43 | |
44 bool operator ==(Object other) { | |
45 if (other is! ErrorEvent) return false; | |
46 ErrorEvent otherEvent = other; | |
47 return error == otherEvent.error; | |
48 } | |
49 | |
50 String toString() => "ErrorEvent: ${error}"; | |
51 } | |
52 | |
53 class DoneEvent implements Event { | |
54 const DoneEvent(); | |
55 | |
56 void replay(EventSink sink) { | |
57 sink.close(); | |
58 } | |
59 | |
60 int get hashCode => 42; | |
61 | |
62 bool operator ==(Object other) => other is DoneEvent; | |
63 | |
64 String toString() => "DoneEvent"; | |
65 } | |
66 | |
67 /** Collector of events. */ | |
68 class Events implements EventSink { | |
69 final List<Event> events = []; | |
70 bool trace = false; | |
71 Completer onDoneSignal = new Completer(); | |
72 | |
73 Events(); | |
74 | |
75 Events.fromIterable(Iterable iterable) { | |
76 for (var value in iterable) add(value); | |
77 close(); | |
78 } | |
79 | |
80 /** Capture events from a stream into a new [Events] object. */ | |
81 factory Events.capture(Stream stream, {bool cancelOnError}) = CaptureEvents; | |
82 | |
83 // EventSink interface. | |
84 void add(var value) { | |
85 if (trace) print("Events#$hashCode: add($value)"); | |
86 events.add(new DataEvent(value)); | |
87 } | |
88 | |
89 void addError(error, [StackTrace stackTrace]) { | |
90 if (trace) print("Events#$hashCode: addError($error)"); | |
91 events.add(new ErrorEvent(error)); | |
92 } | |
93 | |
94 void close() { | |
95 if (trace) print("Events#$hashCode: close()"); | |
96 events.add(const DoneEvent()); | |
97 onDoneSignal.complete(); | |
98 } | |
99 | |
100 /** | |
101 * Error shorthand, for writing events manually. | |
102 */ | |
103 void error(var value, [StackTrace stackTrace]) { | |
104 addError(value, stackTrace); | |
105 } | |
106 | |
107 /** Replay the captured events on a sink. */ | |
108 void replay(EventSink sink) { | |
109 for (int i = 0; i < events.length; i++) { | |
110 events[i].replay(sink); | |
111 } | |
112 } | |
113 | |
114 /** | |
115 * Create a new [Events] with the same captured events. | |
116 * | |
117 * This does not copy a subscription. | |
118 */ | |
119 Events copy() { | |
120 Events result = new Events(); | |
121 replay(result); | |
122 return result; | |
123 } | |
124 | |
125 // Operations that only work when there is a subscription feeding the Events. | |
126 | |
127 /** | |
128 * Pauses the subscription that feeds this [Events]. | |
129 * | |
130 * Should only be used when there is a subscription. That is, after a | |
131 * call to [subscribeTo]. | |
132 */ | |
133 void pause([Future resumeSignal]) { | |
134 throw new StateError("Not capturing events."); | |
135 } | |
136 | |
137 /** Resumes after a call to [pause]. */ | |
138 void resume() { | |
139 throw new StateError("Not capturing events."); | |
140 } | |
141 | |
142 /** | |
143 * Sets an action to be called when this [Events] receives a 'done' event. | |
144 * | |
145 * The action will also be called if capturing events from a stream with | |
146 * `cancelOnError` set to true and receiving an error. | |
147 */ | |
148 void onDone(void action()) { | |
149 onDoneSignal.future.whenComplete(action); | |
150 } | |
151 } | |
152 | |
153 class CaptureEvents extends Events { | |
154 StreamSubscription subscription; | |
155 bool cancelOnError = false; | |
156 | |
157 CaptureEvents(Stream stream, {bool cancelOnError: false}) { | |
158 this.cancelOnError = cancelOnError; | |
159 subscription = stream.listen(add, | |
160 onError: addError, onDone: close, cancelOnError: cancelOnError); | |
161 } | |
162 | |
163 void addError(error, [stackTrace]) { | |
164 super.addError(error, stackTrace); | |
165 if (cancelOnError) { | |
166 onDoneSignal.complete(); | |
167 } | |
168 } | |
169 | |
170 void pause([Future resumeSignal]) { | |
171 if (trace) print("Events#$hashCode: pause"); | |
172 subscription.pause(resumeSignal); | |
173 } | |
174 | |
175 void resume() { | |
176 if (trace) print("Events#$hashCode: resume"); | |
177 subscription.resume(); | |
178 } | |
179 | |
180 void onDone(void action()) { | |
181 if (trace) print("Events#$hashCode: onDone"); | |
182 super.onDone(action); | |
183 } | |
184 } | |
OLD | NEW |