Skip to content

Commit 233d444

Browse files
committed
Add TransitionPromise task source.
1 parent 3bdc61e commit 233d444

File tree

7 files changed

+224
-74
lines changed

7 files changed

+224
-74
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ namespace UnityMvvmToolkit.UniTask.Interfaces
77
public interface ITransitionPredicate
88
{
99
bool TransitionEnd(TransitionEndEvent e);
10-
bool TransitionCancel(TransitionCancelEvent e);
1110
}
1211
}
1312

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

Lines changed: 30 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,34 +16,31 @@ public static class TransitionAsyncExtensions
1616
private const char Dash = '-';
1717
private const int DefaultTimeoutMs = 2500;
1818

19-
public static async UniTask WaitForLongestTransitionEnd(this VisualElement element,
19+
public static UniTask WaitForLongestTransitionEnd(this VisualElement element,
2020
CancellationToken cancellationToken = default)
2121
{
2222
var maxTransitionDelay = element.resolvedStyle.transitionDuration.Max(duration =>
2323
duration.unit == TimeUnit.Millisecond ? duration.value : duration.value * 1000);
2424

25-
if (maxTransitionDelay > float.Epsilon)
26-
{
27-
await UniTask.Delay((int) maxTransitionDelay, cancellationToken: cancellationToken);
28-
}
25+
return maxTransitionDelay > float.Epsilon
26+
? UniTask.Delay((int) maxTransitionDelay, cancellationToken: cancellationToken)
27+
: UniTask.CompletedTask;
2928
}
3029

31-
public static async UniTask WaitForTransitionEnd(this VisualElement element, int transitionIndex,
30+
public static UniTask WaitForTransitionEnd(this VisualElement element, int transitionIndex,
3231
int timeoutMs = DefaultTimeoutMs, CancellationToken cancellationToken = default)
3332
{
34-
if (GetTransitionDuration(element, transitionIndex, out var stylePropertyName) > float.Epsilon)
35-
{
36-
await WaitForTransition(element, stylePropertyName, timeoutMs, cancellationToken);
37-
}
33+
return GetTransitionDuration(element, transitionIndex, out var stylePropertyName) > float.Epsilon
34+
? WaitForTransition(element, stylePropertyName, timeoutMs, cancellationToken)
35+
: UniTask.CompletedTask;
3836
}
3937

40-
public static async UniTask WaitForTransitionEnd(this VisualElement element, StylePropertyName stylePropertyName,
38+
public static UniTask WaitForTransitionEnd(this VisualElement element, StylePropertyName stylePropertyName,
4139
int timeoutMs = DefaultTimeoutMs, CancellationToken cancellationToken = default)
4240
{
43-
if (GetTransitionDuration(element, stylePropertyName) > float.Epsilon)
44-
{
45-
await WaitForTransition(element, stylePropertyName, timeoutMs, cancellationToken);
46-
}
41+
return GetTransitionDuration(element, stylePropertyName) > float.Epsilon
42+
? WaitForTransition(element, stylePropertyName, timeoutMs, cancellationToken)
43+
: UniTask.CompletedTask;
4744
}
4845

4946
/// <summary>
@@ -54,79 +51,42 @@ public static async UniTask WaitForTransitionEnd(this VisualElement element, Sty
5451
/// <param name="timeoutMs"></param>
5552
/// <param name="cancellationToken"></param>
5653
/// <returns></returns>
57-
public static async UniTask WaitForTransitionEnd(this VisualElement element, string propertyName,
54+
public static UniTask WaitForTransitionEnd(this VisualElement element, string propertyName,
5855
int timeoutMs = DefaultTimeoutMs, CancellationToken cancellationToken = default)
5956
{
6057
var transitionData = GetTransitionData(element, propertyName);
61-
if (transitionData is { Duration: { value: > float.Epsilon } })
62-
{
63-
await WaitForTransition(element, transitionData.Value.StylePropertyName, timeoutMs, cancellationToken);
64-
}
58+
59+
return transitionData is { Duration: { value: > float.Epsilon } }
60+
? WaitForTransition(element, transitionData.Value.StylePropertyName, timeoutMs, cancellationToken)
61+
: UniTask.CompletedTask;
6562
}
6663

67-
public static async UniTask WaitForAnyTransitionEnd(this VisualElement element, int timeoutMs = DefaultTimeoutMs,
64+
public static UniTask WaitForAnyTransitionEnd(this VisualElement element, int timeoutMs = DefaultTimeoutMs,
6865
CancellationToken cancellationToken = default)
6966
{
70-
if (AnyTransitionHasDuration(element))
71-
{
72-
await WaitForTransitionEnd(element, new TransitionAnyPredicate(), timeoutMs, cancellationToken);
73-
}
67+
return AnyTransitionHasDuration(element)
68+
? WaitForTransitionEnd(element, new TransitionAnyPredicate(), timeoutMs, cancellationToken)
69+
: UniTask.CompletedTask;
7470
}
7571

76-
public static async UniTask WaitForAllTransitionsEnd(this VisualElement element, int timeoutMs = DefaultTimeoutMs,
72+
public static UniTask WaitForAllTransitionsEnd(this VisualElement element, int timeoutMs = DefaultTimeoutMs,
7773
CancellationToken cancellationToken = default)
7874
{
7975
var transitionsCount = GetTransitionsWithDurationCount(element);
80-
if (transitionsCount == 0)
81-
{
82-
return;
83-
}
8476

85-
await WaitForTransitionEnd(element, new TransitionCounterPredicate(transitionsCount), timeoutMs,
86-
cancellationToken);
77+
return transitionsCount == 0
78+
? UniTask.CompletedTask
79+
: WaitForTransitionEnd(element, new TransitionCounterPredicate(transitionsCount), timeoutMs,
80+
cancellationToken);
8781
}
8882

89-
public static async UniTask WaitForTransitionEnd<T>(this VisualElement element, T transitionPredicate,
83+
public static UniTask WaitForTransitionEnd<T>(this VisualElement element, T transitionPredicate,
9084
int timeoutMs = DefaultTimeoutMs, CancellationToken cancellationToken = default)
9185
where T : ITransitionPredicate
9286
{
93-
var taskCompletionSource = new UniTaskCompletionSource();
94-
95-
void OnTransitionEnd(TransitionEndEvent e)
96-
{
97-
if (transitionPredicate.TransitionEnd(e))
98-
{
99-
taskCompletionSource.TrySetResult();
100-
}
101-
}
102-
103-
void OnTransitionCancel(TransitionCancelEvent e)
104-
{
105-
if (transitionPredicate.TransitionCancel(e))
106-
{
107-
taskCompletionSource.TrySetCanceled();
108-
}
109-
}
110-
111-
try
112-
{
113-
element.RegisterCallback<TransitionCancelEvent>(OnTransitionCancel);
114-
element.RegisterCallback<TransitionEndEvent>(OnTransitionEnd);
115-
116-
var transitionTask = taskCompletionSource.Task;
117-
var timeoutTask = UniTask.Delay(timeoutMs, cancellationToken: cancellationToken);
118-
119-
var task = await UniTask.WhenAny(transitionTask, timeoutTask).SuppressCancellationThrow();
120-
if (task.IsCanceled || task.Result == 1)
121-
{
122-
taskCompletionSource.TrySetCanceled();
123-
}
124-
}
125-
finally
126-
{
127-
element.UnregisterCallback<TransitionCancelEvent>(OnTransitionCancel);
128-
element.UnregisterCallback<TransitionEndEvent>(OnTransitionEnd);
129-
}
87+
return new UniTask(
88+
TransitionPromise<T>.Create(element, transitionPredicate, timeoutMs, PlayerLoopTiming.Update,
89+
cancellationToken, out var token), token);
13090
}
13191

13292
[MethodImpl(MethodImplOptions.AggressiveInlining)]

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/TransitionPredicates/TransitionAnyPredicate.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace UnityMvvmToolkit.UniTask.TransitionPredicates
88
public readonly struct TransitionAnyPredicate : ITransitionPredicate
99
{
1010
public bool TransitionEnd(TransitionEndEvent e) => true;
11-
public bool TransitionCancel(TransitionCancelEvent e) => true;
1211
}
1312
}
1413

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/TransitionPredicates/TransitionCounterPredicate.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ public TransitionCounterPredicate(int transitionsCount)
1515
}
1616

1717
public bool TransitionEnd(TransitionEndEvent e) => --_transitionsCount == 0;
18-
public bool TransitionCancel(TransitionCancelEvent e) => true;
1918
}
2019
}
2120

src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/External/UniTask/TransitionPredicates/TransitionNamePredicate.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ public TransitionNamePredicate(StylePropertyName stylePropertyName)
1515
}
1616

1717
public bool TransitionEnd(TransitionEndEvent e) => e.AffectsProperty(_stylePropertyName);
18-
public bool TransitionCancel(TransitionCancelEvent e) => true;
1918
}
2019
}
2120

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#if UNITYMVVMTOOLKIT_UNITASK_SUPPORT
2+
3+
namespace UnityMvvmToolkit.UniTask
4+
{
5+
using System;
6+
using Interfaces;
7+
using System.Threading;
8+
using Cysharp.Threading.Tasks;
9+
using UnityEngine;
10+
using UnityEngine.UIElements;
11+
12+
internal sealed class TransitionPromise<T> : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<TransitionPromise<T>>
13+
where T : ITransitionPredicate
14+
{
15+
private static TaskPool<TransitionPromise<T>> _pool;
16+
17+
private TransitionPromise<T> _nextNode;
18+
private UniTaskCompletionSourceCore<AsyncUnit> _core;
19+
20+
private int _initFrame;
21+
private float _elapsed;
22+
private float _delayTime;
23+
24+
private T _predicate;
25+
private bool _completed;
26+
private VisualElement _visualElement;
27+
private CancellationToken _cancellationToken;
28+
29+
private readonly EventCallback<TransitionEndEvent> _endCallback;
30+
private readonly EventCallback<TransitionCancelEvent> _cancelCallback;
31+
32+
private TransitionPromise()
33+
{
34+
_endCallback = OnTransitionEnd;
35+
_cancelCallback = OnTransitionCancel;
36+
}
37+
38+
public ref TransitionPromise<T> NextNode => ref _nextNode;
39+
40+
static TransitionPromise()
41+
{
42+
TaskPool.RegisterSizeGetter(typeof(TransitionPromise<T>), () => _pool.Size);
43+
}
44+
45+
public static IUniTaskSource Create(VisualElement visualElement, T predicate, int timeoutMs,
46+
PlayerLoopTiming timing, CancellationToken cancellationToken, out short token)
47+
{
48+
if (cancellationToken.IsCancellationRequested)
49+
{
50+
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
51+
}
52+
53+
if (_pool.TryPop(out var transitionPromise) == false)
54+
{
55+
transitionPromise = new TransitionPromise<T>();
56+
}
57+
58+
transitionPromise._elapsed = 0.0f;
59+
transitionPromise._delayTime = (float) TimeSpan.FromMilliseconds(timeoutMs).TotalSeconds;
60+
transitionPromise._initFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
61+
62+
transitionPromise._completed = false;
63+
transitionPromise._predicate = predicate;
64+
transitionPromise._visualElement = visualElement;
65+
transitionPromise._cancellationToken = cancellationToken;
66+
67+
TaskTracker.TrackActiveTask(transitionPromise, 3);
68+
PlayerLoopHelper.AddAction(timing, transitionPromise);
69+
70+
visualElement.RegisterCallback(transitionPromise._cancelCallback);
71+
visualElement.RegisterCallback(transitionPromise._endCallback);
72+
73+
token = transitionPromise._core.Version;
74+
75+
return transitionPromise;
76+
}
77+
78+
private void OnTransitionEnd(TransitionEndEvent e)
79+
{
80+
UnregisterCallbacks();
81+
82+
if (_completed)
83+
{
84+
Reset();
85+
return;
86+
}
87+
88+
_completed = true;
89+
90+
if (_cancellationToken.IsCancellationRequested)
91+
{
92+
_core.TrySetCanceled(_cancellationToken);
93+
}
94+
else if (_predicate.TransitionEnd(e))
95+
{
96+
_core.TrySetResult(AsyncUnit.Default);
97+
}
98+
}
99+
100+
private void OnTransitionCancel(TransitionCancelEvent e)
101+
{
102+
UnregisterCallbacks();
103+
104+
if (_completed)
105+
{
106+
Reset();
107+
return;
108+
}
109+
110+
_completed = true;
111+
_core.TrySetCanceled(_cancellationToken.IsCancellationRequested ? _cancellationToken : default);
112+
}
113+
114+
private void UnregisterCallbacks()
115+
{
116+
_visualElement.UnregisterCallback(_cancelCallback);
117+
_visualElement.UnregisterCallback(_endCallback);
118+
}
119+
120+
public void GetResult(short token)
121+
{
122+
_core.GetResult(token);
123+
}
124+
125+
public UniTaskStatus GetStatus(short token)
126+
{
127+
return _core.GetStatus(token);
128+
}
129+
130+
public UniTaskStatus UnsafeGetStatus()
131+
{
132+
return _core.UnsafeGetStatus();
133+
}
134+
135+
public void OnCompleted(Action<object> continuation, object state, short token)
136+
{
137+
_core.OnCompleted(continuation, state, token);
138+
}
139+
140+
public bool MoveNext()
141+
{
142+
if (_completed)
143+
{
144+
Reset();
145+
return false;
146+
}
147+
148+
if (_cancellationToken.IsCancellationRequested)
149+
{
150+
_completed = true;
151+
_core.TrySetCanceled(_cancellationToken);
152+
153+
return false;
154+
}
155+
156+
if (_elapsed == 0.0f && _initFrame == Time.frameCount)
157+
{
158+
return true;
159+
}
160+
161+
_elapsed += Time.deltaTime;
162+
163+
if (_elapsed < _delayTime)
164+
{
165+
return true;
166+
}
167+
168+
_core.TrySetResult(AsyncUnit.Default);
169+
170+
return false;
171+
}
172+
173+
private void Reset()
174+
{
175+
TaskTracker.RemoveTracking(this);
176+
177+
_core.Reset();
178+
179+
_elapsed = default;
180+
_delayTime = default;
181+
182+
_predicate = default;
183+
_visualElement = default;
184+
_cancellationToken = default;
185+
186+
_pool.TryPush(this);
187+
}
188+
}
189+
}
190+
191+
#endif

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

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)