// 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.Diagnostics;
namespace System.Reactive.Concurrency
{
///
/// Base class for historical schedulers, which are virtual time schedulers that use for absolute time and for relative time.
///
public abstract class HistoricalSchedulerBase : VirtualTimeSchedulerBase
{
///
/// Creates a new historical scheduler with the minimum value of as the initial clock value.
///
protected HistoricalSchedulerBase()
: base(DateTimeOffset.MinValue, Comparer.Default)
{
}
///
/// Creates a new historical scheduler with the specified initial clock value.
///
/// Initial clock value.
protected HistoricalSchedulerBase(DateTimeOffset initialClock)
: base(initialClock, Comparer.Default)
{
}
///
/// Creates a new historical scheduler with the specified initial clock value and absolute time comparer.
///
/// Initial value for the clock.
/// Comparer to determine causality of events based on absolute time.
protected HistoricalSchedulerBase(DateTimeOffset initialClock, IComparer comparer)
: base(initialClock, comparer)
{
}
///
/// Adds a relative time value to an absolute time value.
///
/// Absolute time value.
/// Relative time value to add.
/// The resulting absolute time sum value.
protected override DateTimeOffset Add(DateTimeOffset absolute, TimeSpan relative)
{
return absolute.Add(relative);
}
///
/// Converts the absolute time value to a value.
///
/// Absolute time value to convert.
/// The corresponding value.
protected override DateTimeOffset ToDateTimeOffset(DateTimeOffset absolute) => absolute;
///
/// Converts the value to a relative time value.
///
/// value to convert.
/// The corresponding relative time value.
protected override TimeSpan ToRelative(TimeSpan timeSpan) => timeSpan;
}
///
/// Provides a virtual time scheduler that uses for absolute time and for relative time.
///
[DebuggerDisplay("\\{ " +
nameof(Clock) + " = {" + nameof(Clock) + "} " +
nameof(Now) + " = {" + nameof(Now) + ".ToString(\"O\")} " +
"\\}")]
public class HistoricalScheduler : HistoricalSchedulerBase
{
private readonly SchedulerQueue _queue = new SchedulerQueue();
///
/// Creates a new historical scheduler with the minimum value of as the initial clock value.
///
public HistoricalScheduler()
{
}
///
/// Creates a new historical scheduler with the specified initial clock value.
///
/// Initial value for the clock.
public HistoricalScheduler(DateTimeOffset initialClock)
: base(initialClock)
{
}
///
/// Creates a new historical scheduler with the specified initial clock value.
///
/// Initial value for the clock.
/// Comparer to determine causality of events based on absolute time.
/// is null.
public HistoricalScheduler(DateTimeOffset initialClock, IComparer comparer)
: base(initialClock, comparer)
{
}
///
/// Gets the next scheduled item to be executed.
///
/// The next scheduled item.
protected override IScheduledItem? GetNext()
{
while (_queue.Count > 0)
{
var next = _queue.Peek();
if (next.IsCanceled)
{
_queue.Dequeue();
}
else
{
return next;
}
}
return null;
}
///
/// Schedules an action to be executed at .
///
/// The type of the state passed to the scheduled action.
/// State passed to the action to be executed.
/// Action to be executed.
/// Absolute time at which to execute the action.
/// The disposable object used to cancel the scheduled action (best effort).
/// is null.
public override IDisposable ScheduleAbsolute(TState state, DateTimeOffset dueTime, Func action)
{
if (action == null)
{
throw new ArgumentNullException(nameof(action));
}
ScheduledItem? si = null;
var run = new Func((scheduler, state1) =>
{
_queue.Remove(si!); // NB: Assigned before function is invoked.
return action(scheduler, state1);
});
si = new ScheduledItem(this, state, run, dueTime, Comparer);
_queue.Enqueue(si);
return si;
}
}
}