UnityAsyncEventHandler as IUniTaskAsyncEnumerable
parent
7fc6c6bd36
commit
bd6906792d
|
@ -51,7 +51,7 @@ namespace NetCoreSandbox
|
||||||
Console.WriteLine(item);
|
Console.WriteLine(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncEnumerable.Range(1,10).FirstAsync(
|
||||||
// AsyncEnumerable.Range(1, 10).GroupBy(x=>x).Select(x=>x.first
|
// AsyncEnumerable.Range(1, 10).GroupBy(x=>x).Select(x=>x.first
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,14 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks.Internal
|
namespace Cysharp.Threading.Tasks.Internal
|
||||||
{
|
{
|
||||||
internal interface IPromisePoolItem
|
// public, allow to user create custom operator with pool.
|
||||||
|
|
||||||
|
public interface IPromisePoolItem
|
||||||
{
|
{
|
||||||
void Reset();
|
void Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class PromisePool<T>
|
public class PromisePool<T>
|
||||||
where T : class, IPromisePoolItem
|
where T : class, IPromisePoolItem
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
|
@ -162,22 +162,25 @@ namespace Cysharp.Threading.Tasks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAsyncClickEventHandler : IDisposable
|
public interface IAsyncClickEventHandler : IDisposable, IUniTaskAsyncEnumerable<AsyncUnit>
|
||||||
{
|
{
|
||||||
UniTask OnClickAsync();
|
UniTask OnClickAsync();
|
||||||
|
IAsyncClickEventHandler DisableAutoClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAsyncValueChangedEventHandler<T> : IDisposable
|
public interface IAsyncValueChangedEventHandler<T> : IDisposable, IUniTaskAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
UniTask<T> OnValueChangedAsync();
|
UniTask<T> OnValueChangedAsync();
|
||||||
|
IAsyncValueChangedEventHandler<T> DisableAutoClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAsyncEndEditEventHandler<T> : IDisposable
|
public interface IAsyncEndEditEventHandler<T> : IDisposable, IUniTaskAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
UniTask<T> OnEndEditAsync();
|
UniTask<T> OnEndEditAsync();
|
||||||
|
IAsyncEndEditEventHandler<T> DisableAutoClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AsyncUnityEventHandler : IUniTaskSource, IDisposable, IAsyncClickEventHandler
|
public class AsyncUnityEventHandler : IUniTaskSource, IDisposable, IAsyncClickEventHandler, IUniTaskAsyncEnumerable<AsyncUnit>
|
||||||
{
|
{
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
@ -222,6 +225,7 @@ namespace Cysharp.Threading.Tasks
|
||||||
|
|
||||||
void Invoke()
|
void Invoke()
|
||||||
{
|
{
|
||||||
|
asyncEnumerator?.SetResult();
|
||||||
core.TrySetResult(AsyncUnit.Default);
|
core.TrySetResult(AsyncUnit.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +234,13 @@ namespace Cysharp.Threading.Tasks
|
||||||
var self = (AsyncUnityEventHandler)state;
|
var self = (AsyncUnityEventHandler)state;
|
||||||
self.Dispose();
|
self.Dispose();
|
||||||
|
|
||||||
|
// call child cancel
|
||||||
|
if (self.asyncEnumerator != null)
|
||||||
|
{
|
||||||
|
self.asyncEnumerator.CancelFromParent(self.cancellationToken);
|
||||||
|
self.asyncEnumerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
self.core.TrySetCanceled(self.cancellationToken);
|
self.core.TrySetCanceled(self.cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,9 +292,118 @@ namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
core.OnCompleted(continuation, state, token);
|
core.OnCompleted(continuation, state, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncEnumerator
|
||||||
|
|
||||||
|
bool disableAutoClose;
|
||||||
|
Enumerator asyncEnumerator;
|
||||||
|
|
||||||
|
public AsyncUnityEventHandler DisableAutoClose()
|
||||||
|
{
|
||||||
|
disableAutoClose = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncClickEventHandler IAsyncClickEventHandler.DisableAutoClose()
|
||||||
|
{
|
||||||
|
disableAutoClose = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IUniTaskAsyncEnumerator<AsyncUnit> IUniTaskAsyncEnumerable<AsyncUnit>.GetAsyncEnumerator(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (this.asyncEnumerator != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Already acquired GetAsyncEnumerator, does not allow get twice before previous enumerator completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.asyncEnumerator = new Enumerator(this, cancellationToken);
|
||||||
|
return asyncEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Enumerator : Cysharp.Threading.Tasks.Linq.MoveNextSource, IUniTaskAsyncEnumerator<AsyncUnit>
|
||||||
|
{
|
||||||
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
AsyncUnityEventHandler parent;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration registration;
|
||||||
|
bool isDisposed;
|
||||||
|
|
||||||
|
public Enumerator(AsyncUnityEventHandler parent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
if (cancellationToken.CanBeCanceled && parent.cancellationToken != cancellationToken)
|
||||||
|
{
|
||||||
|
registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (Enumerator)state;
|
||||||
|
self.DisposeCore(self.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelFromParent(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// call from parent, avoid parent close.
|
||||||
|
parent.disableAutoClose = true;
|
||||||
|
DisposeCore(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetResult()
|
||||||
|
{
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncUnit Current { get; private set; }
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
DisposeCore(CancellationToken.None);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisposeCore(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!isDisposed)
|
||||||
|
{
|
||||||
|
isDisposed = true;
|
||||||
|
registration.Dispose();
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
|
||||||
|
if (!parent.disableAutoClose)
|
||||||
|
{
|
||||||
|
parent.Dispose(); // dispose parent.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.asyncEnumerator == this)
|
||||||
|
{
|
||||||
|
parent.asyncEnumerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
completionSource.TrySetCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AsyncUnityEventHandler<T> : IUniTaskSource<T>, IDisposable, IAsyncValueChangedEventHandler<T>, IAsyncEndEditEventHandler<T>
|
public class AsyncUnityEventHandler<T> : IUniTaskSource<T>, IDisposable, IAsyncValueChangedEventHandler<T>, IAsyncEndEditEventHandler<T>, IUniTaskAsyncEnumerable<T>
|
||||||
{
|
{
|
||||||
static Action<object> cancellationCallback = CancellationCallback;
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
@ -328,6 +448,7 @@ namespace Cysharp.Threading.Tasks
|
||||||
|
|
||||||
void Invoke(T result)
|
void Invoke(T result)
|
||||||
{
|
{
|
||||||
|
asyncEnumerator?.SetResult(result);
|
||||||
core.TrySetResult(result);
|
core.TrySetResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,6 +457,13 @@ namespace Cysharp.Threading.Tasks
|
||||||
var self = (AsyncUnityEventHandler<T>)state;
|
var self = (AsyncUnityEventHandler<T>)state;
|
||||||
self.Dispose();
|
self.Dispose();
|
||||||
|
|
||||||
|
// call child cancel
|
||||||
|
if (self.asyncEnumerator != null)
|
||||||
|
{
|
||||||
|
self.asyncEnumerator.CancelFromParent(self.cancellationToken);
|
||||||
|
self.asyncEnumerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
self.core.TrySetCanceled(self.cancellationToken);
|
self.core.TrySetCanceled(self.cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,6 +478,13 @@ namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
unityEvent.RemoveListener(action);
|
unityEvent.RemoveListener(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asyncEnumerator?.DisposeAsync().Forget();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
core.TrySetCanceled();
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,5 +532,121 @@ namespace Cysharp.Threading.Tasks
|
||||||
{
|
{
|
||||||
core.OnCompleted(continuation, state, token);
|
core.OnCompleted(continuation, state, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AsyncEnumerator
|
||||||
|
|
||||||
|
bool disableAutoClose;
|
||||||
|
Enumerator asyncEnumerator;
|
||||||
|
|
||||||
|
public AsyncUnityEventHandler<T> DisableAutoClose()
|
||||||
|
{
|
||||||
|
disableAutoClose = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncValueChangedEventHandler<T> IAsyncValueChangedEventHandler<T>.DisableAutoClose()
|
||||||
|
{
|
||||||
|
disableAutoClose = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAsyncEndEditEventHandler<T> IAsyncEndEditEventHandler<T>.DisableAutoClose()
|
||||||
|
{
|
||||||
|
disableAutoClose = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
IUniTaskAsyncEnumerator<T> IUniTaskAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (this.asyncEnumerator != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Already acquired GetAsyncEnumerator, does not allow get twice before previous enumerator completed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.asyncEnumerator = new Enumerator(this, cancellationToken);
|
||||||
|
return asyncEnumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Enumerator : Cysharp.Threading.Tasks.Linq.MoveNextSource, IUniTaskAsyncEnumerator<T>
|
||||||
|
{
|
||||||
|
static Action<object> cancellationCallback = CancellationCallback;
|
||||||
|
|
||||||
|
AsyncUnityEventHandler<T> parent;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
CancellationTokenRegistration registration;
|
||||||
|
bool isDisposed;
|
||||||
|
|
||||||
|
public Enumerator(AsyncUnityEventHandler<T> parent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
|
||||||
|
if (cancellationToken.CanBeCanceled && parent.cancellationToken != cancellationToken)
|
||||||
|
{
|
||||||
|
registration = cancellationToken.RegisterWithoutCaptureExecutionContext(cancellationCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(this, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CancellationCallback(object state)
|
||||||
|
{
|
||||||
|
var self = (Enumerator)state;
|
||||||
|
self.DisposeCore(self.cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelFromParent(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// call from parent, avoid parent close.
|
||||||
|
parent.disableAutoClose = true;
|
||||||
|
DisposeCore(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetResult(T result)
|
||||||
|
{
|
||||||
|
Current = result;
|
||||||
|
completionSource.TrySetResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Current { get; private set; }
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
completionSource.Reset();
|
||||||
|
return new UniTask<bool>(this, completionSource.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
DisposeCore(CancellationToken.None);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisposeCore(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!isDisposed)
|
||||||
|
{
|
||||||
|
isDisposed = true;
|
||||||
|
registration.Dispose();
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
|
||||||
|
if (!parent.disableAutoClose)
|
||||||
|
{
|
||||||
|
parent.Dispose(); // dispose parent.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.asyncEnumerator == this)
|
||||||
|
{
|
||||||
|
parent.asyncEnumerator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
completionSource.TrySetCanceled(cancellationToken);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
using Cysharp.Threading.Tasks.Triggers;
|
using Cysharp.Threading.Tasks.Triggers;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -12,7 +13,6 @@ using Unity.Jobs;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Networking;
|
using UnityEngine.Networking;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Cysharp.Threading.Tasks.Linq;
|
|
||||||
|
|
||||||
public struct MyJob : IJob
|
public struct MyJob : IJob
|
||||||
{
|
{
|
||||||
|
@ -105,16 +105,16 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start()
|
async void Start()
|
||||||
{
|
{
|
||||||
Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.Full);
|
Application.SetStackTraceLogType(LogType.Error, StackTraceLogType.Full);
|
||||||
Application.SetStackTraceLogType(LogType.Exception, StackTraceLogType.Full);
|
Application.SetStackTraceLogType(LogType.Exception, StackTraceLogType.Full);
|
||||||
|
|
||||||
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
var playerLoop = UnityEngine.LowLevel.PlayerLoop.GetCurrentPlayerLoop();
|
||||||
ShowPlayerLoop.DumpPlayerLoop("Current", playerLoop);
|
//ShowPlayerLoop.DumpPlayerLoop("Current", playerLoop);
|
||||||
|
|
||||||
|
|
||||||
Update2().Forget();
|
//Update2().Forget();
|
||||||
|
|
||||||
//RunStandardDelayAsync().Forget();
|
//RunStandardDelayAsync().Forget();
|
||||||
|
|
||||||
|
@ -144,7 +144,6 @@ public class SandboxMain : MonoBehaviour
|
||||||
|
|
||||||
//StartCoroutine(cor);
|
//StartCoroutine(cor);
|
||||||
|
|
||||||
Debug.Log(EqualityComparer<MyEnum>.Default.GetType().FullName);
|
|
||||||
|
|
||||||
|
|
||||||
//this.TryGetComponent(
|
//this.TryGetComponent(
|
||||||
|
@ -163,12 +162,36 @@ public class SandboxMain : MonoBehaviour
|
||||||
Application.logMessageReceived += Application_logMessageReceived;
|
Application.logMessageReceived += Application_logMessageReceived;
|
||||||
|
|
||||||
|
|
||||||
UniTask<int> foo = UniTask.FromResult(10);
|
|
||||||
// foo.Status.IsCanceled
|
// foo.Status.IsCanceled
|
||||||
|
|
||||||
|
|
||||||
|
// 5回クリックされるまで待つ、とか。
|
||||||
|
Debug.Log("Await start.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
await okButton.GetAsyncClickEventHandler().DisableAutoClose()
|
||||||
|
.Select((_, clickCount) => clickCount + 1)
|
||||||
|
.FirstAsync(x => x == 5);
|
||||||
|
|
||||||
|
Debug.Log("Click 5 times.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Foo(foo);
|
|
||||||
|
|
||||||
//ucs = new UniTaskCompletionSource();
|
//ucs = new UniTaskCompletionSource();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue