// 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; } } }