// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT License. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Linq; using System.Reactive.Concurrency; namespace System.Reactive.Linq { using ObservableImpl; internal partial class QueryLanguage { #region - Append - public virtual IObservable Append(IObservable source, TSource value) { return Append_(source, value, SchedulerDefaults.ConstantTimeOperations); } public virtual IObservable Append(IObservable source, TSource value, IScheduler scheduler) { return Append_(source, value, scheduler); } private static IObservable Append_(IObservable source, TSource value, IScheduler scheduler) { if (source is AppendPrepend.IAppendPrepend ap && ap.Scheduler == scheduler) { return ap.Append(value); } if (scheduler == ImmediateScheduler.Instance) { return new AppendPrepend.SingleImmediate(source, value, append: true); } return new AppendPrepend.SingleValue(source, value, scheduler, append: true); } #endregion #region + AsObservable + public virtual IObservable AsObservable(IObservable source) { if (source is AsObservable asObservable) { return asObservable; } return new AsObservable(source); } #endregion #region + Buffer + public virtual IObservable> Buffer(IObservable source, int count) { return new Buffer.CountExact(source, count); } public virtual IObservable> Buffer(IObservable source, int count, int skip) { if (count > skip) { return new Buffer.CountOverlap(source, count, skip); } if (count < skip) { return new Buffer.CountSkip(source, count, skip); } // count == skip return new Buffer.CountExact(source, count); } #endregion #region + Dematerialize + public virtual IObservable Dematerialize(IObservable> source) { if (source is Materialize materialize) { return materialize.Dematerialize(); } return new Dematerialize(source); } #endregion #region + DistinctUntilChanged + public virtual IObservable DistinctUntilChanged(IObservable source) { return DistinctUntilChanged_(source, x => x, EqualityComparer.Default); } public virtual IObservable DistinctUntilChanged(IObservable source, IEqualityComparer comparer) { return DistinctUntilChanged_(source, x => x, comparer); } public virtual IObservable DistinctUntilChanged(IObservable source, Func keySelector) { return DistinctUntilChanged_(source, keySelector, EqualityComparer.Default); } public virtual IObservable DistinctUntilChanged(IObservable source, Func keySelector, IEqualityComparer comparer) { return DistinctUntilChanged_(source, keySelector, comparer); } private static IObservable DistinctUntilChanged_(IObservable source, Func keySelector, IEqualityComparer comparer) { return new DistinctUntilChanged(source, keySelector, comparer); } #endregion #region + Do + public virtual IObservable Do(IObservable source, Action onNext) { return new Do.OnNext(source, onNext); } public virtual IObservable Do(IObservable source, Action onNext, Action onCompleted) { return Do_(source, onNext, Stubs.Ignore, onCompleted); } public virtual IObservable Do(IObservable source, Action onNext, Action onError) { return Do_(source, onNext, onError, Stubs.Nop); } public virtual IObservable Do(IObservable source, Action onNext, Action onError, Action onCompleted) { return Do_(source, onNext, onError, onCompleted); } public virtual IObservable Do(IObservable source, IObserver observer) { return new Do.Observer(source, observer); } private static IObservable Do_(IObservable source, Action onNext, Action onError, Action onCompleted) { return new Do.Actions(source, onNext, onError, onCompleted); } #endregion #region + Finally + public virtual IObservable Finally(IObservable source, Action finallyAction) { return new Finally(source, finallyAction); } #endregion #region + IgnoreElements + public virtual IObservable IgnoreElements(IObservable source) { if (source is IgnoreElements ignoreElements) { return ignoreElements; } return new IgnoreElements(source); } #endregion #region + Materialize + public virtual IObservable> Materialize(IObservable source) { // // NOTE: Peephole optimization of xs.Dematerialize().Materialize() should not be performed. It's possible for xs to // contain multiple terminal notifications, which won't survive a Dematerialize().Materialize() chain. In case // a reduction to xs.AsObservable() would be performed, those notification elements would survive. // return new Materialize(source); } #endregion #region - Prepend - public virtual IObservable Prepend(IObservable source, TSource value) { return Prepend_(source, value, SchedulerDefaults.ConstantTimeOperations); } public virtual IObservable Prepend(IObservable source, TSource value, IScheduler scheduler) { return Prepend_(source, value, scheduler); } private static IObservable Prepend_(IObservable source, TSource value, IScheduler scheduler) { if (source is AppendPrepend.IAppendPrepend ap && ap.Scheduler == scheduler) { return ap.Prepend(value); } if (scheduler == ImmediateScheduler.Instance) { return new AppendPrepend.SingleImmediate(source, value, append: false); } return new AppendPrepend.SingleValue(source, value, scheduler, append: false); } #endregion #region - Repeat - public virtual IObservable Repeat(IObservable source) { return RepeatInfinite(source).Concat(); } private static IEnumerable RepeatInfinite(T value) { while (true) { yield return value; } } public virtual IObservable Repeat(IObservable source, int repeatCount) { return Enumerable.Repeat(source, repeatCount).Concat(); } public virtual IObservable RepeatWhen(IObservable source, Func, IObservable> handler) { return new RepeatWhen(source, handler); } #endregion #region - Retry - public virtual IObservable Retry(IObservable source) { return RepeatInfinite(source).Catch(); } public virtual IObservable Retry(IObservable source, int retryCount) { return Enumerable.Repeat(source, retryCount).Catch(); } public virtual IObservable RetryWhen(IObservable source, Func, IObservable> handler) { return new RetryWhen(source, handler); } #endregion #region + Scan + public virtual IObservable Scan(IObservable source, TAccumulate seed, Func accumulator) { return new Scan(source, seed, accumulator); } public virtual IObservable Scan(IObservable source, Func accumulator) { return new Scan(source, accumulator); } #endregion #region + SkipLast + public virtual IObservable SkipLast(IObservable source, int count) { return new SkipLast.Count(source, count); } #endregion #region - StartWith - public virtual IObservable StartWith(IObservable source, params TSource[] values) { return StartWith_(source, SchedulerDefaults.ConstantTimeOperations, values); } public virtual IObservable StartWith(IObservable source, IScheduler scheduler, params TSource[] values) { return StartWith_(source, scheduler, values); } public virtual IObservable StartWith(IObservable source, IEnumerable values) { return StartWith(source, SchedulerDefaults.ConstantTimeOperations, values); } public virtual IObservable StartWith(IObservable source, IScheduler scheduler, IEnumerable values) { // // NOTE: For some reason, someone introduced this signature in the Observable class, which is inconsistent with the Rx pattern // of putting the IScheduler last. It also wasn't wired up through IQueryLanguage. When introducing this method in the // IQueryLanguage interface, we went for consistency with the public API, hence the odd position of the IScheduler. // if (values is not TSource[] valueArray) { var valueList = new List(values); valueArray = valueList.ToArray(); } return StartWith_(source, scheduler, valueArray); } private static IObservable StartWith_(IObservable source, IScheduler scheduler, params TSource[] values) { return values.ToObservable(scheduler).Concat(source); } #endregion #region + TakeLast + public virtual IObservable TakeLast(IObservable source, int count) { return TakeLast_(source, count, SchedulerDefaults.Iteration); } public virtual IObservable TakeLast(IObservable source, int count, IScheduler scheduler) { return TakeLast_(source, count, scheduler); } private static IObservable TakeLast_(IObservable source, int count, IScheduler scheduler) { return new TakeLast.Count(source, count, scheduler); } public virtual IObservable> TakeLastBuffer(IObservable source, int count) { return new TakeLastBuffer.Count(source, count); } #endregion #region + Window + public virtual IObservable> Window(IObservable source, int count, int skip) { return Window_(source, count, skip); } public virtual IObservable> Window(IObservable source, int count) { return Window_(source, count, count); } private static IObservable> Window_(IObservable source, int count, int skip) { return new Window.Count(source, count, skip); } #endregion } }