private static IAsyncEnumerable <TSource> OnErrorResumeNext_ <TSource>(IEnumerable <IAsyncEnumerable <TSource> > sources) { return(Create(() => { var se = sources.GetEnumerator(); var e = default(IAsyncEnumerator <TSource>); var cts = new CancellationTokenDisposable(); var a = new AssignableDisposable(); var d = Disposable.Create(cts, se, a); var f = default(Action <TaskCompletionSource <bool>, CancellationToken>); f = (tcs, ct) => { if (e == null) { var b = false; try { b = se.MoveNext(); if (b) { e = se.Current.GetEnumerator(); } } catch (Exception ex) { tcs.TrySetException(ex); return; } if (!b) { tcs.TrySetResult(false); return; } a.Disposable = e; } e.MoveNext(ct).Then(t => { t.Handle(tcs, res => { if (res) { tcs.TrySetResult(true); } else { e.Dispose(); e = null; f(tcs, ct); } }, ex => { e.Dispose(); e = null; f(tcs, ct); } ); }); }; return Create( (ct, tcs) => { f(tcs, cts.Token); return tcs.Task.UsingEnumerator(a); }, () => e.Current, d.Dispose ); })); }
public static IAsyncEnumerable <TSource> Catch <TSource, TException>(this IAsyncEnumerable <TSource> source, Func <TException, IAsyncEnumerable <TSource> > handler) where TException : Exception { if (source == null) { throw new ArgumentNullException("source"); } if (handler == null) { throw new ArgumentNullException("handler"); } return(Create(() => { var e = source.GetEnumerator(); var cts = new CancellationTokenDisposable(); var a = new AssignableDisposable { Disposable = e }; var d = Disposable.Create(cts, a); var done = false; var f = default(Action <TaskCompletionSource <bool>, CancellationToken>); f = (tcs, ct) => { if (!done) { e.MoveNext(ct).Then(t => { t.Handle(tcs, res => { tcs.TrySetResult(res); }, ex => { var err = default(IAsyncEnumerator <TSource>); try { ex.Flatten().Handle(ex_ => { var exx = ex_ as TException; if (exx != null) { err = handler(exx).GetEnumerator(); return true; } return false; }); } catch (Exception ex2) { tcs.TrySetException(ex2); return; } if (err != null) { e = err; a.Disposable = e; done = true; f(tcs, ct); } } ); }); } else { e.MoveNext(ct).Then(t => { t.Handle(tcs, res => { tcs.TrySetResult(res); }); }); } }; return Create( (ct, tcs) => { f(tcs, cts.Token); return tcs.Task.UsingEnumerator(a); }, () => e.Current, d.Dispose ); })); }
public static IAsyncEnumerable <TResult> SelectMany <TSource, TResult>(this IAsyncEnumerable <TSource> source, Func <TSource, int, IAsyncEnumerable <TResult> > selector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (selector == null) { throw new ArgumentNullException(nameof(selector)); } return(CreateEnumerable( () => { var e = source.GetEnumerator(); var ie = default(IAsyncEnumerator <TResult>); var index = 0; var innerDisposable = new AssignableDisposable(); var cts = new CancellationTokenDisposable(); var d = Disposable.Create(cts, innerDisposable, e); var inner = default(Func <CancellationToken, Task <bool> >); var outer = default(Func <CancellationToken, Task <bool> >); inner = async ct => { if (await ie.MoveNext(ct) .ConfigureAwait(false)) { return true; } innerDisposable.Disposable = null; return await outer(ct) .ConfigureAwait(false); }; outer = async ct => { if (await e.MoveNext(ct) .ConfigureAwait(false)) { var enumerable = selector(e.Current, checked (index++)); ie = enumerable.GetEnumerator(); innerDisposable.Disposable = ie; return await inner(ct) .ConfigureAwait(false); } return false; }; return CreateEnumerator(ct => ie == null ? outer(cts.Token) : inner(cts.Token), () => ie.Current, d.Dispose, e ); })); }
public static IAsyncEnumerable <TSource> Expand <TSource>(this IAsyncEnumerable <TSource> source, Func <TSource, IAsyncEnumerable <TSource> > selector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (selector == null) { throw new ArgumentNullException(nameof(selector)); } return(CreateEnumerable( () => { var e = default(IAsyncEnumerator <TSource>); var cts = new CancellationTokenDisposable(); var a = new AssignableDisposable(); var d = Disposable.Create(cts, a); var queue = new Queue <IAsyncEnumerable <TSource> >(); queue.Enqueue(source); var current = default(TSource); var f = default(Func <CancellationToken, Task <bool> >); f = async ct => { if (e == null) { if (queue.Count > 0) { var src = queue.Dequeue(); e = src.GetEnumerator(); a.Disposable = e; return await f(ct) .ConfigureAwait(false); } return false; } if (await e.MoveNext(ct) .ConfigureAwait(false)) { var item = e.Current; var next = selector(item); queue.Enqueue(next); current = item; return true; } e = null; return await f(ct) .ConfigureAwait(false); }; return CreateEnumerator( f, () => current, d.Dispose, e ); })); }
public static IAsyncEnumerable <TSource> Concat <TSource>(this IAsyncEnumerable <TSource> first, IAsyncEnumerable <TSource> second) { if (first == null) { throw new ArgumentNullException("first"); } if (second == null) { throw new ArgumentNullException("second"); } return(Create(() => { var switched = false; var e = first.GetEnumerator(); var cts = new CancellationTokenDisposable(); var a = new AssignableDisposable { Disposable = e }; var d = Disposable.Create(cts, a); var f = default(Action <TaskCompletionSource <bool>, CancellationToken>); f = (tcs, ct) => e.MoveNext(ct).Then(t => { t.Handle(tcs, res => { if (res) { tcs.TrySetResult(true); } else { if (switched) { tcs.TrySetResult(false); } else { switched = true; e = second.GetEnumerator(); a.Disposable = e; f(tcs, ct); } } }); }); return Create( (ct, tcs) => { f(tcs, cts.Token); return tcs.Task.UsingEnumerator(a); }, () => e.Current, d.Dispose ); })); }