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 [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 RandomAccessSink(File(filename).openSync()); 23 : /// } on IOException catch (error, stackTrace) { 24 : /// return NullStreamSink.error(error, stackTrace); 25 : /// } 26 : /// } 27 : /// ``` 28 : class NullStreamSink<T> implements StreamSink<T> { 29 : @override 30 : final Future done; 31 : 32 : /// Whether the sink has been closed. 33 : var _closed = false; 34 : 35 : /// Whether an [addStream] call is pending. 36 : /// 37 : /// We don't actually add any events from streams, but it does return the 38 : /// [StreamSubscription.cancel] future so to be [StreamSink]-complaint we 39 : /// reject events until that completes. 40 : var _addingStream = false; 41 : 42 : /// Creates a null sink. 43 : /// 44 : /// If [done] is passed, it's used as the [Sink.done] future. Otherwise, a 45 : /// completed future is used. 46 0 : NullStreamSink({Future? done}) : done = done ?? Future.value(); 47 : 48 : /// Creates a null sink whose [done] future emits [error]. 49 : /// 50 : /// Note that this error will not be considered uncaught. 51 0 : NullStreamSink.error(Object error, [StackTrace? stackTrace]) 52 0 : : done = Future.error(error, stackTrace) 53 : // Don't top-level the error. This gives the user a change to call 54 : // [close] or [done], and matches the behavior of a remote endpoint 55 : // experiencing an error. 56 0 : ..catchError((_) {}); 57 : 58 0 : @override 59 : void add(T data) { 60 0 : _checkEventAllowed(); 61 : } 62 : 63 0 : @override 64 : void addError(Object error, [StackTrace? stackTrace]) { 65 0 : _checkEventAllowed(); 66 : } 67 : 68 0 : @override 69 : Future addStream(Stream<T> stream) { 70 0 : _checkEventAllowed(); 71 : 72 0 : _addingStream = true; 73 0 : var future = stream.listen(null).cancel(); 74 0 : return future.whenComplete(() { 75 0 : _addingStream = false; 76 : }); 77 : } 78 : 79 : /// Throws a [StateError] if [close] has been called or an [addStream] call is 80 : /// pending. 81 0 : void _checkEventAllowed() { 82 0 : if (_closed) throw StateError('Cannot add to a closed sink.'); 83 0 : if (_addingStream) { 84 0 : throw StateError('Cannot add to a sink while adding a stream.'); 85 : } 86 : } 87 : 88 0 : @override 89 : Future close() { 90 0 : _closed = true; 91 0 : return done; 92 : } 93 : }