Line data Source code
1 : // Copyright (c) 2015, 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 : import 'stream_completer.dart'; 8 : import 'utils.dart'; 9 : 10 : /// A [Stream] wrapper that forwards to another [Stream] that's initialized 11 : /// lazily. 12 : /// 13 : /// This class allows a concrete `Stream` to be created only once it has a 14 : /// listener. It's useful to wrapping APIs that do expensive computation to 15 : /// produce a `Stream`. 16 : class LazyStream<T> extends Stream<T> { 17 : /// The callback that's called to create the inner stream. 18 : FutureOrCallback<Stream<T>>? _callback; 19 : 20 : /// Creates a single-subscription `Stream` that calls [callback] when it gets 21 : /// a listener and forwards to the returned stream. 22 0 : LazyStream(FutureOr<Stream<T>> Function() callback) : _callback = callback { 23 : // Explicitly check for null because we null out [_callback] internally. 24 0 : if (_callback == null) throw ArgumentError.notNull('callback'); 25 : } 26 : 27 0 : @override 28 : StreamSubscription<T> listen(void Function(T)? onData, 29 : {Function? onError, void Function()? onDone, bool? cancelOnError}) { 30 0 : var callback = _callback; 31 : if (callback == null) { 32 0 : throw StateError('Stream has already been listened to.'); 33 : } 34 : 35 : // Null out the callback before we invoke it to ensure that even while 36 : // running it, this can't be called twice. 37 0 : _callback = null; 38 : var result = callback(); 39 : 40 : Stream<T> stream; 41 0 : if (result is Future<Stream<T>>) { 42 0 : stream = StreamCompleter.fromFuture(result); 43 : } else { 44 : stream = result; 45 : } 46 : 47 0 : return stream.listen(onData, 48 : onError: onError, onDone: onDone, cancelOnError: cancelOnError); 49 : } 50 : }