Esempio n. 1
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;
            }));
        }
Esempio n. 2
0
        public static Task <IAsyncDisposable> Repeat <TSource>(IAsyncObserver <TSource> observer, TSource value, int repeatCount, IAsyncScheduler scheduler)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (repeatCount < 0)
            {
                throw new ArgumentNullException(nameof(repeatCount));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(scheduler.ScheduleAsync(async ct =>
            {
                var i = 0;

                while (!ct.IsCancellationRequested && i < repeatCount)
                {
                    await observer.OnNextAsync(value).RendezVous(scheduler, ct);

                    i++;
                }

                if (i == repeatCount)
                {
                    await observer.OnCompletedAsync().RendezVous(scheduler, ct);
                }
            }));
        }
Esempio n. 3
0
        public static ValueTask <IAsyncDisposable> Timer(IAsyncObserver <long> observer, DateTimeOffset dueTime, TimeSpan period, IAsyncScheduler scheduler)
        {
            if (period < TimeSpan.Zero)
            {
                throw new ArgumentOutOfRangeException(nameof(period));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            var tick = 0L;

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

                // TODO: Compensate for drift by adding stopwatch functionality.

                do
                {
                    await observer.OnNextAsync(tick++).RendezVous(scheduler, ct);

                    await scheduler.Delay(period, ct).RendezVous(scheduler, ct);
                } while (!ct.IsCancellationRequested);
            }, dueTime));
        }
Esempio n. 4
0
        public static ValueTask <IAsyncDisposable> Range(IAsyncObserver <int> observer, int start, int count, IAsyncScheduler scheduler)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (count < 0 || ((long)start) + count - 1 > int.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

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

                for (int i = start, end = start + count - 1; i <= end && !ct.IsCancellationRequested; i++)
                {
                    await observer.OnNextAsync(i).RendezVous(scheduler, ct);
                }

                if (ct.IsCancellationRequested)
                {
                    return;
                }

                await observer.OnCompletedAsync().RendezVous(scheduler, ct);
            }));
        }
Esempio n. 5
0
        public static async ValueTask Delay(this IAsyncScheduler scheduler, TimeSpan dueTime, CancellationToken token = default)
        {
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            var tcs = new TaskCompletionSource <bool>();

            var task = await scheduler.ScheduleAsync(ct =>
            {
                if (ct.IsCancellationRequested)
                {
                    tcs.TrySetCanceled(ct);
                }
                else
                {
                    tcs.SetResult(true);
                }

                return(Task.CompletedTask);
            }, dueTime);

            using (token.Register(() => task.DisposeAsync()))
            {
                await tcs.Task;
            }
        }
Esempio n. 6
0
        public static ValueTask <IAsyncDisposable> Return <TSource>(IAsyncObserver <TSource> observer, TSource value, IAsyncScheduler scheduler)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

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

                await observer.OnNextAsync(value).RendezVous(scheduler, ct);

                if (ct.IsCancellationRequested)
                {
                    return;
                }

                await observer.OnCompletedAsync().RendezVous(scheduler, ct);
            }));
        }
Esempio n. 7
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. 8
0
        public static Task <IAsyncDisposable> Empty <TSource>(IAsyncObserver <TSource> observer, IAsyncScheduler scheduler)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(scheduler.ScheduleAsync(async ct =>
            {
                if (!ct.IsCancellationRequested)
                {
                    await observer.OnCompletedAsync().RendezVous(scheduler, ct);
                }
            }));
        }
Esempio n. 9
0
        public static async ValueTask <TResult> ExecuteAsync <TResult>(this IAsyncScheduler scheduler, Func <CancellationToken, ValueTask <TResult> > action, CancellationToken token = default)
        {
            var tcs = new TaskCompletionSource <TResult>();

            var d = await scheduler.ScheduleAsync(async ct =>
            {
                var res = default(TResult);

                try
                {
                    ct.ThrowIfCancellationRequested();

                    res = await action(ct).RendezVous(scheduler, ct);
                }
                catch (OperationCanceledException ex) when(ex.CancellationToken == ct)
                {
                    tcs.TrySetCanceled(ct);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
                finally
                {
                    tcs.TrySetResult(res);
                }
            });

            using (token.Register(() =>
            {
                try
                {
                    d.DisposeAsync();
                }
                finally
                {
                    tcs.TrySetCanceled(token);
                }
            }))
            {
                return(await tcs.Task.ConfigureAwait(false));
            }
        }
Esempio n. 10
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(Create <TSource>(async observer =>
            {
                var m = new SingleAssignmentAsyncDisposable();
                var d = new SerialAsyncDisposable();

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

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

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

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

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

                return d;
            }));
        }
Esempio n. 11
0
        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 Task.CompletedTask;
                    }));

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

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

                return d;
            }));
        }
Esempio n. 12
0
        public static ValueTask <IAsyncDisposable> Timer(IAsyncObserver <long> observer, TimeSpan dueTime, IAsyncScheduler scheduler)
        {
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

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

                await observer.OnNextAsync(0L).RendezVous(scheduler, ct);

                if (ct.IsCancellationRequested)
                {
                    return;
                }

                await observer.OnCompletedAsync().RendezVous(scheduler, ct);
            }, dueTime));
        }
Esempio n. 13
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. 14
0
        public static Task <IAsyncDisposable> Generate <TState, TResult>(IAsyncObserver <TResult> observer, TState initialState, Func <TState, Task <bool> > condition, Func <TState, Task <TState> > iterate, Func <TState, Task <TResult> > resultSelector, Func <TState, Task <DateTimeOffset> > timeSelector, IAsyncScheduler scheduler)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (condition == null)
            {
                throw new ArgumentNullException(nameof(condition));
            }
            if (iterate == null)
            {
                throw new ArgumentNullException(nameof(iterate));
            }
            if (resultSelector == null)
            {
                throw new ArgumentNullException(nameof(resultSelector));
            }
            if (timeSelector == null)
            {
                throw new ArgumentNullException(nameof(timeSelector));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            return(scheduler.ScheduleAsync(async ct =>
            {
                var first = true;
                var state = initialState;

                while (!ct.IsCancellationRequested)
                {
                    var hasResult = false;
                    var result = default(TResult);
                    var nextDue = default(DateTimeOffset);

                    try
                    {
                        if (first)
                        {
                            first = false;
                        }
                        else
                        {
                            state = await iterate(state).RendezVous(scheduler, ct);
                        }

                        hasResult = await condition(state).RendezVous(scheduler, ct);

                        if (hasResult)
                        {
                            result = await resultSelector(state).RendezVous(scheduler, ct);
                            nextDue = await timeSelector(state).RendezVous(scheduler, ct);
                        }
                    }
                    catch (Exception ex)
                    {
                        await observer.OnErrorAsync(ex).RendezVous(scheduler, ct);
                        return;
                    }

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

                    await scheduler.Delay(nextDue).RendezVous(scheduler, ct);
                }

                if (!ct.IsCancellationRequested)
                {
                    await observer.OnCompletedAsync().RendezVous(scheduler, ct);
                }
            }));
        }
Esempio n. 15
0
        protected override async Task ScheduleAsync()
        {
            var d = await _scheduler.ScheduleAsync(RunAsync).ConfigureAwait(false);

            await _disposable.AssignAsync(d).ConfigureAwait(false);
        }
Esempio n. 16
0
        public static Task <IAsyncDisposable> AcceptAsync(this Task task, IAsyncObserver <Unit> observer, IAsyncScheduler scheduler)
        {
            if (task == null)
            {
                throw new ArgumentNullException(nameof(task));
            }
            if (observer == null)
            {
                throw new ArgumentNullException(nameof(observer));
            }
            if (scheduler == null)
            {
                throw new ArgumentNullException(nameof(scheduler));
            }

            Task <IAsyncDisposable> CompleteAsync()
            {
                return(scheduler.ScheduleAsync(async ct =>
                {
                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    switch (task.Status)
                    {
                    case TaskStatus.RanToCompletion:
                        await observer.OnNextAsync(Unit.Default).RendezVous(scheduler, ct);
                        await observer.OnCompletedAsync().RendezVous(scheduler, ct);
                        break;

                    case TaskStatus.Faulted:
                        await observer.OnErrorAsync(task.Exception.InnerException).RendezVous(scheduler, ct);
                        break;

                    case TaskStatus.Canceled:
                        await observer.OnErrorAsync(new TaskCanceledException(task)).RendezVous(scheduler, ct);
                        break;
                    }
                }));
            }

            Task <IAsyncDisposable> CoreAsync()
            {
                if (task.IsCompleted)
                {
                    return(CompleteAsync());
                }
                else
                {
                    var tco = TaskContinuationOptions.None;

                    if (scheduler == ImmediateAsyncScheduler.Instance)
                    {
                        tco = TaskContinuationOptions.ExecuteSynchronously;
                    }

                    var subject = new SequentialAsyncAsyncSubject <Unit>();

                    task.ContinueWith(t => CompleteAsync(), tco);

                    return(subject.SubscribeAsync(observer));
                }
            }

            return(CoreAsync());
        }