public static IAsyncEnumerable <TSource> ToAsyncEnumerable <TSource>(this IObservable <TSource> source) { if (source == null) { throw new ArgumentNullException("source"); } return(Create(() => { var observer = new ToAsyncEnumerableObserver <TSource>(); observer.Queue = new Queue <Either <TSource, Exception, bool> >(); var subscription = source.Subscribe(observer); return Create( (ct, tcs) => { lock (observer.Queue) { if (observer.Queue.Count > 0) { var n = observer.Queue.Dequeue(); n.Switch( x => { observer.Current = x; tcs.TrySetResult(true); }, ex => { tcs.TrySetException(ex); }, _ => { tcs.TrySetResult(false); } ); } else { observer.TaskCompletionSource = tcs; } } return tcs.Task; }, () => observer.Current, () => { subscription.Dispose(); // Should we cancel in-flight operations somehow? }); })); }
public static IAsyncEnumerable <TSource> ToAsyncEnumerable <TSource>(this IObservable <TSource> source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } return(CreateEnumerable( () => { var observer = new ToAsyncEnumerableObserver <TSource>(); var subscription = source.Subscribe(observer); return CreateEnumerator( (ct, tcs) => { var hasValue = false; var hasCompleted = false; var error = default(Exception); lock (observer.SyncRoot) { if (observer.Values.Count > 0) { hasValue = true; observer.Current = observer.Values.Dequeue(); } else if (observer.HasCompleted) { hasCompleted = true; } else if (observer.Error != null) { error = observer.Error; } else { observer.TaskCompletionSource = tcs; } } if (hasValue) { tcs.TrySetResult(true); } else if (hasCompleted) { tcs.TrySetResult(false); } else if (error != null) { tcs.TrySetException(error); } return tcs.Task; }, () => observer.Current, () => { subscription.Dispose(); // Should we cancel in-flight operations somehow? }); })); }