Kit.Core/LibExternal/System.Reactive/Linq/Observable/SelectMany.cs

1736 lines
61 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.Concurrency;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
namespace System.Reactive.Linq.ObservableImpl
{
internal static class SelectMany<TSource, TCollection, TResult>
{
internal sealed class ObservableSelector : Producer<TResult, ObservableSelector._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, IObservable<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public ObservableSelector(IObservable<TSource> source, Func<TSource, IObservable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CompositeDisposable _group = new();
private readonly Func<TSource, IObservable<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public _(ObservableSelector parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
private volatile bool _isStopped;
public override void OnNext(TSource value)
{
IObservable<TCollection> collection;
try
{
collection = _collectionSelector(value);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
var innerObserver = new InnerObserver(this, value);
_group.Add(innerObserver);
innerObserver.SetResource(collection.SubscribeSafe(innerObserver));
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
_isStopped = true;
if (_group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_gate)
{
ForwardOnCompleted();
}
}
else
{
DisposeUpstream();
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_group.Dispose();
}
}
private sealed class InnerObserver : SafeObserver<TCollection>
{
private readonly _ _parent;
private readonly TSource _value;
public InnerObserver(_ parent, TSource value)
{
_parent = parent;
_value = value;
}
public override void OnNext(TCollection value)
{
TResult res;
try
{
res = _parent._resultSelector(_value, value);
}
catch (Exception ex)
{
lock (_parent._gate)
{
_parent.ForwardOnError(ex);
}
return;
}
lock (_parent._gate)
{
_parent.ForwardOnNext(res);
}
}
public override void OnError(Exception error)
{
lock (_parent._gate)
{
_parent.ForwardOnError(error);
}
}
public override void OnCompleted()
{
_parent._group.Remove(this);
if (_parent._isStopped && _parent._group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_parent._gate)
{
_parent.ForwardOnCompleted();
}
}
}
}
}
}
internal sealed class ObservableSelectorIndexed : Producer<TResult, ObservableSelectorIndexed._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, int, IObservable<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, int, TResult> _resultSelector;
public ObservableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IObservable<TCollection>> collectionSelector, Func<TSource, int, TCollection, int, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CompositeDisposable _group = new();
private readonly Func<TSource, int, IObservable<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, int, TResult> _resultSelector;
public _(ObservableSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
private volatile bool _isStopped;
private int _index;
public override void OnNext(TSource value)
{
int index;
IObservable<TCollection> collection;
try
{
index = checked(_index++);
collection = _collectionSelector(value, index);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
var innerObserver = new InnerObserver(this, value, index);
_group.Add(innerObserver);
innerObserver.SetResource(collection.SubscribeSafe(innerObserver));
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
_isStopped = true;
if (_group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_gate)
{
ForwardOnCompleted();
}
}
else
{
DisposeUpstream();
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_group.Dispose();
}
}
private sealed class InnerObserver : SafeObserver<TCollection>
{
private readonly _ _parent;
private readonly TSource _value;
private readonly int _valueIndex;
public InnerObserver(_ parent, TSource value, int index)
{
_parent = parent;
_value = value;
_valueIndex = index;
}
private int _index;
public override void OnNext(TCollection value)
{
TResult res;
try
{
res = _parent._resultSelector(_value, _valueIndex, value, checked(_index++));
}
catch (Exception ex)
{
lock (_parent._gate)
{
_parent.ForwardOnError(ex);
}
return;
}
lock (_parent._gate)
{
_parent.ForwardOnNext(res);
}
}
public override void OnError(Exception error)
{
lock (_parent._gate)
{
_parent.ForwardOnError(error);
}
}
public override void OnCompleted()
{
_parent._group.Remove(this);
if (_parent._isStopped && _parent._group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_parent._gate)
{
_parent.ForwardOnCompleted();
}
}
}
}
}
}
internal sealed class EnumerableSelector : Producer<TResult, EnumerableSelector._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, IEnumerable<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public EnumerableSelector(IObservable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly Func<TSource, IEnumerable<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public _(EnumerableSelector parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
public override void OnNext(TSource value)
{
IEnumerable<TCollection> xs;
try
{
xs = _collectionSelector(value);
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
IEnumerator<TCollection> e;
try
{
e = xs.GetEnumerator();
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
using (e)
{
var hasNext = true;
while (hasNext)
{
var current = default(TResult);
try
{
hasNext = e.MoveNext();
if (hasNext)
{
current = _resultSelector(value, e.Current);
}
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
if (hasNext)
{
ForwardOnNext(current!);
}
}
}
}
}
}
internal sealed class EnumerableSelectorIndexed : Producer<TResult, EnumerableSelectorIndexed._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, int, IEnumerable<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, int, TResult> _resultSelector;
public EnumerableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IEnumerable<TCollection>> collectionSelector, Func<TSource, int, TCollection, int, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly Func<TSource, int, IEnumerable<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, int, TResult> _resultSelector;
public _(EnumerableSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
private int _index;
public override void OnNext(TSource value)
{
int index;
IEnumerable<TCollection> xs;
try
{
index = checked(_index++);
xs = _collectionSelector(value, index);
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
IEnumerator<TCollection> e;
try
{
e = xs.GetEnumerator();
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
using (e)
{
var eIndex = 0;
var hasNext = true;
while (hasNext)
{
var current = default(TResult);
try
{
hasNext = e.MoveNext();
if (hasNext)
{
current = _resultSelector(value, index, e.Current, checked(eIndex++));
}
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
if (hasNext)
{
ForwardOnNext(current!);
}
}
}
}
}
}
internal sealed class TaskSelector : Producer<TResult, TaskSelector._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, CancellationToken, Task<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public TaskSelector(IObservable<TSource> source, Func<TSource, CancellationToken, Task<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CancellationTokenSource _cancel = new();
private readonly Func<TSource, CancellationToken, Task<TCollection>> _collectionSelector;
private readonly Func<TSource, TCollection, TResult> _resultSelector;
public _(TaskSelector parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
private volatile int _count;
public override void Run(IObservable<TSource> source)
{
_count = 1;
base.Run(source);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_cancel.Cancel();
}
base.Dispose(disposing);
}
public override void OnNext(TSource value)
{
Task<TCollection> task;
try
{
Interlocked.Increment(ref _count);
task = _collectionSelector(value, _cancel.Token);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
if (task.IsCompleted)
{
OnCompletedTask(value, task);
}
else
{
task.ContinueWithState(static (t, tuple) => tuple.@this.OnCompletedTask(tuple.value, t), (@this: this, value), _cancel.Token);
}
}
private void OnCompletedTask(TSource value, Task<TCollection> task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
{
TResult res;
try
{
res = _resultSelector(value, task.Result);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
lock (_gate)
{
ForwardOnNext(res);
}
OnCompleted();
break;
}
case TaskStatus.Faulted:
{
lock (_gate)
{
ForwardOnError(TaskHelpers.GetSingleException(task));
}
break;
}
case TaskStatus.Canceled:
{
if (!_cancel.IsCancellationRequested)
{
lock (_gate)
{
ForwardOnError(new TaskCanceledException(task));
}
}
break;
}
}
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
if (Interlocked.Decrement(ref _count) == 0)
{
lock (_gate)
{
ForwardOnCompleted();
}
}
}
}
}
internal sealed class TaskSelectorIndexed : Producer<TResult, TaskSelectorIndexed._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, int, CancellationToken, Task<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, TResult> _resultSelector;
public TaskSelectorIndexed(IObservable<TSource> source, Func<TSource, int, CancellationToken, Task<TCollection>> collectionSelector, Func<TSource, int, TCollection, TResult> resultSelector)
{
_source = source;
_collectionSelector = collectionSelector;
_resultSelector = resultSelector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CancellationTokenSource _cancel = new();
private readonly Func<TSource, int, CancellationToken, Task<TCollection>> _collectionSelector;
private readonly Func<TSource, int, TCollection, TResult> _resultSelector;
public _(TaskSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_collectionSelector = parent._collectionSelector;
_resultSelector = parent._resultSelector;
}
private volatile int _count;
private int _index;
public override void Run(IObservable<TSource> source)
{
_count = 1;
base.Run(source);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_cancel.Cancel();
}
base.Dispose(disposing);
}
public override void OnNext(TSource value)
{
int index;
Task<TCollection> task;
try
{
index = checked(_index++);
Interlocked.Increment(ref _count);
task = _collectionSelector(value, index, _cancel.Token);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
if (task.IsCompleted)
{
OnCompletedTask(value, index, task);
}
else
{
task.ContinueWithState(static (t, tuple) => tuple.@this.OnCompletedTask(tuple.value, tuple.index, t), (@this: this, value, index), _cancel.Token);
}
}
private void OnCompletedTask(TSource value, int index, Task<TCollection> task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
{
TResult res;
try
{
res = _resultSelector(value, index, task.Result);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
lock (_gate)
{
ForwardOnNext(res);
}
OnCompleted();
break;
}
case TaskStatus.Faulted:
{
lock (_gate)
{
ForwardOnError(TaskHelpers.GetSingleException(task));
}
break;
}
case TaskStatus.Canceled:
{
if (!_cancel.IsCancellationRequested)
{
lock (_gate)
{
ForwardOnError(new TaskCanceledException(task));
}
}
break;
}
}
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
if (Interlocked.Decrement(ref _count) == 0)
{
lock (_gate)
{
ForwardOnCompleted();
}
}
}
}
}
}
internal static class SelectMany<TSource, TResult>
{
internal class ObservableSelector : Producer<TResult, ObservableSelector._>
{
protected readonly IObservable<TSource> _source;
protected readonly Func<TSource, IObservable<TResult>> _selector;
public ObservableSelector(IObservable<TSource> source, Func<TSource, IObservable<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal class _ : Sink<TSource, TResult>
{
protected readonly object _gate = new();
private readonly Func<TSource, IObservable<TResult>> _selector;
private readonly CompositeDisposable _group = new();
private volatile bool _isStopped;
public _(ObservableSelector parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
public override void OnNext(TSource value)
{
IObservable<TResult> inner;
try
{
inner = _selector(value);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
Final();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_group.Dispose();
}
}
protected void Final()
{
_isStopped = true;
if (_group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 0, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_gate)
{
ForwardOnCompleted();
}
}
else
{
DisposeUpstream();
}
}
protected void SubscribeInner(IObservable<TResult> inner)
{
var innerObserver = new InnerObserver(this);
_group.Add(innerObserver);
innerObserver.SetResource(inner.SubscribeSafe(innerObserver));
}
private sealed class InnerObserver : SafeObserver<TResult>
{
private readonly _ _parent;
public InnerObserver(_ parent)
{
_parent = parent;
}
public override void OnNext(TResult value)
{
lock (_parent._gate)
{
_parent.ForwardOnNext(value);
}
}
public override void OnError(Exception error)
{
lock (_parent._gate)
{
_parent.ForwardOnError(error);
}
}
public override void OnCompleted()
{
_parent._group.Remove(this);
if (_parent._isStopped && _parent._group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_parent._gate)
{
_parent.ForwardOnCompleted();
}
}
}
}
}
}
internal sealed class ObservableSelectors : ObservableSelector
{
private readonly Func<Exception, IObservable<TResult>> _selectorOnError;
private readonly Func<IObservable<TResult>> _selectorOnCompleted;
public ObservableSelectors(IObservable<TSource> source, Func<TSource, IObservable<TResult>> selector, Func<Exception, IObservable<TResult>> selectorOnError, Func<IObservable<TResult>> selectorOnCompleted)
: base(source, selector)
{
_selectorOnError = selectorOnError;
_selectorOnCompleted = selectorOnCompleted;
}
protected override ObservableSelector._ CreateSink(IObserver<TResult> observer) => new _(this, observer);
internal new sealed class _ : ObservableSelector._
{
private readonly Func<Exception, IObservable<TResult>> _selectorOnError;
private readonly Func<IObservable<TResult>> _selectorOnCompleted;
public _(ObservableSelectors parent, IObserver<TResult> observer)
: base(parent, observer)
{
_selectorOnError = parent._selectorOnError;
_selectorOnCompleted = parent._selectorOnCompleted;
}
public override void OnError(Exception error)
{
if (_selectorOnError != null)
{
IObservable<TResult> inner;
try
{
inner = _selectorOnError(error);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
Final();
}
else
{
base.OnError(error);
}
}
public override void OnCompleted()
{
if (_selectorOnCompleted != null)
{
IObservable<TResult> inner;
try
{
inner = _selectorOnCompleted();
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
}
Final();
}
}
}
internal class ObservableSelectorIndexed : Producer<TResult, ObservableSelectorIndexed._>
{
protected readonly IObservable<TSource> _source;
protected readonly Func<TSource, int, IObservable<TResult>> _selector;
public ObservableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IObservable<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CompositeDisposable _group = new();
protected readonly Func<TSource, int, IObservable<TResult>> _selector;
private int _index;
private volatile bool _isStopped;
public _(ObservableSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
public override void OnNext(TSource value)
{
IObservable<TResult> inner;
try
{
inner = _selector(value, checked(_index++));
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
Final();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_group.Dispose();
}
}
protected void Final()
{
_isStopped = true;
if (_group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_gate)
{
ForwardOnCompleted();
}
}
else
{
DisposeUpstream();
}
}
protected void SubscribeInner(IObservable<TResult> inner)
{
var innerObserver = new InnerObserver(this);
_group.Add(innerObserver);
innerObserver.SetResource(inner.SubscribeSafe(innerObserver));
}
private sealed class InnerObserver : SafeObserver<TResult>
{
private readonly _ _parent;
public InnerObserver(_ parent)
{
_parent = parent;
}
public override void OnNext(TResult value)
{
lock (_parent._gate)
{
_parent.ForwardOnNext(value);
}
}
public override void OnError(Exception error)
{
lock (_parent._gate)
{
_parent.ForwardOnError(error);
}
}
public override void OnCompleted()
{
_parent._group.Remove(this);
if (_parent._isStopped && _parent._group.Count == 0)
{
//
// Notice there can be a race between OnCompleted of the source and any
// of the inner sequences, where both see _group.Count == 1, and one is
// waiting for the lock. There won't be a double OnCompleted observation
// though, because the call to Dispose silences the observer by swapping
// in a NopObserver<T>.
//
lock (_parent._gate)
{
_parent.ForwardOnCompleted();
}
}
}
}
}
}
internal sealed class ObservableSelectorsIndexed : ObservableSelectorIndexed
{
private readonly Func<Exception, IObservable<TResult>> _selectorOnError;
private readonly Func<IObservable<TResult>> _selectorOnCompleted;
public ObservableSelectorsIndexed(IObservable<TSource> source, Func<TSource, int, IObservable<TResult>> selector, Func<Exception, IObservable<TResult>> selectorOnError, Func<IObservable<TResult>> selectorOnCompleted)
: base(source, selector)
{
_selectorOnError = selectorOnError;
_selectorOnCompleted = selectorOnCompleted;
}
protected override ObservableSelectorIndexed._ CreateSink(IObserver<TResult> observer) => new _(this, observer);
internal new sealed class _ : ObservableSelectorIndexed._
{
private readonly object _gate = new();
private readonly Func<Exception, IObservable<TResult>> _selectorOnError;
private readonly Func<IObservable<TResult>> _selectorOnCompleted;
public _(ObservableSelectorsIndexed parent, IObserver<TResult> observer)
: base(parent, observer)
{
_selectorOnError = parent._selectorOnError;
_selectorOnCompleted = parent._selectorOnCompleted;
}
public override void OnError(Exception error)
{
if (_selectorOnError != null)
{
IObservable<TResult> inner;
try
{
inner = _selectorOnError(error);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
Final();
}
else
{
base.OnError(error);
}
}
public override void OnCompleted()
{
if (_selectorOnCompleted != null)
{
IObservable<TResult> inner;
try
{
inner = _selectorOnCompleted();
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
SubscribeInner(inner);
}
Final();
}
}
}
internal sealed class EnumerableSelector : Producer<TResult, EnumerableSelector._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, IEnumerable<TResult>> _selector;
public EnumerableSelector(IObservable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly Func<TSource, IEnumerable<TResult>> _selector;
public _(EnumerableSelector parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
public override void OnNext(TSource value)
{
IEnumerable<TResult> xs;
try
{
xs = _selector(value);
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
IEnumerator<TResult> e;
try
{
e = xs.GetEnumerator();
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
using (e)
{
var hasNext = true;
while (hasNext)
{
var current = default(TResult);
try
{
hasNext = e.MoveNext();
if (hasNext)
{
current = e.Current;
}
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
if (hasNext)
{
ForwardOnNext(current!);
}
}
}
}
}
}
internal sealed class EnumerableSelectorIndexed : Producer<TResult, EnumerableSelectorIndexed._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, int, IEnumerable<TResult>> _selector;
public EnumerableSelectorIndexed(IObservable<TSource> source, Func<TSource, int, IEnumerable<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly Func<TSource, int, IEnumerable<TResult>> _selector;
public _(EnumerableSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
private int _index;
public override void OnNext(TSource value)
{
IEnumerable<TResult> xs;
try
{
xs = _selector(value, checked(_index++));
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
IEnumerator<TResult> e;
try
{
e = xs.GetEnumerator();
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
using (e)
{
var hasNext = true;
while (hasNext)
{
var current = default(TResult);
try
{
hasNext = e.MoveNext();
if (hasNext)
{
current = e.Current;
}
}
catch (Exception exception)
{
ForwardOnError(exception);
return;
}
if (hasNext)
{
ForwardOnNext(current!);
}
}
}
}
}
}
internal sealed class TaskSelector : Producer<TResult, TaskSelector._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, CancellationToken, Task<TResult>> _selector;
public TaskSelector(IObservable<TSource> source, Func<TSource, CancellationToken, Task<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CancellationTokenSource _cts = new();
private readonly Func<TSource, CancellationToken, Task<TResult>> _selector;
public _(TaskSelector parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
private volatile int _count;
public override void Run(IObservable<TSource> source)
{
_count = 1;
base.Run(source);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_cts.Cancel();
}
base.Dispose(disposing);
}
public override void OnNext(TSource value)
{
Task<TResult> task;
try
{
Interlocked.Increment(ref _count);
task = _selector(value, _cts.Token);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
if (task.IsCompleted)
{
OnCompletedTask(task);
}
else
{
task.ContinueWith((closureTask, thisObject) => ((_)thisObject!).OnCompletedTask(closureTask), this, _cts.Token);
}
}
private void OnCompletedTask(Task<TResult> task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
{
lock (_gate)
{
ForwardOnNext(task.Result);
}
OnCompleted();
break;
}
case TaskStatus.Faulted:
{
lock (_gate)
{
ForwardOnError(TaskHelpers.GetSingleException(task));
}
break;
}
case TaskStatus.Canceled:
{
if (!_cts.IsCancellationRequested)
{
lock (_gate)
{
ForwardOnError(new TaskCanceledException(task));
}
}
break;
}
}
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
if (Interlocked.Decrement(ref _count) == 0)
{
lock (_gate)
{
ForwardOnCompleted();
}
}
}
}
}
internal sealed class TaskSelectorIndexed : Producer<TResult, TaskSelectorIndexed._>
{
private readonly IObservable<TSource> _source;
private readonly Func<TSource, int, CancellationToken, Task<TResult>> _selector;
public TaskSelectorIndexed(IObservable<TSource> source, Func<TSource, int, CancellationToken, Task<TResult>> selector)
{
_source = source;
_selector = selector;
}
protected override _ CreateSink(IObserver<TResult> observer) => new(this, observer);
protected override void Run(_ sink) => sink.Run(_source);
internal sealed class _ : Sink<TSource, TResult>
{
private readonly object _gate = new();
private readonly CancellationTokenSource _cts = new();
private readonly Func<TSource, int, CancellationToken, Task<TResult>> _selector;
public _(TaskSelectorIndexed parent, IObserver<TResult> observer)
: base(observer)
{
_selector = parent._selector;
}
private volatile int _count;
private int _index;
public override void Run(IObservable<TSource> source)
{
_count = 1;
base.Run(source);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_cts.Cancel();
}
base.Dispose(disposing);
}
public override void OnNext(TSource value)
{
Task<TResult> task;
try
{
Interlocked.Increment(ref _count);
task = _selector(value, checked(_index++), _cts.Token);
}
catch (Exception ex)
{
lock (_gate)
{
ForwardOnError(ex);
}
return;
}
if (task.IsCompleted)
{
OnCompletedTask(task);
}
else
{
task.ContinueWith((closureTask, thisObject) => ((_)thisObject!).OnCompletedTask(closureTask), this, _cts.Token);
}
}
private void OnCompletedTask(Task<TResult> task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
{
lock (_gate)
{
ForwardOnNext(task.Result);
}
OnCompleted();
break;
}
case TaskStatus.Faulted:
{
lock (_gate)
{
ForwardOnError(TaskHelpers.GetSingleException(task));
}
break;
}
case TaskStatus.Canceled:
{
if (!_cts.IsCancellationRequested)
{
lock (_gate)
{
ForwardOnError(new TaskCanceledException(task));
}
}
break;
}
}
}
public override void OnError(Exception error)
{
lock (_gate)
{
ForwardOnError(error);
}
}
public override void OnCompleted()
{
if (Interlocked.Decrement(ref _count) == 0)
{
lock (_gate)
{
ForwardOnCompleted();
}
}
}
}
}
}
}