Kit.Core/LibExternal/System.Reactive/Linq/QueryLanguage.Joins.cs

128 lines
4.2 KiB
C#

// 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<TLeft, TRight> And<TLeft, TRight>(IObservable<TLeft> left, IObservable<TRight> right)
{
return new Pattern<TLeft, TRight>(left, right);
}
#endregion
#region Then
public virtual Plan<TResult> Then<TSource, TResult>(IObservable<TSource> source, Func<TSource, TResult> selector)
{
return new Pattern<TSource>(source).Then(selector);
}
#endregion
#region When
public virtual IObservable<TResult> When<TResult>(params Plan<TResult>[] plans)
{
return When((IEnumerable<Plan<TResult>>)plans);
}
public virtual IObservable<TResult> When<TResult>(IEnumerable<Plan<TResult>> plans)
{
return new WhenObservable<TResult>(plans);
}
private sealed class WhenObservable<TResult> : ObservableBase<TResult>
{
private readonly IEnumerable<Plan<TResult>> _plans;
public WhenObservable(IEnumerable<Plan<TResult>> plans)
{
_plans = plans;
}
protected override IDisposable SubscribeCore(IObserver<TResult> observer)
{
var externalSubscriptions = new Dictionary<object, IJoinObserver>();
var gate = new object();
var activePlans = new List<ActivePlan>();
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<TResult>
{
private readonly IObserver<TResult> _observer;
private readonly Dictionary<object, IJoinObserver> _externalSubscriptions;
public OutObserver(IObserver<TResult> observer, Dictionary<object, IJoinObserver> 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
}
}