mirror of https://github.com/Cysharp/UniTask
reduce AsyncTrigger allocation
parent
79f770e687
commit
859eaa2278
|
@ -15,6 +15,55 @@ using System.Reactive.Concurrency;
|
|||
|
||||
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
|
||||
{
|
||||
static string FlattenGenArgs(Type type)
|
||||
|
|
|
@ -19,56 +19,13 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
}
|
||||
|
||||
[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()
|
||||
{
|
||||
if (called) return UniTask.CompletedTask;
|
||||
if (calledAwake) return UniTask.CompletedTask;
|
||||
|
||||
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 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;
|
||||
}
|
||||
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(this, true)).OneShotAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,10 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class AsyncDestroyTrigger : MonoBehaviour
|
||||
public sealed class AsyncDestroyTrigger : MonoBehaviour
|
||||
{
|
||||
bool awakeCalled = false;
|
||||
bool called = false;
|
||||
TriggerEvent<AsyncUnit> triggerEvent;
|
||||
CancellationTokenSource cancellationTokenSource;
|
||||
|
||||
public CancellationToken CancellationToken
|
||||
|
@ -34,6 +33,12 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
{
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
if (!awakeCalled)
|
||||
{
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||
}
|
||||
|
||||
return cancellationTokenSource.Token;
|
||||
}
|
||||
}
|
||||
|
@ -47,28 +52,24 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
{
|
||||
called = true;
|
||||
|
||||
triggerEvent?.TrySetResult(AsyncUnit.Default);
|
||||
cancellationTokenSource?.Cancel();
|
||||
cancellationTokenSource?.Dispose();
|
||||
|
||||
triggerEvent = null;
|
||||
}
|
||||
|
||||
public UniTask OnDestroyAsync()
|
||||
{
|
||||
if (called) return UniTask.CompletedTask;
|
||||
|
||||
if (!awakeCalled)
|
||||
{
|
||||
PlayerLoopHelper.AddAction(PlayerLoopTiming.Update, new AwakeMonitor(this));
|
||||
}
|
||||
var tcs = new UniTaskCompletionSource();
|
||||
|
||||
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
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Triggers
|
||||
|
@ -19,67 +18,21 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public class AsyncStartTrigger : MonoBehaviour
|
||||
public sealed class AsyncStartTrigger : AsyncTriggerBase<AsyncUnit>
|
||||
{
|
||||
bool awakeCalled = false;
|
||||
bool called = false;
|
||||
TriggerEvent<AsyncUnit> triggerEvent;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
awakeCalled = true;
|
||||
}
|
||||
bool called;
|
||||
|
||||
void Start()
|
||||
{
|
||||
called = true;
|
||||
triggerEvent?.TrySetResult(AsyncUnit.Default);
|
||||
triggerEvent = null;
|
||||
RaiseEvent(AsyncUnit.Default);
|
||||
}
|
||||
|
||||
public UniTask StartAsync()
|
||||
{
|
||||
if (called) return UniTask.CompletedTask;
|
||||
|
||||
if (!awakeCalled)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return ((IAsyncOneShotTrigger)new AsyncTriggerHandler<AsyncUnit>(this, true)).OneShotAsync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -10,67 +10,67 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
{
|
||||
public abstract class AsyncTriggerBase<T> : MonoBehaviour, IUniTaskAsyncEnumerable<T>
|
||||
{
|
||||
protected TriggerEvent<T> triggerEvent;
|
||||
TriggerEvent<T> triggerEvent;
|
||||
|
||||
bool calledAwake;
|
||||
bool calledDestroy;
|
||||
ICancelPromise triggerSlot;
|
||||
internal protected bool calledAwake;
|
||||
internal protected bool calledDestroy;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (calledDestroy) return;
|
||||
calledDestroy = true;
|
||||
|
||||
triggerSlot?.TrySetCanceled();
|
||||
triggerSlot = null;
|
||||
triggerEvent.TrySetCanceled(CancellationToken.None);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return new AsyncTriggerEnumerator(GetTriggerEvent(), cancellationToken);
|
||||
return new AsyncTriggerEnumerator(this, cancellationToken);
|
||||
}
|
||||
|
||||
sealed class AsyncTriggerEnumerator : MoveNextSource, IUniTaskAsyncEnumerator<T>, IResolveCancelPromise<T>
|
||||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
readonly TriggerEvent<T> triggerEvent;
|
||||
readonly AsyncTriggerBase<T> parent;
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration registration;
|
||||
bool called;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -105,13 +105,13 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
called = true;
|
||||
|
||||
TaskTracker.TrackActiveTask(this, 3);
|
||||
triggerEvent.Add(this);
|
||||
parent.AddHandler(this);
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return new UniTask<bool>(this, completionSource.Version);
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
isDisposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
registration.Dispose();
|
||||
triggerEvent.Remove(this);
|
||||
parent.RemoveHandler(this);
|
||||
}
|
||||
|
||||
return default;
|
||||
|
@ -169,7 +169,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
{
|
||||
static Action<object> cancellationCallback = CancellationCallback;
|
||||
|
||||
readonly TriggerEvent<T> trigger;
|
||||
readonly AsyncTriggerBase<T> trigger;
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
CancellationTokenRegistration registration;
|
||||
|
@ -180,7 +180,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
|
||||
internal CancellationToken CancellationToken => cancellationToken;
|
||||
|
||||
public AsyncTriggerHandler(TriggerEvent<T> trigger, bool callOnce)
|
||||
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
|
@ -193,12 +193,12 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
this.registration = default;
|
||||
this.callOnce = callOnce;
|
||||
|
||||
trigger.Add(this);
|
||||
trigger.AddHandler(this);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -210,7 +210,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
this.cancellationToken = cancellationToken;
|
||||
this.callOnce = callOnce;
|
||||
|
||||
trigger.Add(this);
|
||||
trigger.AddHandler(this);
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
|
@ -235,7 +235,7 @@ namespace Cysharp.Threading.Tasks.Triggers
|
|||
isDisposed = true;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
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.
|
||||
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) #>)
|
||||
{
|
||||
triggerEvent?.TrySetResult(<#= BuildResultParameter(t.arguments) #>);
|
||||
RaiseEvent(<#= BuildResultParameter(t.arguments) #>);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return new AsyncTriggerHandler<<#= t.returnType #>>(GetTriggerEvent(), cancellationToken, false);
|
||||
return new AsyncTriggerHandler<<#= t.returnType #>>(this, cancellationToken, false);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)) { #>
|
||||
|
|
|
@ -37,6 +37,200 @@ public enum MyEnum
|
|||
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 Button okButton;
|
||||
|
@ -148,16 +342,27 @@ public class SandboxMain : MonoBehaviour
|
|||
// UniTaskAsyncEnumerable.EveryUpdate(PlayerLoopTiming.FixedUpdate)
|
||||
|
||||
|
||||
await UniTask.Yield(PlayerLoopTiming.Update);
|
||||
Debug.Log("Start:" + Time.frameCount);
|
||||
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
||||
{
|
||||
UnityEngine.Debug.Log("Update Trigger 1");
|
||||
}).Forget();
|
||||
|
||||
await UniTaskAsyncEnumerable.TimerFrame(3, 5, PlayerLoopTiming.PostLateUpdate)
|
||||
.Select(x => x)
|
||||
.Do(x => Debug.Log("DODODO"))
|
||||
.ForEachAsync(_ =>
|
||||
{
|
||||
Debug.Log("Call:" + Time.frameCount);
|
||||
}, cancellationToken: this.GetCancellationTokenOnDestroy());
|
||||
|
||||
this.GetAsyncUpdateTrigger().ForEachAsync(_ =>
|
||||
{
|
||||
UnityEngine.Debug.Log("Update Trigger 2");
|
||||
}).Forget();
|
||||
|
||||
//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
|
||||
//{
|
||||
|
|
Loading…
Reference in New Issue