public static Stream <T> fromFutures(IEnumerable <Future <T> > futures) { _StreamController <T> controller = new _SyncStreamController <T>(null, null, null, null); int count = 0; // Declare these as variables holding closures instead of as // function declarations. // This avoids creating a new closure from the functions for each future. var onValue = new Action <object>((object value) => { if (!controller.isClosed) { controller._add((T)value); if (--count == 0) { controller._closeUnchecked(); } } }); var onError = new Func <Exception, FutureOr>((error) => { if (!controller.isClosed) { controller._addError(error, null); if (--count == 0) { controller._closeUnchecked(); } } return(FutureOr.nil); }); // The futures are already running, so start listening to them immediately // (instead of waiting for the stream to be listened on). // If we wait, we might not catch errors in the futures in time. foreach (var future in futures) { count++; future.then(onValue, onError: onError); } // Use schedule microtask since controller is sync. if (count == 0) { async_.scheduleMicrotask(controller.close); } return(controller.stream); }
public static Stream <T> fromFuture(Future <T> future) { // Use the controller's buffering to fill in the value even before // the stream has a listener. For a single value, it's not worth it // to wait for a listener before doing the `then` on the future. _StreamController <T> controller = new _SyncStreamController <T>(null, null, null, null); future.then((value) => { controller._add((T)value); controller._closeUnchecked(); }, onError: (error) => { controller._addError(error, null); controller._closeUnchecked(); return(FutureOr.nil); }); return(controller.stream); }