/// <summary>
        /// Run a sync action synchoronously with a timeout and some additional ooptions.
        /// </summary>
        /// <param name="syncAction">The sync action to execute.</param>
        /// <param name="timeout">The timeout to apply.</param>
        /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param>
        /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out action.</param>
        /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
        public static void RunSyncActionWithTimeout(Action <CancellationToken> syncAction, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task>?timedOutTaskProcessor = null, CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();

            if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan)
            {
                var exc = new SyntheticTimeoutException();
                if (cancelIfTimeout == false)
                {
                    timedOutTaskProcessor?.Invoke(Task.FromException(exc));
                }
                throw exc;
            }

            Task task;

            if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None)
            {
                //task = _taskFactory.StartNew(() => syncAction(token), token);
                syncAction(token);
                return;
            }
            else
            {
                task = RunAsyncActionWithTimeoutAsync(ct => _taskFactory.StartNew(() => syncAction(ct), ct), timeout, cancelIfTimeout, timedOutTaskProcessor, token);
            }

            task.GetAwaiter().GetResult();
        }
        /// <summary>
        /// Run an async function synchoronously with a timeout and some additional ooptions.
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="asyncFunc">The async function to execute.</param>
        /// <param name="timeout">The timeout to apply.</param>
        /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param>
        /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out function.</param>
        /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
        /// <returns>The value returned from the async function</returns>
        public static TResult RunAsyncFuncWithTimeout <TResult>(Func <CancellationToken, Task <TResult> > asyncFunc, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task <TResult> >?timedOutTaskProcessor = null, CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();

            if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan)
            {
                var exc = new SyntheticTimeoutException();
                if (cancelIfTimeout == false)
                {
                    timedOutTaskProcessor?.Invoke(Task.FromException <TResult>(exc));
                }
                throw exc;
            }

            Task <TResult> task;

            if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None)
            {
                task = _taskFactory.StartNew(() => asyncFunc(token), token).Unwrap();
            }
            else
            {
                task = _taskFactory.StartNew(() => RunAsyncFuncWithTimeoutAsync(asyncFunc, timeout, cancelIfTimeout, timedOutTaskProcessor, token), token).Unwrap();
            }

            return(task.GetAwaiter().GetResult());
        }
        /// <summary>
        /// Run an async function asynchronously with a timeout and some additional ooptions.
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="asyncFunc">The async function to execute.</param>
        /// <param name="timeout">The timeout to apply.</param>
        /// <param name="cancelIfTimeout">Indicates if the action should be cancelled in case of a timeout.</param>
        /// <param name="timedOutTaskProcessor">A lambda to process the task representing the eventually timed out function.</param>
        /// <param name="token">An optional <see cref="CancellationToken"/> to cancel the operation.</param>
        /// <returns>The resulting <see cref="Task"/> to await</returns>
        public static async Task <TResult> RunAsyncFuncWithTimeoutAsync <TResult>(Func <CancellationToken, Task <TResult> > asyncFunc, TimeSpan timeout, bool cancelIfTimeout = true, Action <Task <TResult> >?timedOutTaskProcessor = null, CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();

            if (timeout == TimeSpan.Zero || timeout < Timeout.InfiniteTimeSpan)
            {
                var exc = new SyntheticTimeoutException();
                if (cancelIfTimeout == false)
                {
                    timedOutTaskProcessor?.Invoke(Task.FromException <TResult>(exc));
                }
                throw exc;
            }

            if (timeout == Timeout.InfiniteTimeSpan && token == CancellationToken.None)
            {
                return(await asyncFunc(token).ConfigureAwait(false));
            }

            var ctsFunc = cancelIfTimeout
                                ? CancellationTokenSource.CreateLinkedTokenSource(token)
                                : null;

            try
            {
                using (var ctsDelay = CancellationTokenSource.CreateLinkedTokenSource(token))
                {
                    var funcTask = asyncFunc(ctsFunc?.Token ?? token);
                    using (var delayTask = Task.Delay(timeout, ctsDelay.Token))
                    {
                        await Task.WhenAny(funcTask, delayTask).ConfigureAwait(false);

                        if (delayTask.IsCompleted == false && delayTask.IsFaulted == false)
                        {
                            ctsDelay.Cancel();
                        }
                    }

                    if (funcTask.IsCompleted == false && funcTask.IsFaulted == false)
                    {
                        ctsFunc?.Cancel();
                    }

                    token.ThrowIfCancellationRequested();

                    if (funcTask.IsCompleted)
                    {
                        return(await funcTask.ConfigureAwait(false));
                    }

                    if (cancelIfTimeout == false)
                    {
                        timedOutTaskProcessor?.Invoke(funcTask);
                    }

                    throw new SyntheticTimeoutException();
                }
            }
            finally
            {
                ctsFunc?.Dispose();
            }
        }