rd-net/RdFramework/Tasks/RdTaskEx.cs (113 lines of code) (raw):
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
using JetBrains.Collections.Viewable;
using JetBrains.Core;
using JetBrains.Lifetimes;
using JetBrains.Threading;
namespace JetBrains.Rd.Tasks
{
public static class RdTaskEx
{
[PublicAPI] public static bool IsSucceed<T>(this IRdTask<T> task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Success;
[PublicAPI] public static bool IsCanceled<T>(this IRdTask<T> task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Canceled;
[PublicAPI] public static bool IsFaulted<T>(this IRdTask<T> task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Faulted;
public static bool Wait<T>(this IRdTask<T> task, TimeSpan timeout) => SpinWaitEx.SpinUntil(Lifetime.Eternal, timeout, () => task.Result.HasValue());
public static RdTask<T> ToRdTask<T>(this Task<T> task)
{
var res = new RdTask<T>();
task.ContinueWith(t =>
{
if (t.IsOperationCanceled())
res.SetCancelled();
else if (t.IsFaulted)
res.Set(t.Exception?.Flatten().GetBaseException() ?? new Exception("Unknown exception"));
else
res.Set(t.Result);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Current);
return res;
}
public static RdTask<Unit> ToRdTask(this Task task)
{
var res = new RdTask<Unit>();
task.ContinueWith(t =>
{
if (t.IsOperationCanceled())
res.SetCancelled();
else if (t.IsFaulted)
res.Set(t.Exception?.Flatten().GetBaseException() ?? new Exception("Unknown exception"));
else
res.Set(Unit.Instance);
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Current);
return res;
}
[PublicAPI] public static void Set<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<Lifetime, TReq, Task<TRes>> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.SetRdTask((lt, req) => handler(lt, req).ToRdTask(), cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void SetAsync<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<Lifetime, TReq, Task<TRes>> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.Set(handler, cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void SetVoidAsync<TReq>(this IRdEndpoint<TReq, Unit> endpoint, Func<Lifetime, TReq, Task> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.SetAsync(async (lt, x) =>
{
await handler(lt, x);
return Unit.Instance;
}, cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void Set<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<Lifetime, TReq, TRes> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.SetRdTask((lifetime, req) => RdTask.Successful(handler(lifetime, req)), cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void SetSync<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<Lifetime, TReq, TRes> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.Set(handler, cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void Set<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<TReq, TRes> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.SetRdTask((_, req) => RdTask.Successful(handler(req)), cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void SetSync<TReq, TRes>(this IRdEndpoint<TReq, TRes> endpoint, Func<TReq, TRes> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.Set(handler, cancellationScheduler, handlerScheduler);
}
[PublicAPI] public static void SetVoid<TReq>(this IRdEndpoint<TReq, Unit> endpoint, Action<TReq> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null)
{
endpoint.Set(req =>
{
handler(req);
return Unit.Instance;
}, cancellationScheduler, handlerScheduler);
}
[PublicAPI]
public static Task<T> AsTask<T>(this IRdTask<T> task)
{
if (task == null) throw new ArgumentNullException(nameof(task));
var tcs = new TaskCompletionSource<T>();
task.Result.AdviseOnce(Lifetime.Eternal, result =>
{
switch (result.Status)
{
case RdTaskStatus.Success:
tcs.SetResult(result.Result);
break;
case RdTaskStatus.Canceled:
tcs.SetCanceled();
break;
case RdTaskStatus.Faulted:
tcs.SetException(result.Error);
break;
default:
throw new ArgumentOutOfRangeException(result.Status.ToString());
}
});
return tcs.Task;
}
[PublicAPI]
public static TaskAwaiter<T> GetAwaiter<T>(this IRdTask<T> task) => task.AsTask().GetAwaiter();
}
}