Example #1
0
        // REVIEW: This overload is inherited from Rx but arguably a bit esoteric as it doesn't provide context to the closing selector.

        public static IAsyncObservable <IAsyncObservable <TSource> > Window <TSource, TWindowClosing>(this IAsyncObservable <TSource> source, Func <IAsyncObservable <TWindowClosing> > windowClosingSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (windowClosingSelector == null)
            {
                throw new ArgumentNullException(nameof(windowClosingSelector));
            }

            return(Create <IAsyncObservable <TSource> >(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var(sourceObserver, closingSubscription, subscription) = await AsyncObserver.Window <TSource, TWindowClosing>(observer, windowClosingSelector, d).ConfigureAwait(false);

                await d.AddAsync(closingSubscription).ConfigureAwait(false);

                var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);
                await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                return subscription;
            }));
        }
Example #2
0
        public static IAsyncObservable <TSource> Append <TSource>(this IAsyncObservable <TSource> source, IAsyncScheduler scheduler, params TSource[] values)
        {
            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(Create <TSource>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var(sink, disposable) = AsyncObserver.Append(observer, scheduler, values);

                await d.AddAsync(disposable).ConfigureAwait(false);

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

                await d.AddAsync(subscription).ConfigureAwait(false);

                return d;
            }));
        }
Example #3
0
        public static IAsyncObservable <TSource> DelaySubscription <TSource>(this IAsyncObservable <TSource> source, DateTimeOffset dueTime, IAsyncScheduler scheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(Create <TSource>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var task = await scheduler.ScheduleAsync(async ct =>
                {
                    var inner = await source.SubscribeSafeAsync(observer).ConfigureAwait(false);
                    await d.AddAsync(inner).ConfigureAwait(false);
                }, dueTime).ConfigureAwait(false);

                await d.AddAsync(task).ConfigureAwait(false);

                return d;
            }));
        }
Example #4
0
        public static IAsyncObservable <TResult> When <TResult>(IEnumerable <AsyncPlan <TResult> > plans)
        {
            if (plans == null)
            {
                throw new ArgumentNullException(nameof(plans));
            }

            return(Create <TResult>(async observer =>
            {
                var externalSubscriptions = new Dictionary <object, IAsyncJoinObserver>();
                var gate = new AsyncLock();
                var activePlans = new List <ActiveAsyncPlan>();

                var outputObserver = AsyncObserver.Create <TResult>(
                    observer.OnNextAsync,
                    async ex =>
                {
                    foreach (var subscription in externalSubscriptions.Values)
                    {
                        await subscription.DisposeAsync().ConfigureAwait(false);
                    }

                    await observer.OnErrorAsync(ex).ConfigureAwait(false);
                },
                    observer.OnCompletedAsync
                    );

                try
                {
                    foreach (var plan in plans)
                    {
                        var activatedPlan = plan.Activate(externalSubscriptions, outputObserver, async activePlan =>
                        {
                            activePlans.Remove(activePlan);

                            if (activePlans.Count == 0)
                            {
                                await outputObserver.OnCompletedAsync().ConfigureAwait(false);
                            }
                        });

                        activePlans.Add(activatedPlan);
                    }
                }
                catch (Exception ex)
                {
                    return await Throw <TResult>(ex).SubscribeAsync(observer).ConfigureAwait(false);
                }

                var d = new CompositeAsyncDisposable();

                foreach (var joinObserver in externalSubscriptions.Values)
                {
                    await joinObserver.SubscribeAsync(gate).ConfigureAwait(false);
                    await d.AddAsync(joinObserver).ConfigureAwait(false);
                }

                return d;
            }));
        }
Example #5
0
        public static IAsyncObservable <IAsyncObservable <TSource> > Window <TSource, TWindowBoundary>(this IAsyncObservable <TSource> source, IAsyncObservable <TWindowBoundary> windowBoundaries)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (windowBoundaries == null)
            {
                throw new ArgumentNullException(nameof(windowBoundaries));
            }

            return(Create <IAsyncObservable <TSource> >(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var(sourceObserver, boundariesObserver, subscription) = await AsyncObserver.Window <TSource, TWindowBoundary>(observer, d).ConfigureAwait(false);

                var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false);
                await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                var boundariesSubscription = await windowBoundaries.SubscribeSafeAsync(boundariesObserver).ConfigureAwait(false);
                await d.AddAsync(boundariesSubscription).ConfigureAwait(false);

                return subscription;
            }));
        }
Example #6
0
        public static IAsyncObservable <TSource> Throttle <TSource, TThrottle>(this IAsyncObservable <TSource> source, Func <TSource, IAsyncObservable <TThrottle> > throttleSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (throttleSelector == null)
            {
                throw new ArgumentNullException(nameof(throttleSelector));
            }

            return(Create <TSource>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var(sink, throttler) = AsyncObserver.Throttle(observer, throttleSelector);

                await d.AddAsync(throttler).ConfigureAwait(false);

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

                await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                return d;
            }));
        }
Example #7
0
        public static IAsyncObservable <TSource> Throttle <TSource>(this IAsyncObservable <TSource> source, TimeSpan dueTime, IAsyncScheduler scheduler)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (dueTime < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(dueTime));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(Create <TSource>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var(sink, throttler) = AsyncObserver.Throttle(observer, dueTime, scheduler);

                await d.AddAsync(throttler).ConfigureAwait(false);

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

                await d.AddAsync(sourceSubscription).ConfigureAwait(false);

                return d;
            }));
        }
Example #8
0
        public static AsyncAsyncSubject <TSource> RunAsync <TSource>(this IConnectableAsyncObservable <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 d = new CompositeAsyncDisposable();

            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.
                }
                else
                {
                    var ignored = d.AddAsync(t.Result);

                    source.ConnectAsync().ContinueWith(t2 =>
                    {
                        if (t2.Exception == null)
                        {
                            var ignored2 = d.AddAsync(t2.Result);
                        }
                    });
                }
            });

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

            return(subject);
        }
Example #9
0
        public static IAsyncObservable <TResult> Multicast <TSource, TIntermediate, TResult>(this IAsyncObservable <TSource> source, Func <ValueTask <IAsyncSubject <TSource, TIntermediate> > > subjectFactory, Func <IAsyncObservable <TIntermediate>, ValueTask <IAsyncObservable <TResult> > > selector)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }
            if (subjectFactory == null)
            {
                throw new ArgumentNullException(nameof(subjectFactory));
            }
            if (selector == null)
            {
                throw new ArgumentNullException(nameof(selector));
            }

            // REVIEW: Use a lifted observer operator.

            return(CreateAsyncObservable <TResult> .From(
                       source,
                       (subjectFactory, selector),
                       static async (source, state, observer) =>
            {
                var observable = default(IAsyncObservable <TResult>);
                var connectable = default(IConnectableAsyncObservable <TIntermediate>);

                try
                {
                    var subject = await state.subjectFactory().ConfigureAwait(false);
                    connectable = new ConnectableAsyncObservable <TSource, TIntermediate>(source, subject);
                    observable = await state.selector(connectable).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    await observer.OnErrorAsync(ex).ConfigureAwait(false);
                    return AsyncDisposable.Nop;
                }

                var d = new CompositeAsyncDisposable();

                var subscription = await observable.SubscribeAsync(observer).ConfigureAwait(false);
                await d.AddAsync(subscription).ConfigureAwait(false);

                var connection = await connectable.ConnectAsync().ConfigureAwait(false);
                await d.AddAsync(connection).ConfigureAwait(false);

                return d;
            }));
        }
Example #10
0
        public static IAsyncObservable <TResult> Join <TLeft, TRight, TLeftDuration, TRightDuration, TResult>(this IAsyncObservable <TLeft> left, IAsyncObservable <TRight> right, Func <TLeft, IAsyncObservable <TLeftDuration> > leftDurationSelector, Func <TRight, IAsyncObservable <TRightDuration> > rightDurationSelector, Func <TLeft, TRight, TResult> resultSelector)
        {
            if (left == null)
            {
                throw new ArgumentNullException(nameof(left));
            }
            if (right == null)
            {
                throw new ArgumentNullException(nameof(right));
            }
            if (leftDurationSelector == null)
            {
                throw new ArgumentNullException(nameof(leftDurationSelector));
            }
            if (rightDurationSelector == null)
            {
                throw new ArgumentNullException(nameof(rightDurationSelector));
            }
            if (resultSelector == null)
            {
                throw new ArgumentNullException(nameof(resultSelector));
            }

            return(CreateAsyncObservable <TResult> .From(
                       left,
                       (right, leftDurationSelector, rightDurationSelector, resultSelector),
                       static async (left, state, observer) =>
            {
                var subscriptions = new CompositeAsyncDisposable();

                var(leftObserver, rightObserver, disposable) = AsyncObserver.Join(observer, subscriptions, state.leftDurationSelector, state.rightDurationSelector, state.resultSelector);

                var leftSubscription = await left.SubscribeSafeAsync(leftObserver).ConfigureAwait(false);
                await subscriptions.AddAsync(leftSubscription).ConfigureAwait(false);

                var rightSubscription = await state.right.SubscribeSafeAsync(rightObserver).ConfigureAwait(false);
                await subscriptions.AddAsync(rightSubscription).ConfigureAwait(false);

                return disposable;
            }));
        }
        public static IAsyncObservable <TSource> ToAsyncObservable <TSource>(this IObservable <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(Create <TSource>(async observer =>
            {
                var d = new CompositeAsyncDisposable();

                var subscribeTask = await subscribeScheduler.ScheduleAsync(async ct =>
                {
                    ct.ThrowIfCancellationRequested();

                    var disposable = source.Subscribe(AsyncObserver.ToObserver(observer));

                    var disposeTask = AsyncDisposable.Create(() => disposeScheduler.ExecuteAsync(_ =>
                    {
                        disposable.Dispose();
                        return default;
                    }));

                    await d.AddAsync(disposeTask).RendezVous(subscribeScheduler);
                }).ConfigureAwait(false);

                await d.AddAsync(subscribeTask).ConfigureAwait(false);

                return d;
            }));
        }