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(this IRdTask task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Success; [PublicAPI] public static bool IsCanceled(this IRdTask task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Canceled; [PublicAPI] public static bool IsFaulted(this IRdTask task) => task.Result.HasValue() && task.Result.Value.Status == RdTaskStatus.Faulted; public static bool Wait(this IRdTask task, TimeSpan timeout) => SpinWaitEx.SpinUntil(Lifetime.Eternal, timeout, () => task.Result.HasValue()); public static RdTask ToRdTask(this Task task) { var res = new RdTask(); 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 ToRdTask(this Task task) { var res = new RdTask(); 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(this IRdEndpoint endpoint, Func> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.SetRdTask((lt, req) => handler(lt, req).ToRdTask(), cancellationScheduler, handlerScheduler); } [PublicAPI] public static void SetAsync(this IRdEndpoint endpoint, Func> handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.Set(handler, cancellationScheduler, handlerScheduler); } [PublicAPI] public static void SetVoidAsync(this IRdEndpoint endpoint, Func 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(this IRdEndpoint endpoint, Func handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.SetRdTask((lifetime, req) => RdTask.Successful(handler(lifetime, req)), cancellationScheduler, handlerScheduler); } [PublicAPI] public static void SetSync(this IRdEndpoint endpoint, Func handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.Set(handler, cancellationScheduler, handlerScheduler); } [PublicAPI] public static void Set(this IRdEndpoint endpoint, Func handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.SetRdTask((_, req) => RdTask.Successful(handler(req)), cancellationScheduler, handlerScheduler); } [PublicAPI] public static void SetSync(this IRdEndpoint endpoint, Func handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.Set(handler, cancellationScheduler, handlerScheduler); } [PublicAPI] public static void SetVoid(this IRdEndpoint endpoint, Action handler, IScheduler? cancellationScheduler = null, IScheduler? handlerScheduler = null) { endpoint.Set(req => { handler(req); return Unit.Instance; }, cancellationScheduler, handlerScheduler); } [PublicAPI] public static Task AsTask(this IRdTask task) { if (task == null) throw new ArgumentNullException(nameof(task)); var tcs = new TaskCompletionSource(); 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 GetAwaiter(this IRdTask task) => task.AsTask().GetAwaiter(); } }