128 lines
4.2 KiB
C#
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
|
|
}
|
|
}
|