Beispiel #1
0
        public static IAsyncEnumerable <TSource> Except <TSource>(this IAsyncEnumerable <TSource> first, IAsyncEnumerable <TSource> second, IEqualityComparer <TSource> comparer)
        {
            if (first == null)
            {
                throw new ArgumentNullException(nameof(first));
            }
            if (second == null)
            {
                throw new ArgumentNullException(nameof(second));
            }
            if (comparer == null)
            {
                throw new ArgumentNullException(nameof(comparer));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = first.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var mapTask = default(Task <Dictionary <TSource, TSource> >);
                var getMapTask = new Func <CancellationToken, Task <Dictionary <TSource, TSource> > >(
                    ct => mapTask ?? (mapTask = second.ToDictionary(x => x, comparer, ct)));

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (await e.MoveNext(ct)
                        .Zip(getMapTask(ct), (b, _) => b)
                        .ConfigureAwait(false))
                    {
                        if (!mapTask.Result.ContainsKey(e.Current))
                        {
                            return true;
                        }
                        return await f(ct)
                        .ConfigureAwait(false);
                    }
                    return false;
                };

                return CreateEnumerator(
                    f,
                    () => e.Current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #2
0
        private static IAsyncEnumerable <TSource> Concat_ <TSource>(this IEnumerable <IAsyncEnumerable <TSource> > sources)
        {
            return(CreateEnumerable(
                       () =>
            {
                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(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (e == null)
                    {
                        var b = false;
                        b = se.MoveNext();
                        if (b)
                        {
                            e = se.Current.GetEnumerator();
                        }

                        if (!b)
                        {
                            return false;
                        }

                        a.Disposable = e;
                    }

                    if (await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        return true;
                    }
                    e.Dispose();
                    e = null;

                    return await f(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator(
                    f,
                    () => e.Current,
                    d.Dispose,
                    a
                    );
            }));
        }
Beispiel #3
0
        public static IAsyncEnumerable <TSource> SkipWhile <TSource>(this IAsyncEnumerable <TSource> source, Func <TSource, int, bool> predicate)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();
                var skipping = true;
                var index = 0;

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (skipping)
                    {
                        if (await e.MoveNext(ct)
                            .ConfigureAwait(false))
                        {
                            if (predicate(e.Current, checked (index++)))
                            {
                                return await f(ct)
                                .ConfigureAwait(false);
                            }
                            skipping = false;
                            return true;
                        }
                        return false;
                    }
                    return await e.MoveNext(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator(
                    f,
                    () => e.Current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #4
0
        public static IAsyncEnumerable <TSource> SkipLast <TSource>(this IAsyncEnumerable <TSource> source, int count)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var q = new Queue <TSource>();
                var current = default(TSource);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        var item = e.Current;

                        q.Enqueue(item);
                        if (q.Count > count)
                        {
                            current = q.Dequeue();
                            return true;
                        }
                        return await f(ct)
                        .ConfigureAwait(false);
                    }
                    return false;
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #5
0
            public IDisposable Subscribe(IObserver <T> observer)
            {
                var ctd = new CancellationTokenDisposable();
                var e   = _source.GetAsyncEnumerator(ctd.Token);

                async void Core()
                {
                    bool hasNext;

                    try
                    {
                        hasNext = await e.MoveNextAsync().ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        if (!ctd.Token.IsCancellationRequested)
                        {
                            observer.OnError(ex);
                            await e.DisposeAsync().ConfigureAwait(false);
                        }

                        return;
                    }

                    if (hasNext)
                    {
                        observer.OnNext(e.Current);

                        if (!ctd.Token.IsCancellationRequested)
                        {
                            Core();
                        }

                        // In case cancellation is requested, this could only have happened
                        // by disposing the returned composite disposable (see below).
                        // In that case, e will be disposed too, so there is no need to dispose e here.
                    }
                    else
                    {
                        observer.OnCompleted();
                        await e.DisposeAsync().ConfigureAwait(false);
                    }
                }

                Core();

                // REVIEW: Safety of concurrent dispose operation; fire-and-forget nature of dispose?

                return(Disposable.Create(ctd, Disposable.Create(() => { e.DisposeAsync(); })));
            }
Beispiel #6
0
        private static IAsyncEnumerable <TSource> DoHelper <TSource>(this IAsyncEnumerable <TSource> source, Action <TSource> onNext, Action <Exception> onError, Action onCompleted)
        {
            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var current = default(TSource);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    try
                    {
                        var result = await e.MoveNext(ct)
                                     .ConfigureAwait(false);
                        if (!result)
                        {
                            onCompleted();
                        }
                        else
                        {
                            current = e.Current;
                            onNext(current);
                        }
                        return result;
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception ex)
                    {
                        onError(ex);
                        throw;
                    }
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #7
0
        public static IAsyncEnumerable <TSource> DefaultIfEmpty <TSource>(this IAsyncEnumerable <TSource> source, TSource defaultValue)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(CreateEnumerable(
                       () =>
            {
                var done = false;
                var hasElements = false;
                var e = source.GetEnumerator();
                var current = default(TSource);

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (done)
                    {
                        return false;
                    }
                    if (await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        hasElements = true;
                        current = e.Current;
                        return true;
                    }
                    done = true;
                    if (!hasElements)
                    {
                        current = defaultValue;
                        return true;
                    }
                    return false;
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #8
0
            private IAsyncEnumerable <IEnumerable <T> > Classes()
            {
                return(CreateEnumerable(() =>
                {
                    var e = equivalenceClasses.GetEnumerator();
                    var list = new List <IEnumerable <T> >();
                    var e1 = default(IEnumerator <IEnumerable <T> >);

                    var cts = new CancellationTokenDisposable();
                    var d1 = new AssignableDisposable();
                    var d = Disposable.Create(cts, e, d1);

                    var f = default(Func <CancellationToken, Task <bool> >);

                    f = async ct =>
                    {
                        if (await e.MoveNext(ct)
                            .ConfigureAwait(false))
                        {
                            list.AddRange(e.Current.OrderBy(keySelector, comparer)
                                          .GroupUntil(keySelector, x => x, comparer));
                            return await f(ct)
                            .ConfigureAwait(false);
                        }
                        e.Dispose();

                        e1 = list.GetEnumerator();
                        d1.Disposable = e1;

                        return e1.MoveNext();
                    };

                    return CreateEnumerator(
                        async ct =>
                    {
                        if (e1 != null)
                        {
                            return e1.MoveNext();
                        }
                        return await f(cts.Token)
                        .ConfigureAwait(false);
                    },
                        () => e1.Current,
                        d.Dispose,
                        e
                        );
                }));
            }
Beispiel #9
0
            public IDisposable Subscribe(IObserver <T> observer)
            {
                var ctd = new CancellationTokenDisposable();

                async void Core()
                {
                    await using (var e = _source.GetAsyncEnumerator(ctd.Token))
                    {
                        do
                        {
                            bool hasNext;
                            var  value = default(T) !;

                            try
                            {
                                hasNext = await e.MoveNextAsync().ConfigureAwait(false);

                                if (hasNext)
                                {
                                    value = e.Current;
                                }
                            }
                            catch (Exception ex)
                            {
                                if (!ctd.Token.IsCancellationRequested)
                                {
                                    observer.OnError(ex);
                                }

                                return;
                            }

                            if (!hasNext)
                            {
                                observer.OnCompleted();
                                return;
                            }

                            observer.OnNext(value);
                        }while (!ctd.Token.IsCancellationRequested);
                    }
                }

                // Fire and forget
                Core();

                return(ctd);
            }
        public static IAsyncEnumerable <TResult> Zip <TFirst, TSecond, TResult>(this IAsyncEnumerable <TFirst> first, IAsyncEnumerable <TSecond> second, Func <TFirst, TSecond, TResult> selector)
        {
            if (first == null)
            {
                throw new ArgumentNullException("first");
            }
            if (second == null)
            {
                throw new ArgumentNullException("second");
            }
            if (selector == null)
            {
                throw new ArgumentNullException("selector");
            }

            return(Create(() =>
            {
                var e1 = first.GetEnumerator();
                var e2 = second.GetEnumerator();
                var current = default(TResult);

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e1, e2);

                return Create(
                    (ct, tcs) =>
                {
                    e1.MoveNext(cts.Token).Zip(e2.MoveNext(cts.Token), (f, s) =>
                    {
                        var result = f && s;
                        if (result)
                        {
                            current = selector(e1.Current, e2.Current);
                        }
                        return result;
                    }).Then(t =>
                    {
                        t.Handle(tcs, x => tcs.TrySetResult(x));
                    });

                    return tcs.Task.UsingEnumerator(e1).UsingEnumerator(e2);
                },
                    () => current,
                    d.Dispose
                    );
            }));
        }
Beispiel #11
0
        public static IAsyncEnumerable <TAccumulate> Scan <TSource, TAccumulate>(this IAsyncEnumerable <TSource> source, TAccumulate seed, Func <TAccumulate, TSource, TAccumulate> accumulator)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (accumulator == null)
            {
                throw new ArgumentNullException(nameof(accumulator));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var acc = seed;
                var current = default(TAccumulate);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (!await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        return false;
                    }

                    var item = e.Current;
                    acc = accumulator(acc, item);

                    current = acc;
                    return true;
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #12
0
        public static IAsyncEnumerable <TSource> Skip <TSource>(this IAsyncEnumerable <TSource> source, int count)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();
                var n = count;

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    var moveNext = await e.MoveNext(ct)
                                   .ConfigureAwait(false);
                    if (n == 0)
                    {
                        return moveNext;
                    }
                    --n;
                    if (!moveNext)
                    {
                        return false;
                    }
                    return await f(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator(
                    ct => f(cts.Token),
                    () => e.Current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #13
0
        public static IAsyncEnumerable <TSource> Repeat <TSource>(this IAsyncEnumerable <TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = default(IAsyncEnumerator <TSource>);
                var a = new AssignableDisposable();
                var current = default(TSource);

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, a);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (e == null)
                    {
                        e = source.GetEnumerator();

                        a.Disposable = e;
                    }

                    if (await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        current = e.Current;
                        return true;
                    }
                    e = null;
                    return await f(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #14
0
        public static IAsyncEnumerable <TSource> Take <TSource>(this IAsyncEnumerable <TSource> source, int count)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();
                var n = count;

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                return CreateEnumerator(
                    async ct =>
                {
                    if (n == 0)
                    {
                        return false;
                    }

                    var result = await e.MoveNext(cts.Token)
                                 .ConfigureAwait(false);

                    --n;

                    if (n == 0)
                    {
                        e.Dispose();
                    }

                    return result;
                },
                    () => e.Current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #15
0
            public IDisposable Subscribe(IObserver <T> observer)
            {
                var ctd = new CancellationTokenDisposable();
                var e   = source.GetEnumerator();

                var f = default(Action);

                f = () => e.MoveNext(ctd.Token)
                    .ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        observer.OnError(t.Exception);
                        e.Dispose();
                    }
                    else if (t.IsCanceled)
                    {
                        e.Dispose();
                    }
                    else if (t.IsCompleted)
                    {
                        if (t.Result)
                        {
                            observer.OnNext(e.Current);

                            if (!ctd.Token.IsCancellationRequested)
                            {
                                f();
                            }

                            //In case cancellation is requested, this could only have happened
                            //by disposing the returned composite disposable (see below).
                            //In that case, e will be disposed too, so there is no need to dispose e here.
                        }
                        else
                        {
                            observer.OnCompleted();
                            e.Dispose();
                        }
                    }
                }, ctd.Token);

                f();

                return(Disposable.Create(ctd, e));
            }
Beispiel #16
0
            public IAsyncEnumerator <TElement> GetEnumerator()
            {
                var index = -1;

                var cts = new CancellationTokenDisposable();
                var d   = Disposable.Create(cts, sourceDisposable);

                var f = default(Func <CancellationToken, Task <bool> >);

                f = async ct =>
                {
                    var size = 0;
                    lock (elements)
                        size = elements.Count;

                    if (index < size)
                    {
                        return(true);
                    }
                    if (done)
                    {
                        exception?.Throw();
                        return(false);
                    }
                    if (await iterateSource(ct)
                        .ConfigureAwait(false))
                    {
                        return(await f(ct)
                               .ConfigureAwait(false));
                    }
                    return(false);
                };

                return(CreateEnumerator(
                           ct =>
                {
                    ++index;
                    return f(cts.Token);
                },
                           () => elements[index],
                           d.Dispose,
                           null
                           ));
            }
Beispiel #17
0
        public static IAsyncEnumerable <TResult> Zip <TFirst, TSecond, TResult>(this IAsyncEnumerable <TFirst> first, IAsyncEnumerable <TSecond> second, Func <TFirst, TSecond, TResult> selector)
        {
            if (first == null)
            {
                throw new ArgumentNullException(nameof(first));
            }
            if (second == null)
            {
                throw new ArgumentNullException(nameof(second));
            }
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e1 = first.GetEnumerator();
                var e2 = second.GetEnumerator();
                var current = default(TResult);

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e1, e2);

                return CreateEnumerator(
                    ct => e1.MoveNext(cts.Token)
                    .Zip(e2.MoveNext(cts.Token),
                         (f, s) =>
                {
                    var result = f && s;
                    if (result)
                    {
                        current = selector(e1.Current, e2.Current);
                    }
                    return result;
                }),
                    () => current,
                    d.Dispose
                    );
            }));
        }
Beispiel #18
0
        public static IAsyncEnumerable <TSource> Finally <TSource>(this IAsyncEnumerable <TSource> source, Action finallyAction)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (finallyAction == null)
            {
                throw new ArgumentNullException("finallyAction");
            }

            return(Create(() =>
            {
                var e = source.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var r = new Disposable(finallyAction);
                var d = Disposable.Create(cts, e, r);

                var f = default(Action <TaskCompletionSource <bool>, CancellationToken>);
                f = (tcs, ct) =>
                {
                    e.MoveNext(ct).Then(t =>
                    {
                        t.Handle(tcs, res =>
                        {
                            tcs.TrySetResult(res);
                        });
                    });
                };

                return Create(
                    (ct, tcs) =>
                {
                    f(tcs, cts.Token);
                    return tcs.Task.UsingEnumeratorSync(r);
                },
                    () => e.Current,
                    d.Dispose
                    );
            }));
        }
Beispiel #19
0
        public static IAsyncEnumerable <TSource> Reverse <TSource>(this IAsyncEnumerable <TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();
                var stack = default(Stack <TSource>);

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                return CreateEnumerator(
                    async ct =>
                {
                    if (stack == null)
                    {
                        stack = await CreateEnumerable(
                            () => e)
                                .Aggregate(new Stack <TSource>(), (s, x) =>
                        {
                            s.Push(x);
                            return s;
                        }, cts.Token)
                                .ConfigureAwait(false);
                        return stack.Count > 0;
                    }
                    stack.Pop();
                    return stack.Count > 0;
                },
                    () => stack.Peek(),
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #20
0
        public static IAsyncEnumerable <TResult> Select <TSource, TResult>(this IAsyncEnumerable <TSource> source, Func <TSource, int, 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 current = default(TResult);
                var index = 0;

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                return CreateEnumerator(
                    async ct =>
                {
                    if (await e.MoveNext(cts.Token)
                        .ConfigureAwait(false))
                    {
                        current = selector(e.Current, checked (index++));
                        return true;
                    }
                    return false;
                },
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #21
0
            public IDisposable Subscribe(IObserver <T> observer)
            {
                var ctd = new CancellationTokenDisposable();
                var e   = source.GetEnumerator();

                var f = default(Action);

                f = () => e.MoveNext(ctd.Token).ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        observer.OnError(t.Exception);
                        e.Dispose();
                    }
                    else if (t.IsCanceled)
                    {
                        e.Dispose();
                    }
                    else if (t.IsCompleted)
                    {
                        if (t.Result)
                        {
                            observer.OnNext(e.Current);
                            f();
                        }
                        else
                        {
                            observer.OnCompleted();
                            e.Dispose();
                        }
                    }
                }, ctd.Token);

                f();

                return(Disposable.Create(ctd, e));
            }
Beispiel #22
0
        public static IAsyncEnumerable <TSource> TakeWhile <TSource>(this IAsyncEnumerable <TSource> source, Func <TSource, int, bool> predicate)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (predicate == null)
            {
                throw new ArgumentNullException(nameof(predicate));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();
                var index = 0;

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                return CreateEnumerator(
                    async ct =>
                {
                    if (await e.MoveNext(cts.Token)
                        .ConfigureAwait(false))
                    {
                        return predicate(e.Current, checked (index++));
                    }
                    return false;
                },
                    () => e.Current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #23
0
        public static IAsyncEnumerable <TSource> IgnoreElements <TSource>(this IAsyncEnumerable <TSource> source)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(CreateEnumerable(
                       () =>
            {
                var e = source.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, e);

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    if (!await e.MoveNext(ct)
                        .ConfigureAwait(false))
                    {
                        return false;
                    }

                    return await f(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator <TSource>(
                    f,
                    () => { throw new InvalidOperationException(); },
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #24
0
        public static IAsyncEnumerable <TSource> Using <TSource, TResource>(Func <TResource> resourceFactory, Func <TResource, IAsyncEnumerable <TSource> > enumerableFactory) where TResource : IDisposable
        {
            if (resourceFactory == null)
            {
                throw new ArgumentNullException("resourceFactory");
            }
            if (enumerableFactory == null)
            {
                throw new ArgumentNullException("enumerableFactory");
            }

            return(Create(() =>
            {
                var resource = resourceFactory();
                var e = default(IAsyncEnumerator <TSource>);

                try
                {
                    e = enumerableFactory(resource).GetEnumerator();
                }
                catch (Exception)
                {
                    resource.Dispose();
                    throw;
                }

                var cts = new CancellationTokenDisposable();
                var d = new CompositeDisposable(cts, resource, e);

                var current = default(TSource);

                return Create(
                    (ct, tcs) =>
                {
                    e.MoveNext(cts.Token).ContinueWith(t =>
                    {
                        t.Handle(tcs,
                                 res =>
                        {
                            if (res)
                            {
                                current = e.Current;
                                tcs.TrySetResult(true);
                            }
                            else
                            {
                                d.Dispose();
                                tcs.TrySetResult(false);
                            }
                        },
                                 ex =>
                        {
                            d.Dispose();
                            tcs.TrySetException(ex);
                        }
                                 );
                    });

                    return tcs.Task;
                },
                    () => current,
                    d.Dispose
                    );
            }));
        }
Beispiel #25
0
        public static IAsyncEnumerable <IAsyncGrouping <TKey, TElement> > GroupBy <TSource, TKey, TElement>(this IAsyncEnumerable <TSource> source, Func <TSource, TKey> keySelector, Func <TSource, TElement> elementSelector, IEqualityComparer <TKey> comparer)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (keySelector == null)
            {
                throw new ArgumentNullException(nameof(keySelector));
            }
            if (elementSelector == null)
            {
                throw new ArgumentNullException(nameof(elementSelector));
            }
            if (comparer == null)
            {
                throw new ArgumentNullException(nameof(comparer));
            }

            return(CreateEnumerable(() =>
            {
                var gate = new object();

                var e = source.GetEnumerator();
                var count = 1;

                var map = new Dictionary <TKey, AsyncGrouping <TKey, TElement> >(comparer);
                var list = new List <IAsyncGrouping <TKey, TElement> >();

                var index = 0;

                var current = default(IAsyncGrouping <TKey, TElement>);
                var faulted = default(ExceptionDispatchInfo);

                var res = default(bool?);

                var cts = new CancellationTokenDisposable();
                var refCount = new Disposable(
                    () =>
                {
                    if (Interlocked.Decrement(ref count) == 0)
                    {
                        e.Dispose();
                    }
                }
                    );
                var d = Disposable.Create(cts, refCount);

                var iterateSource = default(Func <CancellationToken, Task <bool> >);
                iterateSource = async ct =>
                {
                    lock (gate)
                    {
                        if (res != null)
                        {
                            return res.Value;
                        }
                        res = null;
                    }

                    faulted?.Throw();

                    try
                    {
                        res = await e.MoveNext(ct)
                              .ConfigureAwait(false);
                        if (res == true)
                        {
                            var key = default(TKey);
                            var element = default(TElement);

                            var cur = e.Current;
                            try
                            {
                                key = keySelector(cur);
                                element = elementSelector(cur);
                            }
                            catch (Exception exception)
                            {
                                foreach (var v in map.Values)
                                {
                                    v.Error(exception);
                                }

                                throw;
                            }

                            var group = default(AsyncGrouping <TKey, TElement>);
                            if (!map.TryGetValue(key, out group))
                            {
                                group = new AsyncGrouping <TKey, TElement>(key, iterateSource, refCount);
                                map.Add(key, group);
                                lock (list)
                                    list.Add(group);

                                Interlocked.Increment(ref count);
                            }
                            group.Add(element);
                        }

                        return res.Value;
                    }
                    catch (Exception ex)
                    {
                        foreach (var v in map.Values)
                        {
                            v.Error(ex);
                        }

                        faulted = ExceptionDispatchInfo.Capture(ex);
                        throw;
                    }
                    finally
                    {
                        res = null;
                    }
                };

                var f = default(Func <CancellationToken, Task <bool> >);
                f = async ct =>
                {
                    var result = await iterateSource(ct)
                                 .ConfigureAwait(false);

                    current = null;
                    lock (list)
                    {
                        if (index < list.Count)
                        {
                            current = list[index++];
                        }
                    }

                    if (current != null)
                    {
                        return true;
                    }
                    return result && await f(ct)
                    .ConfigureAwait(false);
                };

                return CreateEnumerator(
                    f,
                    () => current,
                    d.Dispose,
                    e
                    );
            }));
        }
Beispiel #26
0
        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
                    );
            }));
        }
Beispiel #27
0
        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
                    );
            }));
        }
Beispiel #28
0
        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 <TResult> Join <TOuter, TInner, TKey, TResult>(this IAsyncEnumerable <TOuter> outer, IAsyncEnumerable <TInner> inner, Func <TOuter, TKey> outerKeySelector, Func <TInner, TKey> innerKeySelector, Func <TOuter, TInner, TResult> resultSelector, IEqualityComparer <TKey> comparer)
        {
            if (outer == null)
            {
                throw new ArgumentNullException("outer");
            }
            if (inner == null)
            {
                throw new ArgumentNullException("inner");
            }
            if (outerKeySelector == null)
            {
                throw new ArgumentNullException("outerKeySelector");
            }
            if (innerKeySelector == null)
            {
                throw new ArgumentNullException("innerKeySelector");
            }
            if (resultSelector == null)
            {
                throw new ArgumentNullException("resultSelector");
            }
            if (comparer == null)
            {
                throw new ArgumentNullException("comparer");
            }

            return(Create(() =>
            {
                var oe = outer.GetEnumerator();
                var ie = inner.GetEnumerator();

                var cts = new CancellationTokenDisposable();
                var d = Disposable.Create(cts, oe, ie);

                var current = default(TResult);
                var useOuter = true;
                var outerMap = new Dictionary <TKey, List <TOuter> >(comparer);
                var innerMap = new Dictionary <TKey, List <TInner> >(comparer);
                var q = new Queue <TResult>();

                var gate = new object();

                var f = default(Action <TaskCompletionSource <bool>, CancellationToken>);
                f = (tcs, ct) =>
                {
                    if (q.Count > 0)
                    {
                        current = q.Dequeue();
                        tcs.TrySetResult(true);
                        return;
                    }

                    var b = useOuter;
                    if (ie == null && oe == null)
                    {
                        tcs.TrySetResult(false);
                        return;
                    }
                    else if (ie == null)
                    {
                        b = true;
                    }
                    else if (oe == null)
                    {
                        b = false;
                    }
                    useOuter = !useOuter;

                    var enqueue = new Func <TOuter, TInner, bool>((o, i) =>
                    {
                        var result = default(TResult);
                        try
                        {
                            result = resultSelector(o, i);
                        }
                        catch (Exception exception)
                        {
                            tcs.TrySetException(exception);
                            return false;
                        }

                        q.Enqueue(result);
                        return true;
                    });

                    if (b)
                    {
                        oe.MoveNext(ct).Then(t =>
                        {
                            t.Handle(tcs, res =>
                            {
                                if (res)
                                {
                                    var element = oe.Current;
                                    var key = default(TKey);

                                    try
                                    {
                                        key = outerKeySelector(element);
                                    }
                                    catch (Exception exception)
                                    {
                                        tcs.TrySetException(exception);
                                        return;
                                    }

                                    var outerList = default(List <TOuter>);
                                    if (!outerMap.TryGetValue(key, out outerList))
                                    {
                                        outerList = new List <TOuter>();
                                        outerMap.Add(key, outerList);
                                    }

                                    outerList.Add(element);

                                    var innerList = default(List <TInner>);
                                    if (!innerMap.TryGetValue(key, out innerList))
                                    {
                                        innerList = new List <TInner>();
                                        innerMap.Add(key, innerList);
                                    }

                                    foreach (var v in innerList)
                                    {
                                        if (!enqueue(element, v))
                                        {
                                            return;
                                        }
                                    }

                                    f(tcs, ct);
                                }
                                else
                                {
                                    oe.Dispose();
                                    oe = null;
                                    f(tcs, ct);
                                }
                            });
                        });
                    }
                    else
                    {
                        ie.MoveNext(ct).Then(t =>
                        {
                            t.Handle(tcs, res =>
                            {
                                if (res)
                                {
                                    var element = ie.Current;
                                    var key = default(TKey);

                                    try
                                    {
                                        key = innerKeySelector(element);
                                    }
                                    catch (Exception exception)
                                    {
                                        tcs.TrySetException(exception);
                                        return;
                                    }

                                    var innerList = default(List <TInner>);
                                    if (!innerMap.TryGetValue(key, out innerList))
                                    {
                                        innerList = new List <TInner>();
                                        innerMap.Add(key, innerList);
                                    }

                                    innerList.Add(element);

                                    var outerList = default(List <TOuter>);
                                    if (!outerMap.TryGetValue(key, out outerList))
                                    {
                                        outerList = new List <TOuter>();
                                        outerMap.Add(key, outerList);
                                    }

                                    foreach (var v in outerList)
                                    {
                                        if (!enqueue(v, element))
                                        {
                                            return;
                                        }
                                    }

                                    f(tcs, ct);
                                }
                                else
                                {
                                    ie.Dispose();
                                    ie = null;
                                    f(tcs, ct);
                                }
                            });
                        });
                    }
                };

                return Create(
                    (ct, tcs) =>
                {
                    f(tcs, cts.Token);
                    return tcs.Task.UsingEnumerator(oe).UsingEnumerator(ie);
                },
                    () => current,
                    d.Dispose
                    );
            }));
        }
Beispiel #30
0
        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
                                        );
            }));
        }