-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #89 from AnnulusGames/feature-tovaluetask
Add: ToValueTask
- Loading branch information
Showing
12 changed files
with
434 additions
and
64 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
7 changes: 7 additions & 0 deletions
7
src/LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/IMotionTaskSourcePoolNode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace LitMotion | ||
{ | ||
internal interface IMotionTaskSourcePoolNode<T> where T : class | ||
{ | ||
ref T NextNode { get; } | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/IMotionTaskSourcePoolNode.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
65 changes: 65 additions & 0 deletions
65
src/LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/TaskSourcePool.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using System.Threading; | ||
|
||
namespace LitMotion | ||
{ | ||
// This implementation is based on UniTask's TaskPool<T> | ||
// Reference: https://github.com/Cysharp/UniTask/blob/64792b672d35e43b3412fc74861f8bdbf41e3a6f/src/UniTask/Assets/Plugins/UniTask/Runtime/TaskPool.cs | ||
|
||
[StructLayout(LayoutKind.Auto)] | ||
internal struct MotionTaskSourcePool<T> where T : class, IMotionTaskSourcePoolNode<T> | ||
{ | ||
static readonly int MaxPoolSize = int.MaxValue; | ||
|
||
int gate; | ||
int size; | ||
T root; | ||
|
||
public readonly int Size => size; | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool TryPop(out T result) | ||
{ | ||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) | ||
{ | ||
var v = root; | ||
if (v != null) | ||
{ | ||
ref var nextNode = ref v.NextNode; | ||
root = nextNode; | ||
nextNode = null; | ||
size--; | ||
result = v; | ||
Volatile.Write(ref gate, 0); | ||
return true; | ||
} | ||
|
||
Volatile.Write(ref gate, 0); | ||
} | ||
result = default; | ||
return false; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public bool TryPush(T item) | ||
{ | ||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) | ||
{ | ||
if (size < MaxPoolSize) | ||
{ | ||
item.NextNode = root; | ||
root = item; | ||
size++; | ||
Volatile.Write(ref gate, 0); | ||
return true; | ||
} | ||
else | ||
{ | ||
Volatile.Write(ref gate, 0); | ||
} | ||
} | ||
return false; | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/TaskSourcePool.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
164 changes: 164 additions & 0 deletions
164
src/LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/ValueTaskMotionConfiguredSource.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks.Sources; | ||
|
||
namespace LitMotion | ||
{ | ||
internal sealed class ValueTaskMotionConfiguredSource : IValueTaskSource, IMotionTaskSourcePoolNode<ValueTaskMotionConfiguredSource> | ||
{ | ||
static MotionTaskSourcePool<ValueTaskMotionConfiguredSource> pool; | ||
|
||
ValueTaskMotionConfiguredSource nextNode; | ||
public ref ValueTaskMotionConfiguredSource NextNode => ref nextNode; | ||
|
||
readonly Action onCancelCallbackDelegate; | ||
readonly Action onCompleteCallbackDelegate; | ||
|
||
MotionHandle motionHandle; | ||
CancellationToken cancellationToken; | ||
CancellationTokenRegistration cancellationRegistration; | ||
|
||
Action originalCompleteAction; | ||
Action originalCancelAction; | ||
ManualResetValueTaskSourceCore<object> core; | ||
|
||
static ValueTaskMotionConfiguredSource FromCanceled(out short token) | ||
{ | ||
if (canceledSource == null) | ||
{ | ||
canceledSource = new(); | ||
canceledSource.core.SetException(new OperationCanceledException()); | ||
} | ||
|
||
token = canceledSource.Version; | ||
return canceledSource; | ||
} | ||
static ValueTaskMotionConfiguredSource canceledSource; | ||
|
||
ValueTaskMotionConfiguredSource() | ||
{ | ||
onCancelCallbackDelegate = new(OnCancelCallbackDelegate); | ||
onCompleteCallbackDelegate = new(OnCompleteCallbackDelegate); | ||
} | ||
|
||
public static IValueTaskSource Create(MotionHandle motionHandle, CancellationToken cancellationToken, out short token) | ||
{ | ||
if (cancellationToken.IsCancellationRequested) | ||
{ | ||
motionHandle.Cancel(); | ||
return FromCanceled(out token); | ||
} | ||
|
||
if (!pool.TryPop(out var result)) | ||
{ | ||
result = new ValueTaskMotionConfiguredSource(); | ||
} | ||
|
||
result.motionHandle = motionHandle; | ||
result.cancellationToken = cancellationToken; | ||
|
||
var callbacks = MotionStorageManager.GetMotionCallbacks(motionHandle); | ||
result.originalCancelAction = callbacks.OnCancelAction; | ||
result.originalCompleteAction = callbacks.OnCompleteAction; | ||
callbacks.OnCancelAction = result.onCancelCallbackDelegate; | ||
callbacks.OnCompleteAction = result.onCompleteCallbackDelegate; | ||
MotionStorageManager.SetMotionCallbacks(motionHandle, callbacks); | ||
|
||
if (result.originalCancelAction == result.onCancelCallbackDelegate) | ||
{ | ||
result.originalCancelAction = null; | ||
} | ||
if (result.originalCompleteAction == result.onCompleteCallbackDelegate) | ||
{ | ||
result.originalCompleteAction = null; | ||
} | ||
|
||
if (cancellationToken.CanBeCanceled) | ||
{ | ||
result.cancellationRegistration = cancellationToken.Register(static x => | ||
{ | ||
var source = (ValueTaskMotionConfiguredSource)x; | ||
var motionHandle = source.motionHandle; | ||
if (motionHandle.IsActive()) | ||
{ | ||
motionHandle.Cancel(); | ||
} | ||
else | ||
{ | ||
source.core.SetException(new OperationCanceledException()); | ||
} | ||
}, result); | ||
} | ||
|
||
token = result.core.Version; | ||
return result; | ||
} | ||
|
||
public short Version => core.Version; | ||
|
||
void OnCompleteCallbackDelegate() | ||
{ | ||
if (cancellationToken.IsCancellationRequested) | ||
{ | ||
core.SetException(new OperationCanceledException()); | ||
} | ||
else | ||
{ | ||
originalCompleteAction?.Invoke(); | ||
core.SetResult(null); | ||
} | ||
} | ||
|
||
void OnCancelCallbackDelegate() | ||
{ | ||
originalCancelAction?.Invoke(); | ||
core.SetException(new OperationCanceledException()); | ||
} | ||
|
||
public void GetResult(short token) | ||
{ | ||
try | ||
{ | ||
core.GetResult(token); | ||
} | ||
finally | ||
{ | ||
TryReturn(); | ||
} | ||
} | ||
|
||
public ValueTaskSourceStatus GetStatus(short token) | ||
{ | ||
return core.GetStatus(token); | ||
} | ||
|
||
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags) | ||
{ | ||
core.OnCompleted(continuation, state, token, flags); | ||
} | ||
|
||
bool TryReturn() | ||
{ | ||
core.Reset(); | ||
cancellationRegistration.Dispose(); | ||
|
||
RestoreOriginalCallback(); | ||
|
||
motionHandle = default; | ||
cancellationToken = default; | ||
originalCompleteAction = default; | ||
originalCancelAction = default; | ||
|
||
return pool.TryPush(this); | ||
} | ||
|
||
void RestoreOriginalCallback() | ||
{ | ||
if (!motionHandle.IsActive()) return; | ||
var callbacks = MotionStorageManager.GetMotionCallbacks(motionHandle); | ||
callbacks.OnCancelAction = originalCancelAction; | ||
callbacks.OnCompleteAction = originalCompleteAction; | ||
MotionStorageManager.SetMotionCallbacks(motionHandle, callbacks); | ||
} | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
...LitMotion/Assets/LitMotion/Runtime/Internal/Tasks/ValueTaskMotionConfiguredSource.cs.meta
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.