reduce AsyncTrigger allocation
parent
79f770e687
commit
859eaa2278
|
@ -15,6 +15,55 @@ using System.Reactive.Concurrency;
|
||||||
|
|
||||||
namespace NetCoreSandbox
|
namespace NetCoreSandbox
|
||||||
{
|
{
|
||||||
|
public class Text
|
||||||
|
{
|
||||||
|
|
||||||
|
public string text { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class UnityUIComponentExtensions
|
||||||
|
{
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
|
||||||
|
{
|
||||||
|
AAAACORECORE(source, text).Forget();
|
||||||
|
|
||||||
|
async UniTaskVoid AAAACORECORE(IUniTaskAsyncEnumerable<string> source2, Text text2)
|
||||||
|
{
|
||||||
|
var e = source2.GetAsyncEnumerator();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (await e.MoveNextAsync())
|
||||||
|
{
|
||||||
|
text2.text = e.Current;
|
||||||
|
// action(e.Current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static string FlattenGenArgs(Type type)
|
static string FlattenGenArgs(Type type)
|
||||||
|
|
|
@ -19,56 +19,13 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
}
|
}
|
||||||
|
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public class AsyncAwakeTrigger : MonoBehaviour
|
public sealed class AsyncAwakeTrigger : AsyncTriggerBase<AsyncUnit>
|
||||||
{
|
{
|
||||||
bool called = false;
|
|
||||||
TriggerEvent<AsyncUnit> triggerEvent;
|
|
||||||
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
called = true;
|
|
||||||
triggerEvent?.TrySetResult(AsyncUnit.Default);
|
|
||||||
triggerEvent = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniTask AwakeAsync()
|
public UniTask AwakeAsync()
|
||||||
{
|
{
|
||||||
if (called) return UniTask.CompletedTask;
|
if (calledAwake) return UniTask.CompletedTask;
|
||||||
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(this, true)).OneShotAsync();
|
||||||
|
|
||||||
if (triggerEvent == null)
|
|
||||||
{
|
|
||||||
triggerEvent = new TriggerEvent<AsyncUnit>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(triggerEvent, true)).OneShotAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
triggerEvent?.TrySetCanceled(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
class AwakeMonitor : IPlayerLoopItem
|
|
||||||
{
|
|
||||||
readonly AsyncAwakeTrigger trigger;
|
|
||||||
|
|
||||||
public AwakeMonitor(AsyncAwakeTrigger trigger)
|
|
||||||
{
|
|
||||||
this.trigger = trigger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (trigger.called) return false;
|
|
||||||
if (trigger == null)
|
|
||||||
{
|
|
||||||
trigger.OnDestroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,10 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
}
|
}
|
||||||
|
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public class AsyncDestroyTrigger : MonoBehaviour
|
public sealed class AsyncDestroyTrigger : MonoBehaviour
|
||||||
{
|
{
|
||||||
bool awakeCalled = false;
|
bool awakeCalled = false;
|
||||||
bool called = false;
|
bool called = false;
|
||||||
TriggerEvent<AsyncUnit> triggerEvent;
|
|
||||||
CancellationTokenSource cancellationTokenSource;
|
CancellationTokenSource cancellationTokenSource;
|
||||||
|
|
||||||
public CancellationToken CancellationToken
|
public CancellationToken CancellationToken
|
||||||
|
@ -34,6 +33,12 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
{
|
{
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!awakeCalled)
|
||||||
|
{
|
||||||
|
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||||
|
}
|
||||||
|
|
||||||
return cancellationTokenSource.Token;
|
return cancellationTokenSource.Token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,28 +52,24 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
{
|
{
|
||||||
called = true;
|
called = true;
|
||||||
|
|
||||||
triggerEvent?.TrySetResult(AsyncUnit.Default);
|
|
||||||
cancellationTokenSource?.Cancel();
|
cancellationTokenSource?.Cancel();
|
||||||
cancellationTokenSource?.Dispose();
|
cancellationTokenSource?.Dispose();
|
||||||
|
|
||||||
triggerEvent = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTask OnDestroyAsync()
|
public UniTask OnDestroyAsync()
|
||||||
{
|
{
|
||||||
if (called) return UniTask.CompletedTask;
|
if (called) return UniTask.CompletedTask;
|
||||||
|
|
||||||
if (!awakeCalled)
|
var tcs = new UniTaskCompletionSource();
|
||||||
{
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (triggerEvent == null)
|
// OnDestroy = Called Cancel.
|
||||||
|
CancellationToken.RegisterWithoutCaptureExecutionContext(state =>
|
||||||
{
|
{
|
||||||
triggerEvent = new TriggerEvent<AsyncUnit>();
|
var tcs2 = (UniTaskCompletionSource)state;
|
||||||
}
|
tcs2.TrySetResult();
|
||||||
|
}, tcs);
|
||||||
|
|
||||||
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(triggerEvent, true)).OneShotAsync();
|
return tcs.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AwakeMonitor : IPlayerLoopItem
|
class AwakeMonitor : IPlayerLoopItem
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||||
|
|
||||||
using System.Threading;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Triggers
|
namespace Cysharp.Threading.Tasks.Triggers
|
||||||
|
@ -19,67 +18,21 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
}
|
}
|
||||||
|
|
||||||
[DisallowMultipleComponent]
|
[DisallowMultipleComponent]
|
||||||
public class AsyncStartTrigger : MonoBehaviour
|
public sealed class AsyncStartTrigger : AsyncTriggerBase<AsyncUnit>
|
||||||
{
|
{
|
||||||
bool awakeCalled = false;
|
bool called;
|
||||||
bool called = false;
|
|
||||||
TriggerEvent<AsyncUnit> triggerEvent;
|
|
||||||
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
awakeCalled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
called = true;
|
called = true;
|
||||||
triggerEvent?.TrySetResult(AsyncUnit.Default);
|
RaiseEvent(AsyncUnit.Default);
|
||||||
triggerEvent = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UniTask StartAsync()
|
public UniTask StartAsync()
|
||||||
{
|
{
|
||||||
if (called) return UniTask.CompletedTask;
|
if (called) return UniTask.CompletedTask;
|
||||||
|
|
||||||
if (!awakeCalled)
|
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(this, true)).OneShotAsync();
|
||||||
{
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (triggerEvent == null)
|
|
||||||
{
|
|
||||||
triggerEvent = new TriggerEvent<AsyncUnit>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(triggerEvent, true)).OneShotAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
triggerEvent?.TrySetCanceled(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
class AwakeMonitor : IPlayerLoopItem
|
|
||||||
{
|
|
||||||
readonly AsyncStartTrigger trigger;
|
|
||||||
|
|
||||||
public AwakeMonitor(AsyncStartTrigger trigger)
|
|
||||||
{
|
|
||||||
this.trigger = trigger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext()
|
|
||||||
{
|
|
||||||
if (trigger.called) return false;
|
|
||||||
if (trigger == null)
|
|
||||||
{
|
|
||||||
trigger.OnDestroy();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -10,67 +10,67 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
{
|
{
|
||||||
public abstract class AsyncTriggerBase<T> : MonoBehaviour, IUniTaskAsyncEnumerable<T>
|
public abstract class AsyncTriggerBase<T> : MonoBehaviour, IUniTaskAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
protected TriggerEvent<T> triggerEvent;
|
TriggerEvent<T> triggerEvent;
|
||||||
|
|
||||||
bool calledAwake;
|
internal protected bool calledAwake;
|
||||||
bool calledDestroy;
|
internal protected bool calledDestroy;
|
||||||
ICancelPromise triggerSlot;
|
|
||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
calledAwake = true;
|
calledAwake = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TriggerEvent<T> GetTriggerEvent()
|
|
||||||
{
|
|
||||||
if (triggerEvent == null)
|
|
||||||
{
|
|
||||||
triggerEvent = new TriggerEvent<T>();
|
|
||||||
if (triggerSlot == null)
|
|
||||||
{
|
|
||||||
triggerSlot = triggerEvent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("triggerSlot is already filled.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!calledAwake)
|
|
||||||
{
|
|
||||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
return triggerEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnDestroy()
|
void OnDestroy()
|
||||||
{
|
{
|
||||||
if (calledDestroy) return;
|
if (calledDestroy) return;
|
||||||
calledDestroy = true;
|
calledDestroy = true;
|
||||||
|
|
||||||
triggerSlot?.TrySetCanceled();
|
triggerEvent.TrySetCanceled(CancellationToken.None);
|
||||||
triggerSlot = null;
|
}
|
||||||
|
|
||||||
|
internal void AddHandler(IResolveCancelPromise<T> handler)
|
||||||
|
{
|
||||||
|
if (!calledAwake)
|
||||||
|
{
|
||||||
|
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEvent.Add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RemoveHandler(IResolveCancelPromise<T> handler)
|
||||||
|
{
|
||||||
|
if (!calledAwake)
|
||||||
|
{
|
||||||
|
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerEvent.Remove(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RaiseEvent(T value)
|
||||||
|
{
|
||||||
|
triggerEvent.TrySetResult(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return new AsyncTriggerEnumerator(GetTriggerEvent(), cancellationToken);
|
return new AsyncTriggerEnumerator(this, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
||||||
{
|
{
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
readonly TriggerEvent<T> triggerEvent;
|
readonly AsyncTriggerBase<T> parent;
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration registration;
|
CancellationTokenRegistration registration;
|
||||||
bool called;
|
bool called;
|
||||||
bool isDisposed;
|
bool isDisposed;
|
||||||
|
|
||||||
public AsyncTriggerEnumerator(TriggerEvent<T> triggerEvent, CancellationToken cancellationToken)
|
public AsyncTriggerEnumerator(AsyncTriggerBase<T> parent, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
this.triggerEvent = triggerEvent;
|
this.parent = parent;
|
||||||
this.cancellationToken = cancellationToken;
|
this.cancellationToken = cancellationToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,13 +105,13 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
called = true;
|
called = true;
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(this, 3);
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
triggerEvent.Add(this);
|
parent.AddHandler(this);
|
||||||
if (cancellationToken.CanBeCanceled)
|
if (cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UniTask<bool>(this, completionSource.Version);
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
registration.Dispose();
|
registration.Dispose();
|
||||||
triggerEvent.Remove(this);
|
parent.RemoveHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return default;
|
return default;
|
||||||
|
@ -169,7 +169,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
{
|
{
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
readonly TriggerEvent<T> trigger;
|
readonly AsyncTriggerBase<T> trigger;
|
||||||
|
|
||||||
CancellationToken cancellationToken;
|
CancellationToken cancellationToken;
|
||||||
CancellationTokenRegistration registration;
|
CancellationTokenRegistration registration;
|
||||||
|
@ -180,7 +180,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
|
|
||||||
internal CancellationToken CancellationToken => cancellationToken;
|
internal CancellationToken CancellationToken => cancellationToken;
|
||||||
|
|
||||||
public AsyncTriggerHandler(TriggerEvent<T> trigger, bool callOnce)
|
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
@ -193,12 +193,12 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
this.registration = default;
|
this.registration = default;
|
||||||
this.callOnce = callOnce;
|
this.callOnce = callOnce;
|
||||||
|
|
||||||
trigger.Add(this);
|
trigger.AddHandler(this);
|
||||||
|
|
||||||
TaskTracker.TrackActiveTask(this, 3);
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncTriggerHandler(TriggerEvent<T> trigger, CancellationToken cancellationToken, bool callOnce)
|
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, CancellationToken cancellationToken, bool callOnce)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
@ -210,7 +210,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
this.cancellationToken = cancellationToken;
|
this.cancellationToken = cancellationToken;
|
||||||
this.callOnce = callOnce;
|
this.callOnce = callOnce;
|
||||||
|
|
||||||
trigger.Add(this);
|
trigger.AddHandler(this);
|
||||||
|
|
||||||
if (cancellationToken.CanBeCanceled)
|
if (cancellationToken.CanBeCanceled)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +235,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
TaskTracker.RemoveTracking(this);
|
TaskTracker.RemoveTracking(this);
|
||||||
registration.Dispose();
|
registration.Dispose();
|
||||||
trigger.Remove(this);
|
trigger.RemoveHandler(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,8 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class TriggerEvent<T> : IResolveCancelPromise<T>
|
// be careful to use, itself is struct.
|
||||||
|
public struct TriggerEvent<T>
|
||||||
{
|
{
|
||||||
// optimize: many cases, handler is single.
|
// optimize: many cases, handler is single.
|
||||||
IResolveCancelPromise<T> singleHandler;
|
IResolveCancelPromise<T> singleHandler;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -151,27 +151,27 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
{
|
{
|
||||||
void <#= (t.handlerInterface == null) ? "" : $"{t.handlerInterface}." #><#= t.methodName #>(<#= BuildMethodArgument(t.arguments) #>)
|
void <#= (t.handlerInterface == null) ? "" : $"{t.handlerInterface}." #><#= t.methodName #>(<#= BuildMethodArgument(t.arguments) #>)
|
||||||
{
|
{
|
||||||
triggerEvent?.TrySetResult(<#= BuildResultParameter(t.arguments) #>);
|
RaiseEvent(<#= BuildResultParameter(t.arguments) #>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <#= ToInterfaceName(t.methodName) #> Get<#= t.methodName #>AsyncHandler()
|
public <#= ToInterfaceName(t.methodName) #> Get<#= t.methodName #>AsyncHandler()
|
||||||
{
|
{
|
||||||
return new AsyncTriggerHandler<<#= t.returnType #>>(GetTriggerEvent(), false);
|
return new AsyncTriggerHandler<<#= t.returnType #>>(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <#= ToInterfaceName(t.methodName) #> Get<#= t.methodName #>AsyncHandler(CancellationToken cancellationToken)
|
public <#= ToInterfaceName(t.methodName) #> Get<#= t.methodName #>AsyncHandler(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new AsyncTriggerHandler<<#= t.returnType #>>(GetTriggerEvent(), cancellationToken, false);
|
return new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <#= ToUniTaskName(t.returnType) #> <#= t.methodName #>Async()
|
public <#= ToUniTaskName(t.returnType) #> <#= t.methodName #>Async()
|
||||||
{
|
{
|
||||||
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(GetTriggerEvent(), true)).<#= t.methodName #>Async();
|
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(this, true)).<#= t.methodName #>Async();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <#= ToUniTaskName(t.returnType) #> <#= t.methodName #>Async(CancellationToken cancellationToken)
|
public <#= ToUniTaskName(t.returnType) #> <#= t.methodName #>Async(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(GetTriggerEvent(), cancellationToken, true)).<#= t.methodName #>Async();
|
return ((<#= ToInterfaceName(t.methodName) #>)new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, true)).<#= t.methodName #>Async();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<# if(Is2019_3(t.triggerName)) { #>
|
<# if(Is2019_3(t.triggerName)) { #>
|
||||||
|
|
|
@ -37,6 +37,200 @@ public enum MyEnum
|
||||||
A, B, C
|
A, B, C
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public interface IAsyncReadOnlyReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
||||||
|
{
|
||||||
|
T Value { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public interface IAsyncReactiveProperty<T> : IAsyncReadOnlyReactiveProperty<T>
|
||||||
|
{
|
||||||
|
new T Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public struct AsyncValueReactiveProperty<T> : IUniTaskAsyncEnumerable<T>
|
||||||
|
{
|
||||||
|
TriggerEvent<T> triggerEvent;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
T latestValue;
|
||||||
|
|
||||||
|
public T Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return latestValue;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.latestValue = value;
|
||||||
|
triggerEvent.TrySetResult(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncValueReactiveProperty(T value)
|
||||||
|
{
|
||||||
|
this.latestValue = value;
|
||||||
|
this.triggerEvent = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return new Enumerator(triggerEvent, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Enumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
||||||
|
{
|
||||||
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
readonly TriggerEvent<T> triggerEvent;
|
||||||
|
readonly CancellationToken cancellationToken;
|
||||||
|
readonly CancellationTokenRegistration cancellationTokenRegistration;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
public Enumerator(TriggerEvent<T> triggerEvent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.triggerEvent = triggerEvent;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
triggerEvent.Add(this);
|
||||||
|
|
||||||
|
if (cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Current => value;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
triggerEvent.TrySetCanceled(cancellationToken);
|
||||||
|
triggerEvent.Remove(this);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetResult(T value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
return triggerEvent.TrySetResult(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TrySetCanceled(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
DisposeAsync().Forget();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (Enumerator)state;
|
||||||
|
self.DisposeAsync().Forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static partial class UnityUIComponentExtensions
|
||||||
|
{
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, text.GetCancellationTokenOnDestroy(), rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError = true)
|
||||||
|
{
|
||||||
|
BindToCore(source, text, cancellationToken, rebindOnError).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid BindToCore(IUniTaskAsyncEnumerable<string> source, Text text, CancellationToken cancellationToken, bool rebindOnError)
|
||||||
|
{
|
||||||
|
var repeat = false;
|
||||||
|
BIND_AGAIN:
|
||||||
|
var e = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool moveNext;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = await e.MoveNextAsync();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is OperationCanceledException) return;
|
||||||
|
|
||||||
|
if (rebindOnError && !repeat)
|
||||||
|
{
|
||||||
|
repeat = true;
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
goto BIND_AGAIN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!moveNext) return;
|
||||||
|
|
||||||
|
text.text = e.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
await e.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState(text, (x, t) => t.text = x.ToString());
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToText<T>(this IObservable<T> source, Text text, Func<T, string> selector)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState2(text, selector, (x, t, s) => t.text = s(x));
|
||||||
|
//}
|
||||||
|
|
||||||
|
//public static IDisposable SubscribeToInteractable(this IObservable<bool> source, Selectable selectable)
|
||||||
|
//{
|
||||||
|
// return source.SubscribeWithState(selectable, (x, s) => s.interactable = x);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class MyClass
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public class SandboxMain : MonoBehaviour
|
public class SandboxMain : MonoBehaviour
|
||||||
{
|
{
|
||||||
public Button okButton;
|
public Button okButton;
|
||||||
|
@ -148,16 +342,27 @@ public class SandboxMain : MonoBehaviour
|
||||||
// UniTaskAsyncEnumerable.EveryUpdate(PlayerLoopTiming.FixedUpdate)
|
// UniTaskAsyncEnumerable.EveryUpdate(PlayerLoopTiming.FixedUpdate)
|
||||||
|
|
||||||
|
|
||||||
await UniTask.Yield(PlayerLoopTiming.Update);
|
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
||||||
Debug.Log("Start:" + Time.frameCount);
|
{
|
||||||
|
UnityEngine.Debug.Log("Update Trigger 1");
|
||||||
|
}).Forget();
|
||||||
|
|
||||||
await UniTaskAsyncEnumerable.TimerFrame(3, 5, PlayerLoopTiming.PostLateUpdate)
|
|
||||||
.Select(x => x)
|
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
||||||
.Do(x => Debug.Log("DODODO"))
|
{
|
||||||
.ForEachAsync(_ =>
|
UnityEngine.Debug.Log("Update Trigger 2");
|
||||||
{
|
}).Forget();
|
||||||
Debug.Log("Call:" + Time.frameCount);
|
|
||||||
}, cancellationToken: this.GetCancellationTokenOnDestroy());
|
//await UniTask.Yield(PlayerLoopTiming.Update);
|
||||||
|
//Debug.Log("Start:" + Time.frameCount);
|
||||||
|
|
||||||
|
//await UniTaskAsyncEnumerable.TimerFrame(3, 5, PlayerLoopTiming.PostLateUpdate)
|
||||||
|
// .Select(x => x)
|
||||||
|
// .Do(x => Debug.Log("DODODO"))
|
||||||
|
// .ForEachAsync(_ =>
|
||||||
|
// {
|
||||||
|
// Debug.Log("Call:" + Time.frameCount);
|
||||||
|
// }, cancellationToken: this.GetCancellationTokenOnDestroy());
|
||||||
|
|
||||||
//try
|
//try
|
||||||
//{
|
//{
|
||||||
|
|
Loading…
Reference in New Issue