// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Reactive.Disposables; namespace System.Reactive.Concurrency { public static partial class Scheduler { /// /// Schedules an action to be executed recursively. /// /// Scheduler to execute the recursive action on. /// Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, Action action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(action, (_action, self) => _action(() => self(_action))); } /// /// Schedules an action to be executed recursively. /// /// The type of the state passed to the scheduled action. /// Scheduler to execute the recursive action on. /// State passed to the action to be executed. /// Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in recursive invocation state. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, TState state, Action> action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(new Pair>> { First = state, Second = action }, InvokeRec1); } static IDisposable InvokeRec1(IScheduler scheduler, Pair>> pair) { var group = new CompositeDisposable(1); var gate = new object(); var state = pair.First; var action = pair.Second; Action recursiveAction = null; recursiveAction = state1 => action(state1, state2 => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(state2, (scheduler1, state3) => { lock (gate) { if (isAdded) group.Remove(d); else isDone = true; } recursiveAction(state3); return Disposable.Empty; }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); recursiveAction(state); return group; } /// /// Schedules an action to be executed recursively after a specified relative due time. /// /// Scheduler to execute the recursive action on. /// Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action at the specified relative time. /// Relative time after which to execute the action for the first time. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, TimeSpan dueTime, Action> action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(action, dueTime, (_action, self) => _action(dt => self(_action, dt))); } /// /// Schedules an action to be executed recursively after a specified relative due time. /// /// The type of the state passed to the scheduled action. /// Scheduler to execute the recursive action on. /// State passed to the action to be executed. /// Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state. /// Relative time after which to execute the action for the first time. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, TState state, TimeSpan dueTime, Action> action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(new Pair>> { First = state, Second = action }, dueTime, InvokeRec2); } static IDisposable InvokeRec2(IScheduler scheduler, Pair>> pair) { var group = new CompositeDisposable(1); var gate = new object(); var state = pair.First; var action = pair.Second; Action recursiveAction = null; recursiveAction = state1 => action(state1, (state2, dueTime1) => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(state2, dueTime1, (scheduler1, state3) => { lock (gate) { if (isAdded) group.Remove(d); else isDone = true; } recursiveAction(state3); return Disposable.Empty; }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); recursiveAction(state); return group; } /// /// Schedules an action to be executed recursively at a specified absolute due time. /// /// Scheduler to execute the recursive action on. /// Action to execute recursively. The parameter passed to the action is used to trigger recursive scheduling of the action at the specified absolute time. /// Absolute time at which to execute the action for the first time. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, DateTimeOffset dueTime, Action> action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(action, dueTime, (_action, self) => _action(dt => self(_action, dt))); } /// /// Schedules an action to be executed recursively at a specified absolute due time. /// /// The type of the state passed to the scheduled action. /// Scheduler to execute the recursive action on. /// State passed to the action to be executed. /// Action to execute recursively. The last parameter passed to the action is used to trigger recursive scheduling of the action, passing in the recursive due time and invocation state. /// Absolute time at which to execute the action for the first time. /// The disposable object used to cancel the scheduled action (best effort). /// or is null. public static IDisposable Schedule(this IScheduler scheduler, TState state, DateTimeOffset dueTime, Action> action) { if (scheduler == null) throw new ArgumentNullException("scheduler"); if (action == null) throw new ArgumentNullException("action"); return scheduler.Schedule(new Pair>> { First = state, Second = action }, dueTime, InvokeRec3); } static IDisposable InvokeRec3(IScheduler scheduler, Pair>> pair) { var group = new CompositeDisposable(1); var gate = new object(); var state = pair.First; var action = pair.Second; Action recursiveAction = null; recursiveAction = state1 => action(state1, (state2, dueTime1) => { var isAdded = false; var isDone = false; var d = default(IDisposable); d = scheduler.Schedule(state2, dueTime1, (scheduler1, state3) => { lock (gate) { if (isAdded) group.Remove(d); else isDone = true; } recursiveAction(state3); return Disposable.Empty; }); lock (gate) { if (!isDone) { group.Add(d); isAdded = true; } } }); recursiveAction(state); return group; } #if !NO_SERIALIZABLE [Serializable] #endif struct Pair { public T1 First; public T2 Second; } } }