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 <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(CreateAsyncObservable <TSource> .From( source, (count, scheduler), static async (source, state, observer) => { var(sink, drain) = AsyncObserver.TakeLast(observer, state.count, state.scheduler); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
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 <TResult> If <TResult>(Func <ValueTask <bool> > condition, IAsyncObservable <TResult> thenSource, IAsyncObservable <TResult> elseSource) { if (condition == null) { throw new ArgumentNullException(nameof(condition)); } if (thenSource == null) { throw new ArgumentNullException(nameof(thenSource)); } if (elseSource == null) { throw new ArgumentNullException(nameof(elseSource)); } return(CreateAsyncObservable <TResult> .From( thenSource, (elseSource, condition), static async (thenSource, state, observer) => { var b = default(bool); try { b = await state.condition().ConfigureAwait(false); } catch (Exception ex) { return await Throw <TResult>(ex).SubscribeAsync(observer).ConfigureAwait(false); } return await(b ? thenSource : state.elseSource).SubscribeSafeAsync(observer).ConfigureAwait(false); })); }
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(CreateAsyncObservable <TSource> .From( source, (dueTime, other, scheduler), static async (source, state, observer) => { var sourceSubscription = new SingleAssignmentAsyncDisposable(); var(sink, disposable) = await AsyncObserver.Timeout(observer, sourceSubscription, state.dueTime, state.other, state.scheduler).ConfigureAwait(false); var sourceSubscriptionInner = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); await sourceSubscription.AssignAsync(sourceSubscriptionInner).ConfigureAwait(false); return disposable; })); }
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(CreateAsyncObservable <TSource> .From( source, (duration, clock), static async (source, state, observer) => { var(sink, drain) = AsyncObserver.TakeLast(observer, state.duration, state.clock); var subscription = await source.SubscribeSafeAsync(sink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(subscription, drain); })); }
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(CreateAsyncObservable <TSource> .From( source, (dueTime, scheduler), static async (source, state, observer) => { var d = new CompositeAsyncDisposable(); var(sink, throttler) = AsyncObserver.Throttle(observer, state.dueTime, state.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 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 <TSource> Prepend <TSource>(this IAsyncObservable <TSource> source, TSource value, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } return(CreateAsyncObservable <TSource> .From( source, (scheduler, value), static (source, state, observer) => AsyncObserver.Prepend(observer, source, state.value, state.scheduler))); }
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 IAsyncObservable <ILookup <TKey, TValue> > ToLookup <TSource, TKey, TValue>(this IAsyncObservable <TSource> source, Func <TSource, ValueTask <TKey> > keySelector, Func <TSource, ValueTask <TValue> > valueSelector) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } if (valueSelector == null) { throw new ArgumentNullException(nameof(valueSelector)); } return(CreateAsyncObservable <ILookup <TKey, TValue> > .From( source, (keySelector, valueSelector), static (source, state, observer) => source.SubscribeSafeAsync(AsyncObserver.ToLookup(observer, state.keySelector, state.valueSelector)))); }
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> Sample <TSource>(this IAsyncObservable <TSource> source, TimeSpan interval, IAsyncScheduler scheduler) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (scheduler == null) { throw new ArgumentNullException(nameof(scheduler)); } return(CreateAsyncObservable <TSource> .From( source, (scheduler, interval), static async (source, state, observer) => { var(sourceSink, sampler) = await AsyncObserver.Sample(observer, state.interval, state.scheduler).ConfigureAwait(false); var sourceSubscription = await source.SubscribeSafeAsync(sourceSink).ConfigureAwait(false); return StableCompositeAsyncDisposable.Create(sourceSubscription, sampler); })); }
public static IAsyncObservable <IDictionary <TKey, TValue> > ToDictionary <TSource, TKey, TValue>(this IAsyncObservable <TSource> source, Func <TSource, TKey> keySelector, Func <TSource, TValue> valueSelector, IEqualityComparer <TKey> comparer) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (keySelector == null) { throw new ArgumentNullException(nameof(keySelector)); } if (valueSelector == null) { throw new ArgumentNullException(nameof(valueSelector)); } if (comparer == null) { throw new ArgumentNullException(nameof(comparer)); } return(CreateAsyncObservable <IDictionary <TKey, TValue> > .From( source, (keySelector, valueSelector, comparer), static (source, state, observer) => source.SubscribeSafeAsync(AsyncObserver.ToDictionary(observer, state.keySelector, state.valueSelector, state.comparer))));; }
internal static IAsyncObservable <TSource> Create <TSource, TState>(IAsyncObservable <TSource> source, TState state, Func <IAsyncObservable <TSource>, TState, IAsyncObserver <TSource>, ValueTask <IAsyncDisposable> > subscribeAsync) { return(CreateAsyncObservable <TSource> .From(source, state, subscribeAsync)); }