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