Skip to content

Commit c83e20a

Browse files
committed
Fix #4
1 parent d96f252 commit c83e20a

17 files changed

+234
-137
lines changed

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncCommand.T.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public AsyncCommand(Func<T, CancellationToken, UniTask> action, Func<bool> canEx
1818

1919
public void Execute(T parameter)
2020
{
21+
if (IsRunning && AllowConcurrency == false)
22+
{
23+
return;
24+
}
25+
2126
ExecuteAsync(parameter).Forget();
2227
}
2328

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncCommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public AsyncCommand(Func<CancellationToken, UniTask> action, Func<bool> canExecu
1818

1919
public void Execute()
2020
{
21+
if (IsRunning && AllowConcurrency == false)
22+
{
23+
return;
24+
}
25+
2126
ExecuteAsync().Forget();
2227
}
2328

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncLazyCommand.T.cs

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncLazyCommand.T.cs.meta

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncLazyCommand.cs

Lines changed: 0 additions & 44 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/AsyncLazyCommand.cs.meta

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/BaseAsyncCommand.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace UnityMvvmToolkit.UniTask
55
using Core;
66
using System;
77
using Interfaces;
8+
using Extensions;
89
using System.Runtime.CompilerServices;
910

1011
public abstract class BaseAsyncCommand : BaseCommand, IBaseAsyncCommand
@@ -25,6 +26,8 @@ protected set
2526
}
2627
}
2728

29+
public bool AllowConcurrency { get; set; }
30+
2831
public virtual bool DisableOnExecution { get; set; }
2932

3033
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -40,6 +43,8 @@ public override bool CanExecute()
4043

4144
public virtual void Cancel()
4245
{
46+
throw new InvalidOperationException(
47+
$"To make the 'AsyncCommand' cancelable, use '{nameof(AsyncCommandExtensions.WithCancellation)}' extension.");
4348
}
4449
}
4550
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/BaseAsyncLazyCommand.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/BaseAsyncLazyCommand.cs.meta

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/Extensions/AsyncCommandExtensions.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ public static IAsyncCommand WithCancellation(this IAsyncCommand asyncCommand)
1515
throw new NullReferenceException(nameof(asyncCommand));
1616
}
1717

18-
return new AsyncCommandWithCancellation(asyncCommand);
18+
return asyncCommand.AllowConcurrency
19+
? new AsyncCommandWithCancellation(asyncCommand)
20+
: new AsyncLazyCommandWithCancellation(asyncCommand);
1921
}
2022

2123
public static IAsyncCommand<T> WithCancellation<T>(this IAsyncCommand<T> asyncCommand)
@@ -25,7 +27,9 @@ public static IAsyncCommand<T> WithCancellation<T>(this IAsyncCommand<T> asyncCo
2527
throw new NullReferenceException(nameof(asyncCommand));
2628
}
2729

28-
return new AsyncCommandWithCancellation<T>(asyncCommand);
30+
return asyncCommand.AllowConcurrency
31+
? new AsyncCommandWithCancellation<T>(asyncCommand)
32+
: new AsyncLazyCommandWithCancellation<T>(asyncCommand);
2933
}
3034
}
3135
}

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/Interfaces/IBaseAsyncCommand.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace UnityMvvmToolkit.UniTask.Interfaces
55
public interface IBaseAsyncCommand
66
{
77
bool IsRunning { get; }
8+
bool AllowConcurrency { get; set; }
89
bool DisableOnExecution { get; set; }
910

1011
void Cancel();

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/Internal/AsyncCommandWithCancellation.T.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@ namespace UnityMvvmToolkit.UniTask.Internal
66
using Interfaces;
77
using System.Threading;
88
using Cysharp.Threading.Tasks;
9+
using System.Collections.Concurrent;
10+
using System.Runtime.CompilerServices;
911

1012
internal class AsyncCommandWithCancellation<T> : BaseAsyncCommand, IAsyncCommand<T>
1113
{
1214
private readonly IAsyncCommand<T> _asyncCommand;
15+
private readonly ConcurrentQueue<UniTask> _runningCommands;
16+
1317
private CancellationTokenSource _cancellationTokenSource;
1418

1519
public AsyncCommandWithCancellation(IAsyncCommand<T> asyncCommand) : base(null)
1620
{
1721
_asyncCommand = asyncCommand;
22+
_runningCommands = new ConcurrentQueue<UniTask>();
1823
}
1924

25+
public override bool IsRunning { get; protected set; }
26+
2027
public override bool DisableOnExecution
2128
{
2229
get => _asyncCommand.DisableOnExecution;
@@ -31,20 +38,35 @@ public override event EventHandler<bool> CanExecuteChanged
3138

3239
public void Execute(T parameter)
3340
{
34-
ExecuteAsync(parameter).Forget();
41+
if (IsRunning)
42+
{
43+
TryEnqueueAsyncCommand(parameter, _cancellationTokenSource.Token);
44+
}
45+
else
46+
{
47+
ExecuteAsync(parameter).Forget();
48+
}
3549
}
3650

3751
public async UniTask ExecuteAsync(T parameter, CancellationToken cancellationToken = default)
3852
{
39-
_cancellationTokenSource?.Cancel();
40-
_cancellationTokenSource = new CancellationTokenSource();
53+
_cancellationTokenSource ??= new CancellationTokenSource();
4154

4255
try
4356
{
44-
await _asyncCommand.ExecuteAsync(parameter, _cancellationTokenSource.Token);
57+
IsRunning = true;
58+
59+
TryEnqueueAsyncCommand(parameter, _cancellationTokenSource.Token);
60+
61+
while (_runningCommands.TryDequeue(out var asyncCommand))
62+
{
63+
await asyncCommand;
64+
}
4565
}
4666
finally
4767
{
68+
IsRunning = false;
69+
4870
_cancellationTokenSource?.Dispose();
4971
_cancellationTokenSource = null;
5072
}
@@ -54,6 +76,17 @@ public override void Cancel()
5476
{
5577
_cancellationTokenSource?.Cancel();
5678
}
79+
80+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
81+
private void TryEnqueueAsyncCommand(T parameter, CancellationToken cancellationToken)
82+
{
83+
if (cancellationToken.IsCancellationRequested)
84+
{
85+
return;
86+
}
87+
88+
_runningCommands.Enqueue(_asyncCommand.ExecuteAsync(parameter, cancellationToken));
89+
}
5790
}
5891
}
5992

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/Internal/AsyncCommandWithCancellation.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@ namespace UnityMvvmToolkit.UniTask.Internal
66
using Interfaces;
77
using System.Threading;
88
using Cysharp.Threading.Tasks;
9+
using System.Collections.Concurrent;
10+
using System.Runtime.CompilerServices;
911

1012
internal class AsyncCommandWithCancellation : BaseAsyncCommand, IAsyncCommand
1113
{
1214
private readonly IAsyncCommand _asyncCommand;
15+
private readonly ConcurrentQueue<UniTask> _runningCommands;
16+
1317
private CancellationTokenSource _cancellationTokenSource;
1418

1519
public AsyncCommandWithCancellation(IAsyncCommand asyncCommand) : base(null)
1620
{
1721
_asyncCommand = asyncCommand;
22+
_runningCommands = new ConcurrentQueue<UniTask>();
1823
}
1924

25+
public override bool IsRunning { get; protected set; }
26+
2027
public override bool DisableOnExecution
2128
{
2229
get => _asyncCommand.DisableOnExecution;
@@ -31,20 +38,35 @@ public override event EventHandler<bool> CanExecuteChanged
3138

3239
public void Execute()
3340
{
34-
ExecuteAsync().Forget();
41+
if (IsRunning)
42+
{
43+
TryEnqueueAsyncCommand(_cancellationTokenSource.Token);
44+
}
45+
else
46+
{
47+
ExecuteAsync().Forget();
48+
}
3549
}
3650

3751
public async UniTask ExecuteAsync(CancellationToken cancellationToken = default)
3852
{
39-
_cancellationTokenSource?.Cancel();
40-
_cancellationTokenSource = new CancellationTokenSource();
53+
_cancellationTokenSource ??= new CancellationTokenSource();
4154

4255
try
4356
{
44-
await _asyncCommand.ExecuteAsync(_cancellationTokenSource.Token);
57+
IsRunning = true;
58+
59+
TryEnqueueAsyncCommand(_cancellationTokenSource.Token);
60+
61+
while (_runningCommands.TryDequeue(out var asyncCommand))
62+
{
63+
await asyncCommand;
64+
}
4565
}
4666
finally
4767
{
68+
IsRunning = false;
69+
4870
_cancellationTokenSource?.Dispose();
4971
_cancellationTokenSource = null;
5072
}
@@ -54,6 +76,17 @@ public override void Cancel()
5476
{
5577
_cancellationTokenSource?.Cancel();
5678
}
79+
80+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
81+
private void TryEnqueueAsyncCommand(CancellationToken cancellationToken)
82+
{
83+
if (cancellationToken.IsCancellationRequested)
84+
{
85+
return;
86+
}
87+
88+
_runningCommands.Enqueue(_asyncCommand.ExecuteAsync(cancellationToken));
89+
}
5790
}
5891
}
5992

0 commit comments

Comments
 (0)