Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(163)

Side by Side Diff: sdk/lib/async/merge_stream.dart

Issue 12088069: Remove Stream.cyclic/superceding. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/async/async_sources.gypi ('k') | sdk/lib/async/stream.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 part of dart.async;
6
7 class _SupercedeEntry<T> {
8 final _SupercedeStream stream;
9 Stream<T> source;
10 StreamSubscription subscription = null;
11 _SupercedeEntry next;
12
13 _SupercedeEntry(this.stream, this.source, this.next);
14
15 // Whether the source stream is complete.
16 bool get isDone => source == null;
17
18 void onData(T data) {
19 // Stop all lower-priority sources.
20 stream._setData(this, data);
21 }
22
23 void onError(AsyncError error) {
24 stream._signalError(error);
25 }
26
27 void onDone() {
28 subscription = null;
29 source = null;
30 stream._setDone(this);
31 }
32
33 void start() {
34 assert(subscription == null);
35 if (!isDone) {
36 subscription =
37 source.listen(onData, onError: onError, onDone: onDone);
38 }
39 }
40
41 void stop() {
42 if (!isDone) {
43 subscription.cancel();
44 subscription = null;
45 }
46 }
47
48 void pause() {
49 if (!isDone) subscription.pause();
50 }
51
52 void resume() {
53 if (!isDone) subscription.resume();
54 }
55 }
56
57 /**
58 * [Stream] that forwards data from its active source with greatest priority.
59 *
60 * The [_SupercedeStream] gets data from some source [Stream]s which
61 * are ordered in order of increasing priority.
62 * When a higher priority stream provides data, all lower priority streams
63 * are dropped.
64 *
65 * Errors from all (undropped) streams are forwarded.
66 */
67 class _SupercedeStream<T> extends _MultiStreamImpl<T> {
68 _SupercedeEntry _entries = null;
69
70 /**
71 * Create [_SupercedeStream] from the given [sources].
72 *
73 * The [sources] are iterated in order of increasing priority.
74 */
75 _SupercedeStream(Iterable<Stream<T>> sources) {
76 // Set up linked list of sources in decreasing priority order.
77 // The order allows us to drop all lower priority streams when a higher
78 // priority stream provides a value.
79 for (Stream<T> stream in sources) {
80 _entries = new _SupercedeEntry(this, stream, _entries);
81 }
82 }
83
84 void _onSubscriptionStateChange() {
85 if (_hasSubscribers) {
86 for (_SupercedeEntry entry = _entries;
87 entry != null;
88 entry = entry.next) {
89 entry.start();
90 }
91 } else {
92 for (_SupercedeEntry entry = _entries;
93 entry != null;
94 entry = entry.next) {
95 entry.stop();
96 }
97 }
98 }
99
100 void _onPauseStateChange() {
101 if (_isPaused) {
102 for (_SupercedeEntry entry = _entries;
103 entry != null;
104 entry = entry.next) {
105 entry.pause();
106 }
107 } else {
108 for (_SupercedeEntry entry = _entries;
109 entry != null;
110 entry = entry.next) {
111 entry.resume();
112 }
113 }
114 }
115
116 void _setData(_SupercedeEntry entry, T data) {
117 while (entry.next != null) {
118 _SupercedeEntry nextEntry = entry.next;
119 entry.next = null;
120 nextEntry.stop();
121 entry = nextEntry;
122 }
123 _add(data);
124 }
125
126 void _setDone(_SupercedeEntry entry) {
127 if (identical(_entries, entry)) {
128 // Remove the leading completed streams. These are streams
129 // the completed without ever providing data.
130 while (_entries.isDone) {
131 _entries = _entries.next;
132 if (_entries == null) {
133 _close();
134 return;
135 }
136 }
137 }
138 // Otherwise we leave the completed entry in the list and
139 // remove it when a higher priority stream provides data or
140 // all higher priority streams have completed.
141 }
142 }
143
144 /**
145 * Helper class for [_CyclicScheduleStream].
146 *
147 * Used to maintain a list of source streams which are activated in cyclic
148 * order.
149 *
150 * The stream is either unsubscribed, paused or active. Only one stream
151 * will be active at a time. A source is not subscribed until it's first
152 * activated.
153 *
154 * If the source completes, the entry is removed from [stream].
155 */
156 class _CycleEntry<T> {
157 final _CyclicScheduleStream stream;
158 /** A single source stream for the [_CyclicScheduleStream]. */
159 Stream source;
160 /** The active subscription, if any. */
161 StreamSubscription subscription = null;
162 /** Whether the subscription is currently paused. */
163 bool isPaused = false;
164 /** Next entry in a linked list of entries. */
165 _CycleEntry next;
166
167 _CycleEntry(this.stream, this.source);
168
169 void cancel() {
170 // This method may be called even if this entry has never been activated.
171 if (subscription != null) {
172 subscription.cancel();
173 subscription = null;
174 isPaused = false;
175 }
176 }
177
178 void pause() {
179 ensureSubscribed();
180 if (!isPaused) {
181 subscription.pause();
182 isPaused = true;
183 }
184 }
185
186 void activate() {
187 ensureSubscribed();
188 if (isPaused) {
189 isPaused = false;
190 subscription.resume();
191 }
192 }
193
194 void ensureSubscribed() {
195 if (subscription == null) {
196 subscription =
197 source.listen(stream._onData,
198 onError: stream._signalError,
199 onDone: stream._onDone);
200 }
201 }
202 }
203
204 /**
205 * [Stream] that schedules events from multiple sources in cyclic order.
206 *
207 * The source streams are activated and paused so that only one data event
208 * is generated at a time, and those data events are output on this stream.
209 *
210 * Error events from the currently active stream are forwarded without
211 * changing the schedule. When a source stream ends, it is removed from
212 * the schedule.
213 */
214 class _CyclicScheduleStream<T> extends _MultiStreamImpl<T> {
215 _CycleEntry _currentEntry = null;
216 _CycleEntry _lastEntry = null;
217
218 /**
219 * Create a [Stream] that provides data from [sources] one event at a time.
220 *
221 * The data are provided as one event from each stream in the order they are
222 * given by the [Iterable], and then cycling as long as there are data.
223 */
224 _CyclicScheduleStream(Iterable<Stream<T>> sources) {
225 _CycleEntry entry = null;
226 for (Stream<T> source in sources) {
227 _CycleEntry newEntry = new _CycleEntry(this, source);
228 if (_lastEntry == null) {
229 _currentEntry = _lastEntry = newEntry;
230 } else {
231 _lastEntry = _lastEntry.next = newEntry;
232 }
233 }
234 if (_currentEntry == null) {
235 _close();
236 }
237 }
238
239 void _onSubscriptionStateChange() {
240 if (_hasSubscribers) {
241 _currentEntry.activate();
242 for (_CycleEntry entry = _currentEntry.next;
243 entry != null;
244 entry = entry.next) {
245 entry.pause();
246 }
247 return;
248 }
249 for (_CycleEntry entry = _currentEntry; entry != null; entry = entry.next) {
250 entry.cancel();
251 }
252 }
253
254 void _onPauseStateChange() {
255 if (_isPaused) {
256 _currentEntry.pause();
257 } else {
258 _currentEntry.activate();
259 }
260 }
261
262 void _onData(T data) {
263 if (_currentEntry.next != null) {
264 _currentEntry.pause();
265 _add(data);
266 // Move the current entry to the end of the list.
267 _lastEntry = _lastEntry.next = _currentEntry;
268 _currentEntry = _currentEntry.next;
269 _lastEntry.next = null;
270 _currentEntry.activate();
271 } else {
272 // No pausing with only one entry left.
273 _add(data);
274 }
275 }
276
277 void _onDone() {
278 if (_currentEntry.next == null) {
279 _close();
280 _currentEntry = _lastEntry = null;
281 } else {
282 // Remove the current entry from the list now that it's complete.
283 _currentEntry = _currentEntry.next;
284 _currentEntry.activate();
285 }
286 }
287 }
OLDNEW
« no previous file with comments | « sdk/lib/async/async_sources.gypi ('k') | sdk/lib/async/stream.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698