public static IAsyncObservable <TSource> TakeLast <TSource>(this IAsyncObservable <TSource> source, TimeSpan duration, IClock clock) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (duration < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(duration)); } if (clock == null) { throw new ArgumentNullException(nameof(clock)); } if (duration == TimeSpan.Zero) { return(Empty <TSource>()); } return(Create <TSource>(async observer => { var(sink, drain) = AsyncObserver.TakeLast(observer, duration, clock); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
public static Task <IAsyncDisposable> Repeat <TSource>(IAsyncObserver <TSource> observer, IAsyncObservable <TSource> source, int repeatCount) { if (observer == null) { throw new ArgumentNullException(nameof(observer)); } if (source == null) { throw new ArgumentNullException(nameof(source)); } if (repeatCount < 0) { throw new ArgumentNullException(nameof(repeatCount)); } async Task <IAsyncDisposable> CoreAsync() { var(sink, inner) = Concat(observer, Enumerable.Repeat(source, repeatCount).GetEnumerator()); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return(StableCompositeAsyncDisposable.Create(subscription, inner)); } return(CoreAsync()); }
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> TakeLast <TSource>(this IAsyncObservable <TSource> source, int count, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } if (count == 0) { return(Empty <TSource>()); } return(Create <TSource>(async observer => { var(sink, drain) = AsyncObserver.TakeLast(observer, count, scheduler); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
public static IAsyncObservable <IList <TSource> > Zip <TSource>(params IAsyncObservable <TSource>[] sources) { if (sources == null) { throw new ArgumentNullException(nameof(sources)); } return(Create <IList <TSource> >(async observer => { var count = sources.Length; var observers = AsyncObserver.Zip(observer, count); var tasks = new Task <IAsyncDisposable> [count]; for (var i = 0; i < count; i++) { tasks[i] = sources[i].SubscribeSafeAsync(observers[i]).AsTask(); } await Task.WhenAll(tasks).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(tasks.Select(t => t.Result)); })); }
public static IAsyncObservable <TSource> SkipUntil <TSource>(this IAsyncObservable <TSource> source, DateTimeOffset endTime, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } // REVIEW: May be easier to just use SkipUntil with a Timer parameter. Do we want SkipUntil on the observer? return(CreateAsyncObservable <TSource> .From( source, (scheduler, endTime), static async (source, state, observer) => { var(sourceObserver, timer) = await AsyncObserver.SkipUntil(observer, state.endTime).ConfigureAwait(false); var subscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, timer); })); }
public static IAsyncObservable <bool> SequenceEqual <TSource>(this IAsyncObservable <TSource> first, IAsyncObservable <TSource> second, IEqualityComparer <TSource> comparer) { if (first == null) { throw new ArgumentNullException(nameof(first)); } if (second == null) { throw new ArgumentNullException(nameof(second)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } return(CreateAsyncObservable <bool> .From( first, (second, comparer), static async (first, state, observer) => { var(firstObserver, secondObserver) = AsyncObserver.SequenceEqual(observer, state.comparer); var firstTask = first.SubscribeSafeAsync(firstObserver); var secondTask = state.second.SubscribeSafeAsync(secondObserver); // REVIEW: Consider concurrent subscriptions. var d1 = await firstTask.ConfigureAwait(false); var d2 = await secondTask.ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(d1, d2); })); }
public static IAsyncObservable <TResult> SelectMany <TSource, TCollection, TResult>(this IAsyncObservable <TSource> source, Func <TSource, ValueTask <IAsyncObservable <TCollection> > > collectionSelector, Func <TSource, TCollection, ValueTask <TResult> > resultSelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (collectionSelector == null) { throw new ArgumentNullException(nameof(collectionSelector)); } if (resultSelector == null) { throw new ArgumentNullException(nameof(resultSelector)); } return(CreateAsyncObservable <TResult> .From( source, (collectionSelector, resultSelector), static async (source, state, observer) => { var(sink, inner) = AsyncObserver.SelectMany(observer, state.collectionSelector, state.resultSelector); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
public static IAsyncObservable <TSource> Skip <TSource>(this IAsyncObservable <TSource> source, TimeSpan duration, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (duration < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(duration)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } if (duration == TimeSpan.Zero) { return(source); } // REVIEW: May be easier to just use SkipUntil with a Timer parameter. Do we want Skip on the observer? return(Create <TSource>(async observer => { var(sourceObserver, timer) = await AsyncObserver.Skip(observer, duration).ConfigureAwait(false); var subscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, timer); })); }
public static IAsyncObservable <TSource> StartAsync <TSource>(Func <CancellationToken, Task <TSource> > functionAsync, IAsyncScheduler scheduler) { if (functionAsync == null) { throw new ArgumentNullException(nameof(functionAsync)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } var cancel = new CancellationAsyncDisposable(); var task = default(Task <TSource>); try { task = functionAsync(cancel.Token); } catch (Exception ex) { return(Throw <TSource>(ex)); } return(Create <TSource>(async observer => { var subscription = await task.ToAsyncObservable(scheduler).SubscribeAsync(observer).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(cancel, subscription); })); }
public static IAsyncObservable <TSource> Catch <TSource>(this IEnumerable <IAsyncObservable <TSource> > sources) { if (sources == null) { throw new ArgumentNullException(nameof(sources)); } return(Create <TSource>(async observer => { var enumerator = sources.GetEnumerator(); if (!enumerator.MoveNext()) { return AsyncDisposable.Nop; // REVIEW: Is Never behavior right here? } var source = enumerator.Current; var(sink, inner) = AsyncObserver.Catch(observer, enumerator); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
public static IAsyncObservable <IList <TSource> > Buffer <TSource>(this IAsyncObservable <TSource> source, TimeSpan timeSpan, int count, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (timeSpan < TimeSpan.Zero) { throw new ArgumentNullException(nameof(timeSpan)); } if (count <= 0) { throw new ArgumentNullException(nameof(count)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } return(Create <IList <TSource> >(async observer => { var(sink, timer) = await AsyncObserver.Buffer(observer, timeSpan, count, scheduler).ConfigureAwait(false); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, timer); })); }
public static IAsyncObservable <TSource> SkipUntil <TSource, TUntil>(this IAsyncObservable <TSource> source, IAsyncObservable <TUntil> until) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (until == null) { throw new ArgumentNullException(nameof(until)); } return(Create <TSource>(async observer => { var(sourceObserver, untilObserver) = AsyncObserver.SkipUntil <TSource, TUntil>(observer); var sourceTask = source.SubscribeSafeAsync(sourceObserver); var untilTask = until.SubscribeSafeAsync(untilObserver); // REVIEW: Consider concurrent subscriptions. var d1 = await sourceTask.ConfigureAwait(false); var d2 = await untilTask.ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(d1, d2); })); }
protected override async Task <IAsyncDisposable> SubscribeAsyncCore(IAsyncObserver <TSource> observer) { if (_disposable != null) { var d = await _disposable.GetDisposableAsync().ConfigureAwait(false); var s = await _subject.SubscribeAsync(observer).ConfigureAwait(false); return(StableCompositeAsyncDisposable.Create(d, s)); } return(await _subject.SubscribeAsync(observer).ConfigureAwait(false)); }
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 IAsyncObservable <TSource> Delay <TSource>(this IAsyncObservable <TSource> source, TimeSpan dueTime) { if (source == null) { throw new ArgumentNullException(nameof(source)); } return(Create <TSource>(async observer => { var(sink, drain) = await AsyncObserver.Delay(observer, dueTime).ConfigureAwait(false); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
public static IAsyncObservable <TSource> Sample <TSource>(this IAsyncObservable <TSource> source, TimeSpan interval) { if (source == null) { throw new ArgumentNullException(nameof(source)); } return(Create <TSource>(async observer => { var(sourceSink, sampler) = await AsyncObserver.Sample(observer, interval).ConfigureAwait(false); var sourceSubscription = await source.SubscribeSafeAsync(sourceSink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(sourceSubscription, sampler); })); }
public static IAsyncObservable <TSource> Switch <TSource>(this IAsyncObservable <IAsyncObservable <TSource> > source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } return(Create <TSource>(async observer => { var(sink, cancel) = AsyncObserver.Switch(observer); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, cancel); })); }
public static IAsyncObservable <TResult> SelectMany <TSource, TResult>(this IAsyncObservable <TSource> source, Func <TSource, int, ValueTask <IAsyncObservable <TResult> > > selector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (selector == null) { throw new ArgumentNullException(nameof(selector)); } return(Create <TResult>(async observer => { var(sink, inner) = AsyncObserver.SelectMany(observer, selector); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
// 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 <IList <TSource> > Buffer <TSource, TBufferClosing>(this IAsyncObservable <TSource> source, Func <IAsyncObservable <TBufferClosing> > bufferClosingSelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (bufferClosingSelector == null) { throw new ArgumentNullException(nameof(bufferClosingSelector)); } return(Create <IList <TSource> >(async observer => { var(sourceObserver, closingDisposable) = await AsyncObserver.Buffer <TSource, TBufferClosing>(observer, bufferClosingSelector).ConfigureAwait(false); var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(sourceSubscription, closingDisposable); })); }
public static IAsyncObservable <TSource> OnErrorResumeNext <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(sink, inner) = AsyncObserver.OnErrorResumeNext(observer, second); var subscription = await first.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
public static IAsyncObservable <TSource> Retry <TSource>(this IAsyncObservable <TSource> source, int retryCount) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (retryCount < 0) { throw new ArgumentOutOfRangeException(nameof(retryCount)); } return(Create <TSource>(async observer => { var(sink, inner) = AsyncObserver.Retry(observer, source, retryCount); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
public static IAsyncObservable <TSource> ObserveOn <TSource>(this IAsyncObservable <TSource> source, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } return(Create <TSource>(async observer => { var(sink, drain) = await AsyncObserver.ObserveOn(observer, scheduler).ConfigureAwait(false); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
public static IAsyncObservable <IList <TSource> > Buffer <TSource, TBufferBoundary>(this IAsyncObservable <TSource> source, IAsyncObservable <TBufferBoundary> bufferBoundaries) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (bufferBoundaries == null) { throw new ArgumentNullException(nameof(bufferBoundaries)); } return(Create <IList <TSource> >(async observer => { var(sourceObserver, boundariesObserver) = AsyncObserver.Buffer <TSource, TBufferBoundary>(observer); var sourceSubscription = await source.SubscribeSafeAsync(sourceObserver).ConfigureAwait(false); var boundariesSubscription = await bufferBoundaries.SubscribeSafeAsync(boundariesObserver).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(sourceSubscription, boundariesSubscription); })); }
public static IAsyncObservable <TSource> Catch <TSource, TException>(this IAsyncObservable <TSource> source, Func <TException, ValueTask <IAsyncObservable <TSource> > > handler) where TException : Exception { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } return(Create <TSource>(async observer => { var(sink, inner) = AsyncObserver.Catch(observer, handler); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, inner); })); }
public static IAsyncObservable <TSource> Sample <TSource, TSample>(this IAsyncObservable <TSource> source, IAsyncObservable <TSample> sampler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (sampler == null) { throw new ArgumentNullException(nameof(sampler)); } return(CreateAsyncObservable <TSource> .From( source, sampler, static async (source, sampler, observer) => { var(sourceSink, samplerSink) = AsyncObserver.Sample <TSource, TSample>(observer); var sourceSubscription = await source.SubscribeSafeAsync(sourceSink).ConfigureAwait(false); var samplerSubscription = await sampler.SubscribeSafeAsync(samplerSink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(sourceSubscription, samplerSubscription); })); }
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); })); }
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)); } }