Line data Source code
1 : // Copyright (c) 2016, 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 : import 'dart:async';
6 :
7 : /// A [StreamSink] that discards all events.
8 : ///
9 : /// The sink silently drops events until [close] is called, at which point it
10 : /// throws [StateError]s when events are added. This is the same behavior as a
11 : /// sink whose remote end has closed, such as when a [WebSocket] connection has
12 : /// been closed.
13 : ///
14 : /// This can be used when a sink is needed but no events are actually intended
15 : /// to be added. The [new NullStreamSink.error] constructor can be used to
16 : /// represent errors when creating a sink, since [StreamSink.done] exposes sink
17 : /// errors. For example:
18 : ///
19 : /// ```dart
20 : /// StreamSink<List<int>> openForWrite(String filename) {
21 : /// try {
22 : /// return new RandomAccessSink(new File(filename).openSync());
23 : /// } on IOException catch (error, stackTrace) {
24 : /// return new NullStreamSink.error(error, stackTrace);
25 : /// }
26 : /// }
27 : /// ```
28 : class NullStreamSink<T> implements StreamSink<T> {
29 : final Future done;
30 :
31 : /// Whether the sink has been closed.
32 : var _closed = false;
33 :
34 : /// Whether an [addStream] call is pending.
35 : ///
36 : /// We don't actually add any events from streams, but it does return the
37 : /// [StreamSubscription.cancel] future so to be [StreamSink]-complaint we
38 : /// reject events until that completes.
39 : var _addingStream = false;
40 :
41 : /// Creates a null sink.
42 : ///
43 : /// If [done] is passed, it's used as the [Sink.done] future. Otherwise, a
44 : /// completed future is used.
45 0 : NullStreamSink({Future done}) : done = done ?? new Future.value();
46 :
47 : /// Creates a null sink whose [done] future emits [error].
48 : ///
49 : /// Note that this error will not be considered uncaught.
50 : NullStreamSink.error(error, [StackTrace stackTrace])
51 0 : : done = new Future.error(error, stackTrace)
52 : // Don't top-level the error. This gives the user a change to call
53 : // [close] or [done], and matches the behavior of a remote endpoint
54 : // experiencing an error.
55 0 : ..catchError((_) {});
56 :
57 : void add(T data) {
58 0 : _checkEventAllowed();
59 : }
60 :
61 : void addError(error, [StackTrace stackTrace]) {
62 0 : _checkEventAllowed();
63 : }
64 :
65 : Future addStream(Stream<T> stream) {
66 0 : _checkEventAllowed();
67 :
68 0 : _addingStream = true;
69 0 : var future = stream.listen(null).cancel() ?? new Future.value();
70 0 : return future.whenComplete(() {
71 0 : _addingStream = false;
72 : });
73 : }
74 :
75 : /// Throws a [StateError] if [close] has been called or an [addStream] call is
76 : /// pending.
77 : void _checkEventAllowed() {
78 0 : if (_closed) throw new StateError("Cannot add to a closed sink.");
79 0 : if (_addingStream) {
80 0 : throw new StateError("Cannot add to a sink while adding a stream.");
81 : }
82 : }
83 :
84 : Future close() {
85 0 : _closed = true;
86 0 : return done;
87 : }
88 : }
|