// 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.Runtime.CompilerServices; namespace System.Reactive.Concurrency { internal abstract class SchedulerWrapper : IScheduler, IServiceProvider { protected readonly IScheduler _scheduler; private readonly ConditionalWeakTable _cache; protected SchedulerWrapper(IScheduler scheduler) { _scheduler = scheduler; _cache = new ConditionalWeakTable(); } protected SchedulerWrapper(IScheduler scheduler, ConditionalWeakTable cache) { _scheduler = scheduler; _cache = cache; } public DateTimeOffset Now => _scheduler.Now; public IDisposable Schedule(TState state, Func action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } return _scheduler.Schedule(state, Wrap(action)); } public IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } return _scheduler.Schedule(state, dueTime, Wrap(action)); } public IDisposable Schedule(TState state, DateTimeOffset dueTime, Func action) { if (action == null) { throw new ArgumentNullException(nameof(action)); } return _scheduler.Schedule(state, dueTime, Wrap(action)); } protected virtual Func Wrap(Func action) { return (self, state) => action(GetRecursiveWrapper(self), state); } protected IScheduler GetRecursiveWrapper(IScheduler scheduler) { return _cache.GetValue(scheduler, s => Clone(s, _cache)); } protected abstract SchedulerWrapper Clone(IScheduler scheduler, ConditionalWeakTable cache); public object? GetService(Type serviceType) { if (_scheduler is not IServiceProvider serviceProvider) { return null; } if (TryGetService(serviceProvider, serviceType, out var result)) { return result; } return serviceProvider.GetService(serviceType); } protected abstract bool TryGetService(IServiceProvider provider, Type serviceType, out object? service); } }