WutheringWaves/KcpSharp/KcpConversation.FlushAsyncMethodBuilder.cs
2024-02-08 00:41:39 +03:00

278 lines
11 KiB
C#

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace KcpSharp
{
partial class KcpConversation
{
#if NET6_0_OR_GREATER
[ThreadStatic]
private static KcpConversation? s_currentObject;
private object? _flushStateMachine;
struct KcpFlushAsyncMethodBuilder
{
private readonly KcpConversation _conversation;
private StateMachineBox? _task;
private static readonly StateMachineBox s_syncSuccessSentinel = new SyncSuccessSentinelStateMachineBox();
public KcpFlushAsyncMethodBuilder(KcpConversation conversation)
{
_conversation = conversation;
_task = null;
}
public static KcpFlushAsyncMethodBuilder Create()
{
KcpConversation? conversation = s_currentObject;
Debug.Assert(conversation is not null);
s_currentObject = null;
return new KcpFlushAsyncMethodBuilder(conversation);
}
#pragma warning disable CA1822 // Mark members as static
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Start<TStateMachine>(ref TStateMachine stateMachine)
where TStateMachine : IAsyncStateMachine
#pragma warning restore CA1822 // Mark members as static
{
Debug.Assert(stateMachine is not null);
stateMachine.MoveNext();
}
public ValueTask Task
{
get
{
if (ReferenceEquals(_task, s_syncSuccessSentinel))
{
return default;
}
StateMachineBox stateMachineBox = _task ??= CreateWeaklyTypedStateMachineBox();
return new ValueTask(stateMachineBox, stateMachineBox.Version);
}
}
#pragma warning disable CA1822 // Mark members as static
public void SetStateMachine(IAsyncStateMachine stateMachine)
#pragma warning restore CA1822 // Mark members as static
{
Debug.Fail("SetStateMachine should not be used.");
}
public void SetResult()
{
if (_task == null)
{
_task = s_syncSuccessSentinel;
}
else
{
_task.SetResult();
}
}
public void SetException(Exception exception)
{
SetException(exception, ref _task);
}
private static void SetException(Exception exception, ref StateMachineBox? boxFieldRef)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
(boxFieldRef ??= CreateWeaklyTypedStateMachineBox()).SetException(exception);
}
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine
{
AwaitOnCompleted(ref awaiter, ref stateMachine, ref _task, _conversation);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine
{
AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine, ref _task, _conversation);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? boxRef, KcpConversation conversation) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
{
StateMachineBox stateMachineBox = GetStateMachineBox(ref stateMachine, ref boxRef, conversation);
AwaitUnsafeOnCompleted(ref awaiter, stateMachineBox);
}
private static void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine, ref StateMachineBox? box, KcpConversation conversation) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
{
try
{
awaiter.OnCompleted(GetStateMachineBox(ref stateMachine, ref box, conversation).MoveNextAction);
}
catch (Exception exception)
{
var edi = ExceptionDispatchInfo.Capture(exception);
ThreadPool.QueueUserWorkItem(static state => ((ExceptionDispatchInfo)state!).Throw(), edi);
}
}
private static void AwaitUnsafeOnCompleted<TAwaiter>(ref TAwaiter awaiter, StateMachineBox box) where TAwaiter : ICriticalNotifyCompletion
{
try
{
awaiter.UnsafeOnCompleted(box.MoveNextAction);
}
catch (Exception exception)
{
var edi = ExceptionDispatchInfo.Capture(exception);
ThreadPool.QueueUserWorkItem(static state => ((ExceptionDispatchInfo)state!).Throw(), edi);
}
}
private static StateMachineBox CreateWeaklyTypedStateMachineBox()
{
return new StateMachineBox<IAsyncStateMachine>(null);
}
private static StateMachineBox GetStateMachineBox<TStateMachine>(ref TStateMachine stateMachine, ref StateMachineBox? boxFieldRef, KcpConversation conversation) where TStateMachine : IAsyncStateMachine
{
StateMachineBox<TStateMachine>? stateMachineBox = boxFieldRef as StateMachineBox<TStateMachine>;
if (stateMachineBox != null)
{
return stateMachineBox;
}
StateMachineBox<IAsyncStateMachine>? stateMachineBox2 = boxFieldRef as StateMachineBox<IAsyncStateMachine>;
if (stateMachineBox2 != null)
{
if (stateMachineBox2.StateMachine == null)
{
Debugger.NotifyOfCrossThreadDependency();
stateMachineBox2.StateMachine = stateMachine;
}
return stateMachineBox2;
}
Debugger.NotifyOfCrossThreadDependency();
StateMachineBox<TStateMachine> stateMachineBox3 = (StateMachineBox<TStateMachine>)(boxFieldRef = StateMachineBox<TStateMachine>.GetOrCreateBox(conversation));
stateMachineBox3.StateMachine = stateMachine;
return stateMachineBox3;
}
abstract class StateMachineBox : IValueTaskSource
{
protected ManualResetValueTaskSourceCore<bool> _mrvtsc;
protected Action? _moveNextAction;
public virtual Action MoveNextAction => _moveNextAction!;
public short Version => _mrvtsc.Version;
public void SetResult()
{
_mrvtsc.SetResult(true);
}
public void SetException(Exception error)
{
_mrvtsc.SetException(error);
}
public ValueTaskSourceStatus GetStatus(short token)
{
return _mrvtsc.GetStatus(token);
}
public void OnCompleted(Action<object?> continuation, object? state, short token, ValueTaskSourceOnCompletedFlags flags)
{
_mrvtsc.OnCompleted(continuation, state, token, flags);
}
void IValueTaskSource.GetResult(short token)
{
throw new NotSupportedException();
}
}
sealed class SyncSuccessSentinelStateMachineBox : StateMachineBox
{
public SyncSuccessSentinelStateMachineBox()
{
SetResult();
}
}
sealed class StateMachineBox<TStateMachine> : StateMachineBox, IValueTaskSource where TStateMachine : IAsyncStateMachine
{
[MaybeNull]
public TStateMachine StateMachine;
private KcpConversation? _conversation;
public override Action MoveNextAction => _moveNextAction ??= MoveNext;
internal StateMachineBox(KcpConversation? conversation)
{
_conversation = conversation;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static StateMachineBox<TStateMachine> GetOrCreateBox(KcpConversation conversation)
{
if (conversation._flushStateMachine is StateMachineBox<TStateMachine> stateMachine)
{
stateMachine._conversation = conversation;
conversation._flushStateMachine = null;
return stateMachine;
}
return new StateMachineBox<TStateMachine>(conversation);
}
void IValueTaskSource.GetResult(short token)
{
try
{
_mrvtsc.GetResult(token);
}
finally
{
ReturnOrDropBox();
}
}
public void MoveNext()
{
if (StateMachine is not null)
{
StateMachine.MoveNext();
}
}
private void ReturnOrDropBox()
{
StateMachine = default!;
_mrvtsc.Reset();
if (_conversation is not null)
{
_conversation._flushStateMachine = this;
_conversation = null;
}
}
}
}
#endif
}
}