// 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 { 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 observer) => new(_start, _count, observer); protected override void Run(RangeSink sink) => sink.Run(_scheduler); internal sealed class RangeSink : IdentitySink { private readonly int _end; private int _index; private MultipleAssignmentDisposableValue _task; public RangeSink(int start, int count, IObserver 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 { 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 observer) => new(_start, _count, observer); protected override void Run(RangeSink sink) => sink.Run(_scheduler); internal sealed class RangeSink : IdentitySink { private readonly int _end; private readonly int _index; public RangeSink(int start, int count, IObserver 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(); } } } } }