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; })); }
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); } })); }
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)); }
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); })); }
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; } }
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); })); }
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)); } }
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); } })); }
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)); } }
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; })); }
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; })); }
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)); }
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)); } }
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); } })); }
protected override async Task ScheduleAsync() { var d = await _scheduler.ScheduleAsync(RunAsync).ConfigureAwait(false); await _disposable.AssignAsync(d).ConfigureAwait(false); }
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()); }