IEnumerator.ToUniTask() behave same as StartCoroutine #120

master
neuecc 2020-08-13 17:44:06 +09:00
parent d5455f3716
commit 38d159b69e
3 changed files with 154 additions and 0 deletions

View File

@ -44,6 +44,7 @@ namespace Cysharp.Threading.Tasks
IEnumerator innerEnumerator;
CancellationToken cancellationToken;
int initialFrame;
UniTaskCompletionSourceCore<object> core;
@ -66,10 +67,13 @@ namespace Cysharp.Threading.Tasks
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
result.cancellationToken = cancellationToken;
result.initialFrame = -1;
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
result.MoveNext(); // run immediately.
return result;
}
@ -108,6 +112,19 @@ namespace Cysharp.Threading.Tasks
return false;
}
if (initialFrame == -1)
{
// Time can not touch in threadpool.
if (PlayerLoopHelper.IsMainThread)
{
initialFrame = Time.frameCount;
}
}
else if (initialFrame == Time.frameCount)
{
return true; // already executed in first frame, skip.
}
try
{
if (innerEnumerator.MoveNext())

View File

@ -0,0 +1,126 @@
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine.UI;
using UnityEngine.Scripting;
using Cysharp.Threading.Tasks;
using Unity.Collections;
using System.Threading;
using NUnit.Framework;
using UnityEngine.TestTools;
using FluentAssertions;
namespace Cysharp.Threading.TasksTests
{
public class CoroutineToUniTaskTest
{
[UnityTest]
public IEnumerator EarlyUpdate() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.EarlyUpdate);
var l = new List<(int, int)>();
var currentFrame = Time.frameCount;
var t = Worker(l).ToUniTask();
l.Count.Should().Be(1);
l[0].Should().Be((0, currentFrame));
await t;
l[1].Should().Be((1, Time.frameCount));
l[1].Item2.Should().NotBe(currentFrame);
});
[UnityTest]
public IEnumerator LateUpdate() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var l = new List<(int, int)>();
var currentFrame = Time.frameCount;
var t = Worker(l).ToUniTask();
l.Count.Should().Be(1);
l[0].Should().Be((0, currentFrame));
await t;
l[1].Should().Be((1, Time.frameCount));
l[1].Item2.Should().NotBe(currentFrame);
});
//[UnityTest]
//public IEnumerator TestCoroutine()
//{
// yield return UniTask.Yield(PlayerLoopTiming.EarlyUpdate).ToUniTask().ToCoroutine();
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
// var l = new List<(int, int)>();
// var currentFrame = Time.frameCount;
// var t = nanika.StartCoroutine(Worker(l));
// l.Count.Should().Be(1);
// l[0].Should().Be((0, currentFrame));
// yield return t;
// l[1].Should().Be((1, Time.frameCount));
// l[1].Item2.Should().NotBe(currentFrame);
//}
//[UnityTest]
//public IEnumerator TestCoroutine2()
//{
// yield return UniTask.Yield(PlayerLoopTiming.PostLateUpdate).ToUniTask().ToCoroutine();
// var nanika = (UnityEngine.MonoBehaviour)GameObject.FindObjectOfType(typeof(UnityEngine.MonoBehaviour));
// var l = new List<(int, int)>();
// var currentFrame = Time.frameCount;
// var t = nanika.StartCoroutine(Worker(l));
// l.Count.Should().Be(1);
// l[0].Should().Be((0, currentFrame));
// yield return t;
// l[1].Should().Be((1, Time.frameCount));
// l[1].Item2.Should().NotBe(currentFrame);
//}
IEnumerator Worker(List<(int, int)> l)
{
l.Add((0, Time.frameCount));
yield return null;
l.Add((1, Time.frameCount));
}
public async UniTask Foo()
{
var tasks = new List<UniTask>();
var t = Bar<int>();
tasks.Add(t);
t = Bar<int>();
tasks.Add(t);
await UniTask.WhenAll(tasks);
}
public async UniTask<T> Bar<T>()
{
await UniTask.Yield();
return default(T);
}
}
}
#endif

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 43ffb719370515746932af3732ce073e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: