Esempio n. 1
0
        public static IAsyncObservable <TSource> Amb <TSource>(params IAsyncObservable <TSource>[] sources)
        {
            if (sources == null)
            {
                throw new ArgumentNullException(nameof(sources));
            }

            return(Create <TSource>(async observer =>
            {
                var count = sources.Length;

                var subscriptions = new SingleAssignmentAsyncDisposable[count];

                for (var i = 0; i < count; i++)
                {
                    subscriptions[i] = new SingleAssignmentAsyncDisposable();
                }

                var observers = AsyncObserver.Amb(observer, subscriptions);

                var tasks = new Task[count];

                for (var i = 0; i < count; i++)
                {
                    tasks[i] = sources[i].SubscribeSafeAsync(observers[i]).AsTask().ContinueWith(d => subscriptions[i].AssignAsync(d.Result).AsTask()).Unwrap();
                }

                await Task.WhenAll(tasks).ConfigureAwait(false);

                return StableCompositeAsyncDisposable.Create(subscriptions);
            }));
        }
Esempio n. 2
0
        public static IAsyncObservable <TSource> Amb <TSource>(this IAsyncObservable <TSource> first, IAsyncObservable <TSource> second)
        {
            if (first == null)
            {
                throw new ArgumentNullException(nameof(first));
            }
            if (second == null)
            {
                throw new ArgumentNullException(nameof(second));
            }

            return(Create <TSource>(async observer =>
            {
                var firstSubscription = new SingleAssignmentAsyncDisposable();
                var secondSubscription = new SingleAssignmentAsyncDisposable();

                var(firstObserver, secondObserver) = AsyncObserver.Amb(observer, firstSubscription, secondSubscription);

                var firstTask = first.SubscribeSafeAsync(firstObserver).AsTask().ContinueWith(d => firstSubscription.AssignAsync(d.Result).AsTask()).Unwrap();
                var secondTask = second.SubscribeSafeAsync(secondObserver).AsTask().ContinueWith(d => secondSubscription.AssignAsync(d.Result).AsTask()).Unwrap();

                await Task.WhenAll(firstTask, secondTask).ConfigureAwait(false);

                return StableCompositeAsyncDisposable.Create(firstSubscription, secondSubscription);
            }));
        }
Esempio n. 3
0
        public static IAsyncObservable <TSource> Timeout <TSource>(this IAsyncObservable <TSource> source, TimeSpan dueTime, IAsyncObservable <TSource> other, IAsyncScheduler scheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (other == null)
            {
                throw new ArgumentNullException(nameof(other));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(Create <TSource>(async observer =>
            {
                var sourceSubscription = new SingleAssignmentAsyncDisposable();

                var(sink, disposable) = await AsyncObserver.Timeout(observer, sourceSubscription, dueTime, other, scheduler).ConfigureAwait(false);

                var sourceSubscriptionInner = await source.SubscribeSafeAsync(sink).ConfigureAwait(false);

                await sourceSubscription.AssignAsync(sourceSubscriptionInner).ConfigureAwait(false);

                return disposable;
            }));
        }
Esempio n. 4
0
        public static IAsyncObservable <TSource> While <TSource>(Func <Task <bool> > condition, IAsyncObservable <TSource> source)
        {
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(Create <TSource>(async observer =>
            {
                var subscription = new SerialAsyncDisposable();

                var o = default(IAsyncObserver <TSource>);

                o = AsyncObserver.CreateUnsafe <TSource>(
                    observer.OnNextAsync,
                    observer.OnErrorAsync,
                    MoveNext
                    );

                async ValueTask MoveNext()
                {
                    var b = default(bool);

                    try
                    {
                        b = await condition().ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        await observer.OnErrorAsync(ex).ConfigureAwait(false);
                        return;
                    }

                    if (b)
                    {
                        var sad = new SingleAssignmentAsyncDisposable();
                        await subscription.AssignAsync(sad).ConfigureAwait(false);

                        var d = await source.SubscribeSafeAsync(o).ConfigureAwait(false);
                        await sad.AssignAsync(d).ConfigureAwait(false);
                    }
                    else
                    {
                        await observer.OnCompletedAsync().ConfigureAwait(false);
                    }
                }

                await MoveNext().ConfigureAwait(false);

                return subscription;
            }));
        }
Esempio n. 5
0
        public static ValueTask <IAsyncDisposable> Prepend <TSource>(IAsyncObserver <TSource> observer, IAsyncObservable <TSource> source, IAsyncScheduler scheduler, params TSource[] values)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }
            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            return(CoreAsync());

            async ValueTask <IAsyncDisposable> CoreAsync()
            {
                var subscription = new SingleAssignmentAsyncDisposable();

                var task = await scheduler.ScheduleAsync(async ct =>
                {
                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    for (var i = 0; i < values.Length && !ct.IsCancellationRequested; i++)
                    {
                        await observer.OnNextAsync(values[i]).RendezVous(scheduler, ct);
                    }

                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    var inner = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);
                    await subscription.AssignAsync(inner).RendezVous(scheduler, ct);
                }).ConfigureAwait(false);

                return(StableCompositeAsyncDisposable.Create(task, subscription));
            }
        }
Esempio n. 6
0
        public static AsyncAsyncSubject <TSource> RunAsync <TSource>(this IAsyncObservable <TSource> source, CancellationToken token)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            var subject = new SequentialAsyncAsyncSubject <TSource>();

            if (token.IsCancellationRequested)
            {
                var ignored = subject.OnErrorAsync(new OperationCanceledException(token));
                return(subject);
            }

            var subscribeTask = source.SubscribeSafeAsync(subject);

            subscribeTask.ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    subject.OnErrorAsync(t.Exception); // NB: Should not occur due to use of SubscribeSafeAsync.
                }
            });

            if (token.CanBeCanceled)
            {
                var d = new SingleAssignmentAsyncDisposable();

                subscribeTask.ContinueWith(t =>
                {
                    if (t.Exception == null)
                    {
                        var ignored = d.AssignAsync(t.Result);
                    }
                });

                token.Register(() =>
                {
                    var ignored = d.DisposeAsync();
                });
            }

            return(subject);
        }
Esempio n. 7
0
        public static IAsyncObservable <TSource> SubscribeOn <TSource>(this IAsyncObservable <TSource> source, IAsyncScheduler subscribeScheduler, IAsyncScheduler disposeScheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (subscribeScheduler == null)
            {
                throw new ArgumentNullException(nameof(subscribeScheduler));
            }
            if (disposeScheduler == null)
            {
                throw new ArgumentNullException(nameof(disposeScheduler));
            }

            return(CreateAsyncObservable <TSource> .From(
                       source,
                       (subscribeScheduler, disposeScheduler),
                       static async (source, state, observer) =>
            {
                var m = new SingleAssignmentAsyncDisposable();
                var d = new SerialAsyncDisposable();

                await d.AssignAsync(m).ConfigureAwait(false);

                var scheduled = await state.subscribeScheduler.ScheduleAsync(async ct =>
                {
                    var subscription = await source.SubscribeSafeAsync(observer).RendezVous(state.subscribeScheduler, ct);

                    var scheduledDispose = AsyncDisposable.Create(async() =>
                    {
                        await state.disposeScheduler.ScheduleAsync(async _ =>
                        {
                            await subscription.DisposeAsync().RendezVous(state.disposeScheduler, ct);
                        }).ConfigureAwait(false);
                    });

                    await d.AssignAsync(scheduledDispose).RendezVous(state.subscribeScheduler, ct);
                }).ConfigureAwait(false);

                await m.AssignAsync(scheduled).ConfigureAwait(false);

                return d;
            }));
        }
Esempio n. 8
0
        public static ValueTask <IAsyncDisposable> Prepend <TSource>(IAsyncObserver <TSource> observer, IAsyncObservable <TSource> source, IAsyncScheduler scheduler, IEnumerable <TSource> values)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }
            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            return(CoreAsync());

            async ValueTask <IAsyncDisposable> CoreAsync()
            {
                var subscription = new SingleAssignmentAsyncDisposable();

                var task = await scheduler.ScheduleAsync(async ct =>
                {
                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    var e = default(IEnumerator <TSource>);

                    try
                    {
                        e = values.GetEnumerator();
                    }
                    catch (Exception ex)
                    {
                        await observer.OnErrorAsync(ex).RendezVous(scheduler, ct);
                        return;
                    }

                    using (e)
                    {
                        while (!ct.IsCancellationRequested)
                        {
                            var b     = default(bool);
                            var value = default(TSource);

                            try
                            {
                                b = e.MoveNext();

                                if (b)
                                {
                                    value = e.Current;
                                }
                            }
                            catch (Exception ex)
                            {
                                await observer.OnErrorAsync(ex).RendezVous(scheduler, ct);
                                return;
                            }

                            if (b)
                            {
                                await observer.OnNextAsync(value).RendezVous(scheduler, ct);
                            }
                            else
                            {
                                break;
                            }
                        }
                    }

                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    var inner = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);
                    await subscription.AssignAsync(inner).RendezVous(scheduler, ct);
                }).ConfigureAwait(false);

                return(StableCompositeAsyncDisposable.Create(task, subscription));
            }
        }
Esempio n. 9
0
        private static async Task ForEachAsyncCore <TSource>(IAsyncObservable <TSource> source, Func <TSource, int, Task> onNext, CancellationToken token)
        {
            token.ThrowIfCancellationRequested();

            var tcs = new TaskCompletionSource <object>();

            var subscription = new SingleAssignmentAsyncDisposable();

            using (token.Register(() =>
            {
                tcs.TrySetCanceled(token);

                subscription.DisposeAsync().AsTask().ContinueWith(t =>
                {
                    if (t.Exception != null)
                    {
                        // TODO: Trace?
                    }
                });
            }))
            {
                var i = 0;

                var o = AsyncObserver.Create <TSource>(
                    async x =>
                {
                    try
                    {
                        await onNext(x, checked (i++)).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        try
                        {
                            tcs.TrySetException(ex);
                        }
                        finally
                        {
                            await subscription.DisposeAsync().ConfigureAwait(false);
                        }
                    }
                },
                    async ex =>
                {
                    try
                    {
                        tcs.TrySetException(ex);
                    }
                    finally
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                },
                    async() =>
                {
                    try
                    {
                        tcs.TrySetResult(null);
                    }
                    finally
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }
                }
                    );

                //
                // NB: If any of the lines below throw, the result will go into the Task returned from the async method.
                //     There's also no need to use SubscribeSafeAsync here; the exception will propagate just fine.
                //

                var d = await source.SubscribeAsync(o).ConfigureAwait(false);

                await subscription.AssignAsync(d).ConfigureAwait(false);
            }

            await tcs.Task.ConfigureAwait(false);
        }
Esempio n. 10
0
        public static IAsyncObservable <TResult> For <TSource, TResult>(IEnumerable <TSource> source, Func <TSource, Task <IAsyncObservable <TResult> > > resultSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (resultSelector == null)
            {
                throw new ArgumentNullException(nameof(resultSelector));
            }

            return(Create <TResult>(async observer =>
            {
                var subscription = new SerialAsyncDisposable();

                var enumerator = source.GetEnumerator();

                var o = default(IAsyncObserver <TResult>);

                o = AsyncObserver.CreateUnsafe <TResult>(
                    observer.OnNextAsync,
                    observer.OnErrorAsync,
                    MoveNext
                    );

                async Task MoveNext()
                {
                    var b = default(bool);
                    var next = default(IAsyncObservable <TResult>);

                    try
                    {
                        b = enumerator.MoveNext();

                        if (b)
                        {
                            next = await resultSelector(enumerator.Current).ConfigureAwait(false);
                        }
                    }
                    catch (Exception ex)
                    {
                        await observer.OnErrorAsync(ex).ConfigureAwait(false);
                        return;
                    }

                    if (b)
                    {
                        var sad = new SingleAssignmentAsyncDisposable();
                        await subscription.AssignAsync(sad).ConfigureAwait(false);

                        var d = await next.SubscribeSafeAsync(o).ConfigureAwait(false);
                        await sad.AssignAsync(d).ConfigureAwait(false);
                    }
                    else
                    {
                        await observer.OnCompletedAsync().ConfigureAwait(false);
                    }
                }

                await MoveNext().ConfigureAwait(false);

                var disposeEnumerator = AsyncDisposable.Create(() =>
                {
                    enumerator.Dispose();
                    return Task.CompletedTask;
                });

                return StableCompositeAsyncDisposable.Create(disposeEnumerator, subscription);
            }));
        }