// Copyright © 2014 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace CefSharp.Internals
{
///
/// TaskExtension based on the following
/// https://github.com/ChadBurggraf/parallel-extensions-extras/blob/master/Extensions/TaskExtrasExtensions.cs
/// https://github.com/ChadBurggraf/parallel-extensions-extras/blob/ec803e58eee28c698e44f55f49c5ad6671b1aa58/Extensions/TaskCompletionSourceExtensions.cs
///
public static class TaskExtensions
{
/// Creates a new Task that mirrors the supplied task but that will be canceled after the specified timeout.
/// Specifies the type of data contained in the task.
/// The task.
/// The timeout.
/// The new Task that may time out.
public static Task WithTimeout(this Task task, TimeSpan timeout)
{
var result = new TaskCompletionSource(task.AsyncState);
var timer = new Timer(state => ((TaskCompletionSource)state).TrySetCanceled(), result, timeout, TimeSpan.FromMilliseconds(-1));
task.ContinueWith(t =>
{
timer.Dispose();
result.TrySetFromTask(t);
}, TaskContinuationOptions.ExecuteSynchronously);
return result.Task;
}
/// Attempts to transfer the result of a Task to the TaskCompletionSource.
/// Specifies the type of the result.
/// The TaskCompletionSource.
/// The task whose completion results should be transfered.
/// Whether the transfer could be completed.
public static bool TrySetFromTask(this TaskCompletionSource resultSetter, Task task)
{
switch (task.Status)
{
case TaskStatus.RanToCompletion:
return resultSetter.TrySetResult(task is Task ? ((Task)task).Result : default(TResult));
case TaskStatus.Faulted:
return resultSetter.TrySetException(task.Exception.InnerExceptions);
case TaskStatus.Canceled:
return resultSetter.TrySetCanceled();
default:
throw new InvalidOperationException("The task was not completed.");
}
}
/// Attempts to transfer the result of a Task to the TaskCompletionSource.
/// Specifies the type of the result.
/// The TaskCompletionSource.
/// The task whose completion results should be transfered.
/// Whether the transfer could be completed.
public static bool TrySetFromTask(this TaskCompletionSource resultSetter, Task task)
{
return TrySetFromTask(resultSetter, (Task)task);
}
public static Task FromResult(T value)
{
var tcs = new TaskCompletionSource();
tcs.SetResult(value);
return tcs.Task;
}
public static TaskCompletionSource WithTimeout(this TaskCompletionSource taskCompletionSource, TimeSpan timeout)
{
return WithTimeout(taskCompletionSource, timeout, null);
}
public static TaskCompletionSource WithTimeout(this TaskCompletionSource taskCompletionSource, TimeSpan timeout, Action cancelled)
{
Timer timer = null;
timer = new Timer(state =>
{
timer.Dispose();
if (taskCompletionSource.Task.Status != TaskStatus.RanToCompletion)
{
taskCompletionSource.TrySetCanceled();
if (cancelled != null)
{
cancelled();
}
}
}, null, timeout, TimeSpan.FromMilliseconds(-1));
return taskCompletionSource;
}
///
/// Set the TaskCompletionSource in an async fashion. This prevents the Task Continuation being executed sync on the same thread
/// This is required otherwise contintinuations will happen on CEF UI threads
///
/// Generic param
/// tcs
/// result
public static void TrySetResultAsync(this TaskCompletionSource taskCompletionSource, TResult result)
{
Task.Factory.StartNew(delegate
{ taskCompletionSource.TrySetResult(result); }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
}
}
}