// 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.Reactive.Disposables; using System.Reactive.Joins; namespace System.Reactive.Linq { internal partial class QueryLanguage { #region And public virtual Pattern And(IObservable left, IObservable right) { return new Pattern(left, right); } #endregion #region Then public virtual Plan Then(IObservable source, Func selector) { return new Pattern(source).Then(selector); } #endregion #region When public virtual IObservable When(params Plan[] plans) { return When((IEnumerable>)plans); } public virtual IObservable When(IEnumerable> plans) { return new WhenObservable(plans); } private sealed class WhenObservable : ObservableBase { private readonly IEnumerable> _plans; public WhenObservable(IEnumerable> plans) { _plans = plans; } protected override IDisposable SubscribeCore(IObserver observer) { var externalSubscriptions = new Dictionary(); var gate = new object(); var activePlans = new List(); var outObserver = new OutObserver(observer, externalSubscriptions); try { void onDeactivate(ActivePlan activePlan) { activePlans.Remove(activePlan); if (activePlans.Count == 0) { outObserver.OnCompleted(); } } foreach (var plan in _plans) { activePlans.Add(plan.Activate(externalSubscriptions, outObserver, onDeactivate)); } } catch (Exception e) { // // [OK] Use of unsafe Subscribe: we're calling into a known producer implementation. // observer.OnError(e); return Disposable.Empty; } var group = new CompositeDisposable(externalSubscriptions.Values.Count); foreach (var joinObserver in externalSubscriptions.Values) { joinObserver.Subscribe(gate); group.Add(joinObserver); } return group; } private sealed class OutObserver : IObserver { private readonly IObserver _observer; private readonly Dictionary _externalSubscriptions; public OutObserver(IObserver observer, Dictionary externalSubscriptions) { _observer = observer; _externalSubscriptions = externalSubscriptions; } public void OnCompleted() { _observer.OnCompleted(); } public void OnError(Exception exception) { foreach (var po in _externalSubscriptions.Values) { po.Dispose(); } _observer.OnError(exception); } public void OnNext(TResult value) { _observer.OnNext(value); } } } #endregion } }