128 lines
3.9 KiB
C#
128 lines
3.9 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.Reactive.Concurrency;
|
|
using System.Reactive.Disposables;
|
|
|
|
namespace System.Reactive.Linq.ObservableImpl
|
|
{
|
|
internal sealed class RangeRecursive : Producer<int, RangeRecursive.RangeSink>
|
|
{
|
|
private readonly int _start;
|
|
private readonly int _count;
|
|
private readonly IScheduler _scheduler;
|
|
|
|
public RangeRecursive(int start, int count, IScheduler scheduler)
|
|
{
|
|
_start = start;
|
|
_count = count;
|
|
_scheduler = scheduler;
|
|
}
|
|
|
|
protected override RangeSink CreateSink(IObserver<int> observer) => new(_start, _count, observer);
|
|
|
|
protected override void Run(RangeSink sink) => sink.Run(_scheduler);
|
|
|
|
internal sealed class RangeSink : IdentitySink<int>
|
|
{
|
|
private readonly int _end;
|
|
private int _index;
|
|
private MultipleAssignmentDisposableValue _task;
|
|
|
|
public RangeSink(int start, int count, IObserver<int> observer)
|
|
: base(observer)
|
|
{
|
|
_index = start;
|
|
_end = start + count;
|
|
}
|
|
|
|
public void Run(IScheduler scheduler)
|
|
{
|
|
var first = scheduler.Schedule(this, static (innerScheduler, @this) => @this.LoopRec(innerScheduler));
|
|
_task.TrySetFirst(first);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
base.Dispose(disposing);
|
|
if (disposing)
|
|
{
|
|
_task.Dispose();
|
|
}
|
|
}
|
|
|
|
private IDisposable LoopRec(IScheduler scheduler)
|
|
{
|
|
var idx = _index;
|
|
|
|
if (idx != _end)
|
|
{
|
|
_index = idx + 1;
|
|
ForwardOnNext(idx);
|
|
var next = scheduler.Schedule(this, static (innerScheduler, @this) => @this.LoopRec(innerScheduler));
|
|
_task.Disposable = next;
|
|
}
|
|
else
|
|
{
|
|
ForwardOnCompleted();
|
|
}
|
|
|
|
return Disposable.Empty;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class RangeLongRunning : Producer<int, RangeLongRunning.RangeSink>
|
|
{
|
|
private readonly int _start;
|
|
private readonly int _count;
|
|
private readonly ISchedulerLongRunning _scheduler;
|
|
|
|
public RangeLongRunning(int start, int count, ISchedulerLongRunning scheduler)
|
|
{
|
|
_start = start;
|
|
_count = count;
|
|
_scheduler = scheduler;
|
|
}
|
|
|
|
protected override RangeSink CreateSink(IObserver<int> observer) => new(_start, _count, observer);
|
|
|
|
protected override void Run(RangeSink sink) => sink.Run(_scheduler);
|
|
|
|
internal sealed class RangeSink : IdentitySink<int>
|
|
{
|
|
private readonly int _end;
|
|
private readonly int _index;
|
|
|
|
public RangeSink(int start, int count, IObserver<int> observer)
|
|
: base(observer)
|
|
{
|
|
_index = start;
|
|
_end = start + count;
|
|
}
|
|
|
|
public void Run(ISchedulerLongRunning scheduler)
|
|
{
|
|
SetUpstream(scheduler.ScheduleLongRunning(this, static (@this, cancel) => @this.Loop(cancel)));
|
|
}
|
|
|
|
private void Loop(ICancelable cancel)
|
|
{
|
|
var idx = _index;
|
|
var end = _end;
|
|
|
|
while (!cancel.IsDisposed && idx != end)
|
|
{
|
|
ForwardOnNext(idx++);
|
|
}
|
|
|
|
if (!cancel.IsDisposed)
|
|
{
|
|
ForwardOnCompleted();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|