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); })); }
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); })); }
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; })); }
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; })); }
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 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); }
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; })); }
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)); } }
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); }
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); })); }