using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Wabbajack.Common.CSP { public abstract class AChannel : IChannel { public abstract bool IsClosed { get; } public abstract void Close(); public abstract (AsyncResult, bool) Put(TIn val, Handler> handler); public abstract (AsyncResult, TOut) Take(Handler> handler); private Task<(bool, TOut)> _take_cancelled_task; private Task<(bool, TOut)> TakeCancelledTask { get { if (_take_cancelled_task == null) _take_cancelled_task = Task.FromCanceled<(bool, TOut)>(CancellationToken.None); return _take_cancelled_task; } } private Task _put_cancelled_task; private Task PutCancelledTask { get { if (_put_cancelled_task == null) _put_cancelled_task = Task.FromCanceled(CancellationToken.None); return _put_cancelled_task; } } public ValueTask<(bool, TOut)> Take(bool onCaller) { var handler = new TakeTaskHandler(); var (resultType, val) = Take(handler); switch (resultType) { case AsyncResult.Closed: return new ValueTask<(bool, TOut)>((false, default)); case AsyncResult.Completed: return new ValueTask<(bool, TOut)>((true, val)); case AsyncResult.Enqueued: return new ValueTask<(bool, TOut)>(handler.TaskCompletionSource.Task); case AsyncResult.Canceled: return new ValueTask<(bool, TOut)>(TakeCancelledTask); default: // Should never happen throw new InvalidDataException(); } } public ValueTask Put(TIn val, bool onCaller) { var handler = new PutTaskHandler(); var (resultType, putResult) = Put(val, handler); switch (resultType) { case AsyncResult.Completed: return new ValueTask(putResult); case AsyncResult.Canceled: return new ValueTask(PutCancelledTask); case AsyncResult.Closed: return new ValueTask(false); case AsyncResult.Enqueued: return new ValueTask(handler.TaskCompletionSource.Task); default: // Should never happen throw new InvalidDataException(); } } } }