// 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.Diagnostics.CodeAnalysis; namespace System.Reactive.Linq { using ObservableImpl; internal partial class QueryLanguage { #region - Chunkify - public virtual IEnumerable> Chunkify(IObservable source) { return source.Collect>(() => new List(), (lst, x) => { lst.Add(x); return lst; }, _ => new List()); } #endregion #region + Collect + public virtual IEnumerable Collect(IObservable source, Func newCollector, Func merge) { return Collect_(source, newCollector, merge, _ => newCollector()); } public virtual IEnumerable Collect(IObservable source, Func getInitialCollector, Func merge, Func getNewCollector) { return Collect_(source, getInitialCollector, merge, getNewCollector); } private static IEnumerable Collect_(IObservable source, Func getInitialCollector, Func merge, Func getNewCollector) { return new Collect(source, getInitialCollector, merge, getNewCollector); } #endregion #region First public virtual TSource First(IObservable source) { return FirstOrDefaultInternal(source, throwOnEmpty: true)!; } public virtual TSource First(IObservable source, Func predicate) { return First(Where(source, predicate)); } #endregion #region FirstOrDefault [return: MaybeNull] public virtual TSource FirstOrDefault(IObservable source) { return FirstOrDefaultInternal(source, throwOnEmpty: false); } [return: MaybeNull] public virtual TSource FirstOrDefault(IObservable source, Func predicate) { return FirstOrDefault(Where(source, predicate)); } [return: MaybeNull] private static TSource FirstOrDefaultInternal(IObservable source, bool throwOnEmpty) { using var consumer = new FirstBlocking(); using (source.Subscribe(consumer)) { consumer.Wait(); } consumer._error?.Throw(); if (throwOnEmpty && !consumer._hasValue) { throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS); } return consumer._value; } #endregion #region + ForEach + public virtual void ForEach(IObservable source, Action onNext) { using var sink = new ForEach.Observer(onNext); using (source.SubscribeSafe(sink)) { sink.Wait(); } sink.Error?.Throw(); } public virtual void ForEach(IObservable source, Action onNext) { using var sink = new ForEach.ObserverIndexed(onNext); using (source.SubscribeSafe(sink)) { sink.Wait(); } sink.Error?.Throw(); } #endregion #region + GetEnumerator + public virtual IEnumerator GetEnumerator(IObservable source) { var e = new GetEnumerator(); return e.Run(source); } #endregion #region Last public virtual TSource Last(IObservable source) { return LastOrDefaultInternal(source, throwOnEmpty: true)!; } public virtual TSource Last(IObservable source, Func predicate) { return Last(Where(source, predicate)); } #endregion #region LastOrDefault [return: MaybeNull] public virtual TSource LastOrDefault(IObservable source) { return LastOrDefaultInternal(source, throwOnEmpty: false); } [return: MaybeNull] public virtual TSource LastOrDefault(IObservable source, Func predicate) { return LastOrDefault(Where(source, predicate)); } [return: MaybeNull] private static TSource LastOrDefaultInternal(IObservable source, bool throwOnEmpty) { using var consumer = new LastBlocking(); using (source.Subscribe(consumer)) { consumer.Wait(); } consumer._error?.Throw(); if (throwOnEmpty && !consumer._hasValue) { throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS); } return consumer._value; } #endregion #region + Latest + public virtual IEnumerable Latest(IObservable source) { return new Latest(source); } #endregion #region + MostRecent + public virtual IEnumerable MostRecent(IObservable source, TSource initialValue) { return new MostRecent(source, initialValue); } #endregion #region + Next + public virtual IEnumerable Next(IObservable source) { return new Next(source); } #endregion #region Single public virtual TSource Single(IObservable source) { return SingleOrDefaultInternal(source, throwOnEmpty: true)!; } public virtual TSource Single(IObservable source, Func predicate) { return Single(Where(source, predicate)); } #endregion #region SingleOrDefault [return: MaybeNull] public virtual TSource SingleOrDefault(IObservable source) { return SingleOrDefaultInternal(source, throwOnEmpty: false); } [return: MaybeNull] public virtual TSource SingleOrDefault(IObservable source, Func predicate) { return SingleOrDefault(Where(source, predicate)); } [return: MaybeNull] private static TSource SingleOrDefaultInternal(IObservable source, bool throwOnEmpty) { using var consumer = new SingleBlocking(); using (source.Subscribe(consumer)) { consumer.Wait(); } consumer._error?.Throw(); if (consumer._hasMoreThanOneElement) { throw new InvalidOperationException(Strings_Linq.MORE_THAN_ONE_ELEMENT); } if (throwOnEmpty && !consumer._hasValue) { throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS); } return consumer._value; } #endregion #region Wait public virtual TSource Wait(IObservable source) { return LastOrDefaultInternal(source, true)!; } #endregion } }