// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Reactive.Disposables; using System.Reactive.Linq; namespace System.Reactive.Joins { internal interface IJoinObserver : IDisposable { void Subscribe(object gate); void Dequeue(); } internal sealed class JoinObserver : ObserverBase>, IJoinObserver { private object gate; private readonly IObservable source; private readonly Action onError; private List activePlans; public Queue> Queue { get; private set; } private readonly SingleAssignmentDisposable subscription; private bool isDisposed; public JoinObserver(IObservable source, Action onError) { this.source = source; this.onError = onError; Queue = new Queue>(); subscription = new SingleAssignmentDisposable(); activePlans = new List(); } public void AddActivePlan(ActivePlan activePlan) { activePlans.Add(activePlan); } public void Subscribe(object gate) { this.gate = gate; subscription.Disposable = source.Materialize().SubscribeSafe(this); } public void Dequeue() { Queue.Dequeue(); } protected override void OnNextCore(Notification notification) { lock (gate) { if (!isDisposed) { if (notification.Kind == NotificationKind.OnError) { onError(notification.Exception); return; } Queue.Enqueue(notification); foreach (var activePlan in activePlans.ToArray()) activePlan.Match(); } } } protected override void OnErrorCore(Exception exception) { } protected override void OnCompletedCore() { } internal void RemoveActivePlan(ActivePlan activePlan) { activePlans.Remove(activePlan); if (activePlans.Count == 0) Dispose(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (!isDisposed) { if (disposing) subscription.Dispose(); isDisposed = true; } } } }