Compare commits

...

24 Commits

Author SHA1 Message Date
neuecc
d6a0563319 ready 2.0.19 2020-06-18 03:39:44 +09:00
neuecc
af82a94b87 Fix TimeoutWithoutException does not suppress exception 2020-06-18 03:30:53 +09:00
neuecc
82219e6111 Fix UniTask.Delay does not run on threadpool thread 2020-06-18 03:28:03 +09:00
neuecc
81f9c55c7f Add UniTask.Run(Func<UniTask>) overload 2020-06-18 03:27:26 +09:00
neuecc
0640f278cc Fix AsyncLazy can not await multiple times when task is not completed 2020-06-18 03:02:01 +09:00
neuecc
769b5c6bab UniTaskCompletionSource can await multiple times(same behaviour as TaskCompletionSource) 2020-06-18 02:34:56 +09:00
neuecc
bdd569e213 fix can not close application in mono build 2020-06-17 21:37:45 +09:00
neuecc
5bfff5bc24 Subscribe ReadMe 2020-06-15 22:46:01 +09:00
neuecc
edf32496e4 re 2020-06-15 15:29:12 +09:00
neuecc
785f5837d1 Merge remote-tracking branch 'origin/master' 2020-06-15 15:28:29 +09:00
neuecc
8c9272bc9f 2.0.18 2020-06-15 15:26:28 +09:00
neuecc
3e00735b3d Add AsUniTaskAsyncEnumerable/AsAsyncEnumerable in .NET Core 2020-06-15 15:23:25 +09:00
neuecc
00a1be8666 await UnityWebRequestAsyncOperation throws UnityWebRequestException when isHttpError or isNetworkError 2020-06-15 15:23:07 +09:00
neuecc
a2783d3c8a yes meta 2020-06-15 12:29:46 +09:00
Yoshifumi Kawai
85d1a8a4a4 Update README.md 2020-06-14 15:44:40 +09:00
neuecc
bbfb8354bb 2.0.17 2020-06-14 15:32:37 +09:00
Yoshifumi Kawai
2f68e47443 Merge pull request #92 from yashihei/fix-cancellation-token
Fixed CancelationToken not being passed correctly
2020-06-14 15:08:37 +09:00
yashihei
89339ffb29 Fixed CancelationToken not being passed correctly 2020-06-14 08:24:25 +09:00
neuecc
0535862fe6 Merge remote-tracking branch 'origin/master' 2020-06-13 18:58:56 +09:00
neuecc
a9e5fd4589 Add UniTaskAsyncEnumerable.Subscribe 2020-06-13 18:58:43 +09:00
Yoshifumi Kawai
a3f3a28ea1 Update README.md 2020-06-12 17:18:31 +09:00
Yoshifumi Kawai
59020df965 Update README.md 2020-06-12 17:18:22 +09:00
Yoshifumi Kawai
ac01be79bf Update README.md 2020-06-12 16:59:14 +09:00
neuecc
de5951f208 lock q 2020-06-12 10:46:29 +09:00
39 changed files with 2389 additions and 1007 deletions

View File

@@ -2,7 +2,7 @@ UniTask
===
[![GitHub Actions](https://github.com/Cysharp/UniTask/workflows/Build-Debug/badge.svg)](https://github.com/Cysharp/UniTask/actions) [![Releases](https://img.shields.io/github/release/Cysharp/UniTask.svg)](https://github.com/Cysharp/UniTask/releases)
Provides an efficient async/await integration to Unity.
Provides an efficient allocation free async/await integration to Unity.
* Struct based `UniTask<T>` and custom AsyncMethodBuilder to achive zero allocation
* All Unity AsyncOperations and Coroutine to awaitable
@@ -13,6 +13,9 @@ Provides an efficient async/await integration to Unity.
* TaskTracker window to prevent memory leak
* Highly compatible behaviour with Task/ValueTask/IValueTaskSource
Techinical details, see blog post: [UniTask v2 — Zero Allocation async/await for Unity, with Asynchronous LINQ
](https://medium.com/@neuecc/unitask-v2-zero-allocation-async-await-for-unity-with-asynchronous-linq-1aa9c96aa7dd)
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Table of Contents
@@ -491,11 +494,19 @@ await okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).ForEachAsy
});
```
Fire and Forget style(for example, event handling), also you can use `Subscribe`.
```csharp
okButton.OnClickAsAsyncEnumerable().Where((x, i) => i % 2 == 0).Subscribe(_ =>
{
});
```
Async LINQ is enabled when `using Cysharp.Threading.Tasks.Linq;`, and `UniTaskAsyncEnumerable` is defined in `UniTask.Linq` asmdef.
It's closer to UniRx (Reactive Extensions), but UniTaskAsyncEnumerable is a pull-based asynchronous stream, whereas Rx was a push-based asynchronous stream. Note that although similar, the characteristics are different and the details behave differently along with them.
`UniTaskAsyncEnumerable` is the entry point like `Enumerbale`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`.
`UniTaskAsyncEnumerable` is the entry point like `Enumerbale`. In addition to the standard query operators, there are other generators for Unity such as `EveryUpdate`, `Timer`, `TimerFrame`, `Interval`, `IntervalFrame`, and `EveryValueChanged`. And also added additional UniTask original query operators like `Append`, `Prepend`, `DistinctUntilChanged`, `ToHashSet`, `Buffer`, `CombineLatest`, `Do`, `Never`, `ForEachAsync`, `Pairwise`, `Publish`, `Queue`, `Return`, `SkipUntilCanceled`, `TakeUntilCanceled`, `TakeLast`, `Subscribe`.
The method with Func as an argument has three additional overloads, `***Await`, `***AwaitWithCancellation`.
@@ -613,10 +624,10 @@ A pull-type asynchronous stream does not get the next values until the asynchron
```csharp
// can not get click event during 3 seconds complete.
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync()
await button.OnClickAsAsyncEnumerable().ForEachAwaitAsync(async x =>
{
await UniTask.Delay(TimeSpan.FromSeconds(3));
}
});
```
It is useful(prevent double-click) but not useful in sometimes.
@@ -625,10 +636,19 @@ Using `Queue()` method, which will also queue events during asynchronous process
```csharp
// queued message in asynchronous processing
await button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync()
await button.OnClickAsAsyncEnumerable().Queue().ForEachAwaitAsync(async x =>
{
await UniTask.Delay(TimeSpan.FromSeconds(3));
}
});
```
Or use `Subscribe`, fire and forget style.
```csharp
button.OnClickAsAsyncEnumerable().Subscribe(async x =>
{
await UniTask.Delay(TimeSpan.FromSeconds(3));
});
```
Channel
@@ -778,7 +798,7 @@ After Unity 2019.3.4f1, Unity 2020.1a21, that support path query parameter of gi
or add `"com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask"` to `Packages/manifest.json`.
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.15`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.15`.
If you want to set a target version, UniTask is using `*.*.*` release tag so you can specify a version like `#2.0.19`. For example `https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.0.19`.
### Install via OpenUPM

View File

@@ -0,0 +1,101 @@
#if !NETSTANDARD2_0
#pragma warning disable 0649
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Sources;
namespace Cysharp.Threading.Tasks
{
public static class AsyncEnumerableExtensions
{
public static IUniTaskAsyncEnumerable<T> AsUniTaskAsyncEnumerable<T>(this IAsyncEnumerable<T> source)
{
return new AsyncEnumerableToUniTaskAsyncEnumerable<T>(source);
}
public static IAsyncEnumerable<T> AsAsyncEnumerable<T>(this IUniTaskAsyncEnumerable<T> source)
{
return new UniTaskAsyncEnumerableToAsyncEnumerable<T>(source);
}
sealed class AsyncEnumerableToUniTaskAsyncEnumerable<T> : IUniTaskAsyncEnumerable<T>
{
readonly IAsyncEnumerable<T> source;
public AsyncEnumerableToUniTaskAsyncEnumerable(IAsyncEnumerable<T> source)
{
this.source = source;
}
public IUniTaskAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
}
sealed class Enumerator : IUniTaskAsyncEnumerator<T>
{
readonly IAsyncEnumerator<T> enumerator;
public Enumerator(IAsyncEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public T Current => enumerator.Current;
public async UniTask DisposeAsync()
{
await enumerator.DisposeAsync();
}
public async UniTask<bool> MoveNextAsync()
{
return await enumerator.MoveNextAsync();
}
}
}
sealed class UniTaskAsyncEnumerableToAsyncEnumerable<T> : IAsyncEnumerable<T>
{
readonly IUniTaskAsyncEnumerable<T> source;
public UniTaskAsyncEnumerableToAsyncEnumerable(IUniTaskAsyncEnumerable<T> source)
{
this.source = source;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new Enumerator(source.GetAsyncEnumerator(cancellationToken));
}
sealed class Enumerator : IAsyncEnumerator<T>
{
readonly IUniTaskAsyncEnumerator<T> enumerator;
public Enumerator(IUniTaskAsyncEnumerator<T> enumerator)
{
this.enumerator = enumerator;
}
public T Current => enumerator.Current;
public ValueTask DisposeAsync()
{
return enumerator.DisposeAsync();
}
public ValueTask<bool> MoveNextAsync()
{
return enumerator.MoveNextAsync();
}
}
}
}
}
#endif

View File

@@ -26,15 +26,14 @@ namespace Cysharp.Threading.Tasks
#endif
}
public static UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true)
public static async UniTask<T> AsUniTask<T>(this ValueTask<T> task)
{
// NOTE: get _obj and _token directly for low overhead conversion but not yet implemented.
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
return await task;
}
public static UniTask AsUniTask(this ValueTask task, bool useCurrentSynchronizationContext = true)
public static async UniTask AsUniTask(this ValueTask task)
{
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
await task;
}
#if NETSTANDARD2_0

View File

@@ -0,0 +1,167 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using Cysharp.Threading.Tasks.Linq;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class AsyncLazyTest
{
[Fact]
public async Task LazyLazy()
{
{
var l = UniTask.Lazy(() => After());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await a;
await b;
await c;
}
{
var l = UniTask.Lazy(() => AfterException());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
[Fact]
public async Task LazyImmediate()
{
{
var l = UniTask.Lazy(() => UniTask.FromResult(1).AsUniTask());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await a;
await b;
await c;
}
{
var l = UniTask.Lazy(() => UniTask.FromException(new TaskTestException()));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
static async UniTask AwaitAwait(UniTask t)
{
await t;
}
async UniTask After()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
await UniTask.Yield();
}
async UniTask AfterException()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
throw new TaskTestException();
}
}
public class AsyncLazyTest2
{
[Fact]
public async Task LazyLazy()
{
{
var l = UniTask.Lazy(() => After());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
var a2 = await a;
var b2 = await b;
var c2 = await c;
(a2, b2, c2).Should().Be((10, 10, 10));
}
{
var l = UniTask.Lazy(() => AfterException());
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
[Fact]
public async Task LazyImmediate()
{
{
var l = UniTask.Lazy(() => UniTask.FromResult(1));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
var a2 = await a;
var b2 = await b;
var c2 = await c;
(a2, b2, c2).Should().Be((1, 1, 1));
}
{
var l = UniTask.Lazy(() => UniTask.FromException<int>(new TaskTestException()));
var a = AwaitAwait(l.Task);
var b = AwaitAwait(l.Task);
var c = AwaitAwait(l.Task);
await Assert.ThrowsAsync<TaskTestException>(async () => await a);
await Assert.ThrowsAsync<TaskTestException>(async () => await b);
await Assert.ThrowsAsync<TaskTestException>(async () => await c);
}
}
static async UniTask<int> AwaitAwait(UniTask<int> t)
{
return await t;
}
async UniTask<int> After()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
await UniTask.Yield();
return 10;
}
async UniTask<int> AfterException()
{
await UniTask.Yield();
Thread.Sleep(TimeSpan.FromSeconds(1));
await UniTask.Yield();
throw new TaskTestException();
}
}
}

View File

@@ -0,0 +1,590 @@
using Cysharp.Threading.Tasks;
using FluentAssertions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using Cysharp.Threading.Tasks.Linq;
using System.Threading.Tasks;
using Xunit;
namespace NetCoreTests
{
public class CompletionSourceTest
{
[Fact]
public async Task SetFirst()
{
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetResult();
await tcs.Task; // ok.
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task SingleOnFirst()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetResult();
await a;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiOne()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetResult();
await a;
await b;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiTwo()
{
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetResult();
await a;
await b;
await c;
await tcs.Task; // ok.
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await c);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource();
async UniTask Await()
{
await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
class TestException : Exception
{
}
}
public class CompletionSourceTest2
{
[Fact]
public async Task SetFirst()
{
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetResult(10);
var a = await tcs.Task; // ok.
var b = await tcs.Task; // ok.
a.Should().Be(10);
b.Should().Be(10);
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task SingleOnFirst()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await tcs.Task; // ok.
r1.Should().Be(10);
r2.Should().Be(10);
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiOne()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await b;
var r3 = await tcs.Task; // ok.
(r1, r2, r3).Should().Be((10, 10, 10));
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
[Fact]
public async Task MultiTwo()
{
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetResult(10);
var r1 = await a;
var r2 = await b;
var r3 = await c;
var r4 = await tcs.Task; // ok.
(r1, r2, r3, r4).Should().Be((10, 10, 10, 10));
tcs.Task.Status.Should().Be(UniTaskStatus.Succeeded);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new TestException());
await Assert.ThrowsAsync<TestException>(async () => await a);
await Assert.ThrowsAsync<TestException>(async () => await b);
await Assert.ThrowsAsync<TestException>(async () => await c);
await Assert.ThrowsAsync<TestException>(async () => await tcs.Task);
tcs.Task.Status.Should().Be(UniTaskStatus.Faulted);
}
var cts = new CancellationTokenSource();
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetException(new OperationCanceledException(cts.Token));
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
{
var tcs = new UniTaskCompletionSource<int>();
async UniTask<int> Await()
{
return await tcs.Task;
}
var a = Await();
var b = Await();
var c = Await();
tcs.TrySetCanceled(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await a)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await b)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await c)).CancellationToken.Should().Be(cts.Token);
(await Assert.ThrowsAsync<OperationCanceledException>(async () => await tcs.Task)).CancellationToken.Should().Be(cts.Token);
tcs.Task.Status.Should().Be(UniTaskStatus.Canceled);
}
}
class TestException : Exception
{
}
}
}

View File

@@ -7,113 +7,239 @@ namespace Cysharp.Threading.Tasks
{
public class AsyncLazy
{
Func<UniTask> valueFactory;
UniTask target;
static Action<object> continuation = SetCompletionSource;
Func<UniTask> taskFactory;
UniTaskCompletionSource completionSource;
UniTask.Awaiter awaiter;
object syncLock;
bool initialized;
public AsyncLazy(Func<UniTask> valueFactory)
public AsyncLazy(Func<UniTask> taskFactory)
{
this.valueFactory = valueFactory;
this.target = default;
this.taskFactory = taskFactory;
this.completionSource = new UniTaskCompletionSource();
this.syncLock = new object();
this.initialized = false;
}
internal AsyncLazy(UniTask value)
internal AsyncLazy(UniTask task)
{
this.valueFactory = null;
this.target = value;
this.taskFactory = null;
this.completionSource = new UniTaskCompletionSource();
this.syncLock = null;
this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
}
public UniTask Task => EnsureInitialized();
public UniTask Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
UniTask EnsureInitialized()
public UniTask.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{
if (Volatile.Read(ref initialized))
{
return target;
return;
}
return EnsureInitializedCore();
EnsureInitializedCore();
}
UniTask EnsureInitializedCore()
void EnsureInitializedCore()
{
lock (syncLock)
{
if (!Volatile.Read(ref initialized))
{
var f = Interlocked.Exchange(ref valueFactory, null);
var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null)
{
target = f().Preserve(); // with preserve(allow multiple await).
var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true);
}
}
}
}
return target;
void SetCompletionSource(in UniTask.Awaiter awaiter)
{
try
{
awaiter.GetResult();
completionSource.TrySetResult();
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy)state;
try
{
self.awaiter.GetResult();
self.completionSource.TrySetResult();
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
}
}
public class AsyncLazy<T>
{
Func<UniTask<T>> valueFactory;
UniTask<T> target;
static Action<object> continuation = SetCompletionSource;
Func<UniTask<T>> taskFactory;
UniTaskCompletionSource<T> completionSource;
UniTask<T>.Awaiter awaiter;
object syncLock;
bool initialized;
public AsyncLazy(Func<UniTask<T>> valueFactory)
public AsyncLazy(Func<UniTask<T>> taskFactory)
{
this.valueFactory = valueFactory;
this.target = default;
this.taskFactory = taskFactory;
this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = new object();
this.initialized = false;
}
internal AsyncLazy(UniTask<T> value)
internal AsyncLazy(UniTask<T> task)
{
this.valueFactory = null;
this.target = value;
this.taskFactory = null;
this.completionSource = new UniTaskCompletionSource<T>();
this.syncLock = null;
this.initialized = true;
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
}
public UniTask<T> Task => EnsureInitialized();
public UniTask<T> Task
{
get
{
EnsureInitialized();
return completionSource.Task;
}
}
public UniTask<T>.Awaiter GetAwaiter() => EnsureInitialized().GetAwaiter();
UniTask<T> EnsureInitialized()
public UniTask<T>.Awaiter GetAwaiter() => Task.GetAwaiter();
void EnsureInitialized()
{
if (Volatile.Read(ref initialized))
{
return target;
return;
}
return EnsureInitializedCore();
EnsureInitializedCore();
}
UniTask<T> EnsureInitializedCore()
void EnsureInitializedCore()
{
lock (syncLock)
{
if (!Volatile.Read(ref initialized))
{
var f = Interlocked.Exchange(ref valueFactory, null);
var f = Interlocked.Exchange(ref taskFactory, null);
if (f != null)
{
target = f().Preserve(); // with preserve(allow multiple await).
var task = f();
var awaiter = task.GetAwaiter();
if (awaiter.IsCompleted)
{
SetCompletionSource(awaiter);
}
else
{
this.awaiter = awaiter;
awaiter.SourceOnCompleted(continuation, this);
}
Volatile.Write(ref initialized, true);
}
}
}
}
return target;
void SetCompletionSource(in UniTask<T>.Awaiter awaiter)
{
try
{
var result = awaiter.GetResult();
completionSource.TrySetResult(result);
}
catch (Exception ex)
{
completionSource.TrySetException(ex);
}
}
static void SetCompletionSource(object state)
{
var self = (AsyncLazy<T>)state;
try
{
var result = self.awaiter.GetResult();
self.completionSource.TrySetResult(result);
}
catch (Exception ex)
{
self.completionSource.TrySetException(ex);
}
finally
{
self.awaiter = default;
}
}
}
}

View File

@@ -143,14 +143,6 @@ namespace Cysharp.Threading.Tasks
return pool.TryPush(this);
}
~WaitAsyncSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;
@@ -468,14 +460,6 @@ namespace Cysharp.Threading.Tasks
return pool.TryPush(this);
}
~WaitAsyncSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
static void CancellationCallback(object state)
{
var self = (WaitAsyncSource)state;

View File

@@ -239,14 +239,6 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
core.OnCompleted(continuation, state, token);
}
~AsyncUniTask()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
internal sealed class AsyncUniTask<TStateMachine, T> : IStateMachineRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
@@ -376,14 +368,6 @@ namespace Cysharp.Threading.Tasks.CompilerServices
{
core.OnCompleted(continuation, state, token);
}
~AsyncUniTask()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
}

View File

@@ -134,14 +134,6 @@ namespace Cysharp.Threading.Tasks
return pool.TryPush(this);
}
~EnumeratorPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
// Unwrap YieldInstructions
static IEnumerator ConsumeEnumerator(IEnumerator enumerator)

View File

@@ -193,14 +193,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
@@ -314,14 +306,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion
@@ -512,14 +496,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
@@ -637,14 +613,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationHandleConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion

View File

@@ -278,14 +278,6 @@ namespace Cysharp.Threading.Tasks
originalUpdateAction = default;
return pool.TryPush(this);
}
~TweenConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
}

View File

@@ -0,0 +1,313 @@
using Cysharp.Threading.Tasks.Internal;
using System;
using System.Threading;
using Subscribes = Cysharp.Threading.Tasks.Linq.Subscribe;
namespace Cysharp.Threading.Tasks.Linq
{
public static partial class UniTaskAsyncEnumerable
{
// OnNext
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> action, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(action, nameof(action));
Subscribes.SubscribeCore(source, action, Subscribes.NopError, Subscribes.NopCompleted, cancellationToken).Forget();
}
// OnNext, OnError
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onError, nameof(onError));
Subscribes.SubscribeCore(source, onNext, onError, Subscribes.NopCompleted, cancellationToken).Forget();
}
// OnNext, OnCompleted
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
return cts;
}
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action onCompleted, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action onCompleted, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(onNext, nameof(onNext));
Error.ThrowArgumentNullException(onCompleted, nameof(onCompleted));
Subscribes.SubscribeCore(source, onNext, Subscribes.NopError, onCompleted, cancellationToken).Forget();
}
// IObserver
public static IDisposable Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(observer, nameof(observer));
var cts = new CancellationTokenDisposable();
Subscribes.SubscribeCore(source, observer, cts.Token).Forget();
return cts;
}
public static void Subscribe<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
{
Error.ThrowArgumentNullException(source, nameof(source));
Error.ThrowArgumentNullException(observer, nameof(observer));
Subscribes.SubscribeCore(source, observer, cancellationToken).Forget();
}
}
internal sealed class CancellationTokenDisposable : IDisposable
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
public CancellationToken Token => cts.Token;
public void Dispose()
{
if (!cts.IsCancellationRequested)
{
cts.Cancel();
}
}
}
internal static class Subscribe
{
public static readonly Action<Exception> NopError = _ => { };
public static readonly Action NopCompleted = () => { };
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Action<TSource> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
onNext(e.Current);
}
onCompleted();
}
catch (Exception ex)
{
if (onError == NopError)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
return;
}
if (ex is OperationCanceledException) return;
onError(ex);
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
onNext(e.Current).Forget();
}
onCompleted();
}
catch (Exception ex)
{
if (onError == NopError)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
return;
}
if (ex is OperationCanceledException) return;
onError(ex);
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTaskVoid> onNext, Action<Exception> onError, Action onCompleted, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
onNext(e.Current, cancellationToken).Forget();
}
onCompleted();
}
catch (Exception ex)
{
if (onError == NopError)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
return;
}
if (ex is OperationCanceledException) return;
onError(ex);
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
public static async UniTaskVoid SubscribeCore<TSource>(IUniTaskAsyncEnumerable<TSource> source, IObserver<TSource> observer, CancellationToken cancellationToken)
{
var e = source.GetAsyncEnumerator(cancellationToken);
try
{
while (await e.MoveNextAsync())
{
observer.OnNext(e.Current);
}
observer.OnCompleted();
}
catch (Exception ex)
{
if (ex is OperationCanceledException) return;
observer.OnError(ex);
}
finally
{
if (e != null)
{
await e.DisposeAsync();
}
}
}
}
}

View File

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

View File

@@ -248,15 +248,18 @@ namespace Cysharp.Threading.Tasks.Linq
return current;
}
if (queuedResult.Count != 0)
lock (queuedResult)
{
current = queuedResult.Dequeue();
useCachedCurrent = true;
return current;
}
else
{
return default; // undefined.
if (queuedResult.Count != 0)
{
current = queuedResult.Dequeue();
useCachedCurrent = true;
return current;
}
else
{
return default; // undefined.
}
}
}
}

View File

@@ -34,6 +34,7 @@ namespace Cysharp.Threading.Tasks.Linq
public _EveryUpdate(PlayerLoopTiming updateTiming, CancellationToken cancellationToken)
{
this.updateTiming = updateTiming;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);

View File

@@ -100,10 +100,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (this.period <= 0) this.period = 1;
}
this.initialFrame = Time.frameCount;
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
this.dueTimePhase = true;
this.updateTiming = updateTiming;
this.ignoreTimeScale = ignoreTimeScale;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);
}
@@ -219,10 +220,11 @@ namespace Cysharp.Threading.Tasks.Linq
if (periodFrameCount <= 0) periodFrameCount = 1;
}
this.initialFrame = Time.frameCount;
this.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
this.dueTimePhase = true;
this.dueTimeFrameCount = dueTimeFrameCount;
this.periodFrameCount = periodFrameCount;
this.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(this, 2);
PlayerLoopHelper.AddAction(updateTiming, this);

View File

@@ -94,6 +94,8 @@ namespace Cysharp.Threading.Tasks
public static int MainThreadId => mainThreadId;
internal static string ApplicationDataPath => applicationDataPath;
public static bool IsMainThread => Thread.CurrentThread.ManagedThreadId == mainThreadId;
static int mainThreadId;
static string applicationDataPath;
static SynchronizationContext unitySynchronizationContetext;

View File

@@ -1,6 +1,7 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using UnityEngine;
@@ -181,14 +182,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~YieldPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class NextFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<NextFramePromise>
@@ -221,7 +214,7 @@ namespace Cysharp.Threading.Tasks
result = new NextFramePromise();
}
result.frameCount = Time.frameCount;
result.frameCount = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
@@ -283,14 +276,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~NextFramePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
@@ -328,7 +313,7 @@ namespace Cysharp.Threading.Tasks
result.delayFrameCount = delayFrameCount;
result.cancellationToken = cancellationToken;
result.initialFrame = Time.frameCount;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
TaskTracker.TrackActiveTask(result, 3);
@@ -406,14 +391,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~DelayFramePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
@@ -452,7 +429,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.cancellationToken = cancellationToken;
result.initialFrame = Time.frameCount;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
TaskTracker.TrackActiveTask(result, 3);
@@ -524,14 +501,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~DelayPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
@@ -569,7 +538,7 @@ namespace Cysharp.Threading.Tasks
result.elapsed = 0.0f;
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
result.initialFrame = Time.frameCount;
result.initialFrame = PlayerLoopHelper.IsMainThread ? Time.frameCount : -1;
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
@@ -642,14 +611,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~DelayIgnoreTimeScalePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
}

View File

@@ -11,10 +11,7 @@ namespace Cysharp.Threading.Tasks
{
static readonly UniTask CanceledUniTask = new Func<UniTask>(() =>
{
var promise = new UniTaskCompletionSource();
promise.TrySetCanceled(CancellationToken.None);
promise.MarkHandled();
return promise.Task;
return new UniTask(new CanceledResultSource(CancellationToken.None), 0);
})();
static class CanceledUniTaskCache<T>
@@ -23,10 +20,7 @@ namespace Cysharp.Threading.Tasks
static CanceledUniTaskCache()
{
var promise = new UniTaskCompletionSource<T>();
promise.TrySetCanceled(CancellationToken.None);
promise.MarkHandled();
Task = promise.Task;
Task = new UniTask<T>(new CanceledResultSource<T>(CancellationToken.None), 0);
}
}
@@ -34,18 +28,22 @@ namespace Cysharp.Threading.Tasks
public static UniTask FromException(Exception ex)
{
var promise = new UniTaskCompletionSource();
promise.TrySetException(ex);
promise.MarkHandled();
return promise.Task;
if (ex is OperationCanceledException oce)
{
return FromCanceled(oce.CancellationToken);
}
return new UniTask(new ExceptionResultSource(ex), 0);
}
public static UniTask<T> FromException<T>(Exception ex)
{
var promise = new UniTaskCompletionSource<T>();
promise.TrySetException(ex);
promise.MarkHandled();
return promise.Task;
if (ex is OperationCanceledException oce)
{
return FromCanceled<T>(oce.CancellationToken);
}
return new UniTask<T>(new ExceptionResultSource<T>(ex), 0);
}
public static UniTask<T> FromResult<T>(T value)
@@ -61,10 +59,7 @@ namespace Cysharp.Threading.Tasks
}
else
{
var promise = new UniTaskCompletionSource();
promise.TrySetCanceled(cancellationToken);
promise.MarkHandled();
return promise.Task;
return new UniTask(new CanceledResultSource(cancellationToken), 0);
}
}
@@ -76,10 +71,7 @@ namespace Cysharp.Threading.Tasks
}
else
{
var promise = new UniTaskCompletionSource<T>();
promise.TrySetCanceled(cancellationToken);
promise.MarkHandled();
return promise.Task;
return new UniTask<T>(new CanceledResultSource<T>(cancellationToken), 0);
}
}
@@ -182,6 +174,136 @@ namespace Cysharp.Threading.Tasks
return new UniTask<T>(new DeferPromise<T>(factory), 0);
}
sealed class ExceptionResultSource : IUniTaskSource
{
readonly Exception exception;
public ExceptionResultSource(Exception exception)
{
this.exception = exception;
}
public void GetResult(short token)
{
throw exception;
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Faulted;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Faulted;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class ExceptionResultSource<T> : IUniTaskSource<T>
{
readonly Exception exception;
public ExceptionResultSource(Exception exception)
{
this.exception = exception;
}
public T GetResult(short token)
{
throw exception;
}
void IUniTaskSource.GetResult(short token)
{
throw exception;
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Faulted;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Faulted;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class CanceledResultSource : IUniTaskSource
{
readonly CancellationToken cancellationToken;
public CanceledResultSource(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public void GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Canceled;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Canceled;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class CanceledResultSource<T> : IUniTaskSource<T>
{
readonly CancellationToken cancellationToken;
public CanceledResultSource(CancellationToken cancellationToken)
{
this.cancellationToken = cancellationToken;
}
public T GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
void IUniTaskSource.GetResult(short token)
{
throw new OperationCanceledException(cancellationToken);
}
public UniTaskStatus GetStatus(short token)
{
return UniTaskStatus.Canceled;
}
public UniTaskStatus UnsafeGetStatus()
{
return UniTaskStatus.Canceled;
}
public void OnCompleted(Action<object> continuation, object state, short token)
{
continuation(state);
}
}
sealed class DeferPromise : IUniTaskSource
{
Func<UniTask> factory;

View File

@@ -50,6 +50,50 @@ namespace Cysharp.Threading.Tasks
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask Run(Func<UniTask> action, bool configureAwait = true)
{
await UniTask.SwitchToThreadPool();
if (configureAwait)
{
try
{
await action();
}
finally
{
await UniTask.Yield();
}
}
else
{
await action();
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask Run(Func<object, UniTask> action, object state, bool configureAwait = true)
{
await UniTask.SwitchToThreadPool();
if (configureAwait)
{
try
{
await action(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
await action(state);
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask<T> Run<T>(Func<T> func, bool configureAwait = true)
{
@@ -71,6 +115,27 @@ namespace Cysharp.Threading.Tasks
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask<T> Run<T>(Func<UniTask<T>> func, bool configureAwait = true)
{
await UniTask.SwitchToThreadPool();
if (configureAwait)
{
try
{
return await func();
}
finally
{
await UniTask.Yield();
}
}
else
{
return await func();
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask<T> Run<T>(Func<object, T> func, object state, bool configureAwait = true)
{
@@ -92,6 +157,28 @@ namespace Cysharp.Threading.Tasks
return func(state);
}
}
/// <summary>Run action on the threadPool and return to main thread if configureAwait = true.</summary>
public static async UniTask<T> Run<T>(Func<object, UniTask<T>> func, object state, bool configureAwait = true)
{
await UniTask.SwitchToThreadPool();
if (configureAwait)
{
try
{
return await func(state);
}
finally
{
await UniTask.Yield();
}
}
else
{
return await func(state);
}
}
}
}

View File

@@ -137,14 +137,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~WaitUntilPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
@@ -249,14 +241,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~WaitWhilePromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
@@ -344,14 +328,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~WaitUntilCanceledPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
// where T : UnityEngine.Object, can not add constraint
@@ -475,14 +451,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~WaitUntilValueChangedUnityObjectPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class WaitUntilValueChangedStandardObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedStandardObjectPromise<T, U>>
@@ -604,14 +572,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~WaitUntilValueChangedStandardObjectPromise()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
}
}

View File

@@ -131,11 +131,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3)> WhenAll<T1, T2, T3>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3)
@@ -295,11 +290,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4)> WhenAll<T1, T2, T3, T4>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4)
@@ -495,11 +485,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5)> WhenAll<T1, T2, T3, T4, T5>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5)
@@ -731,11 +716,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6)> WhenAll<T1, T2, T3, T4, T5, T6>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6)
@@ -1003,11 +983,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7)> WhenAll<T1, T2, T3, T4, T5, T6, T7>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7)
@@ -1311,11 +1286,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8)
@@ -1655,11 +1625,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9)
@@ -2035,11 +2000,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10)
@@ -2451,11 +2411,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11)
@@ -2903,11 +2858,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12)
@@ -3391,11 +3341,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13)
@@ -3915,11 +3860,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13, UniTask<T14> task14)
@@ -4475,11 +4415,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
public static UniTask<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)> WhenAll<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13, UniTask<T14> task14, UniTask<T15> task15)
@@ -5071,11 +5006,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
}
}

View File

@@ -45,7 +45,7 @@ namespace Cysharp.Threading.Tasks
public WhenAllPromise(<#= args #>)
{
TaskTracker2.TrackActiveTask(this, 3);
TaskTracker.TrackActiveTask(this, 3);
this.completedCount = 0;
<# for(var j = 1; j <= i; j++) { #>
@@ -92,7 +92,7 @@ namespace Cysharp.Threading.Tasks
public (<#= t #>) GetResult(short token)
{
TaskTracker2.RemoveTracking(this);
TaskTracker.RemoveTracking(this);
GC.SuppressFinalize(this);
return core.GetResult(token);
}
@@ -116,11 +116,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
<# } #>
}

View File

@@ -142,11 +142,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
sealed class WhenAllPromise : IUniTaskSource
@@ -237,11 +232,6 @@ namespace Cysharp.Threading.Tasks
{
core.OnCompleted(continuation, state, token);
}
~WhenAllPromise()
{
core.Reset();
}
}
}
}

View File

@@ -127,11 +127,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3)> WhenAny<T1, T2, T3>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3)
@@ -289,11 +284,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4)> WhenAny<T1, T2, T3, T4>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4)
@@ -488,11 +478,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5)> WhenAny<T1, T2, T3, T4, T5>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5)
@@ -724,11 +709,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6)> WhenAny<T1, T2, T3, T4, T5, T6>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6)
@@ -997,11 +977,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7)> WhenAny<T1, T2, T3, T4, T5, T6, T7>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7)
@@ -1307,11 +1282,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8)
@@ -1654,11 +1624,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9)
@@ -2038,11 +2003,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10)
@@ -2459,11 +2419,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11)
@@ -2917,11 +2872,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12)
@@ -3412,11 +3362,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13)
@@ -3944,11 +3889,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13, UniTask<T14> task14)
@@ -4513,11 +4453,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
public static UniTask<(int winArgumentIndex, T1 result1, T2 result2, T3 result3, T4 result4, T5 result5, T6 result6, T7 result7, T8 result8, T9 result9, T10 result10, T11 result11, T12 result12, T13 result13, T14 result14, T15 result15)> WhenAny<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>(UniTask<T1> task1, UniTask<T2> task2, UniTask<T3> task3, UniTask<T4> task4, UniTask<T5> task5, UniTask<T6> task6, UniTask<T7> task7, UniTask<T8> task8, UniTask<T9> task9, UniTask<T10> task10, UniTask<T11> task11, UniTask<T12> task12, UniTask<T13> task13, UniTask<T14> task14, UniTask<T15> task15)
@@ -5119,11 +5054,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
}

View File

@@ -37,7 +37,7 @@ namespace Cysharp.Threading.Tasks
public WhenAnyPromise(<#= args #>)
{
TaskTracker2.TrackActiveTask(this, 3);
TaskTracker.TrackActiveTask(this, 3);
this.completedCount = 0;
<# for(var j = 1; j <= i; j++) { #>
@@ -86,7 +86,7 @@ namespace Cysharp.Threading.Tasks
public (int, <#= tBool #>) GetResult(short token)
{
TaskTracker2.RemoveTracking(this);
TaskTracker.RemoveTracking(this);
GC.SuppressFinalize(this);
return core.GetResult(token);
}
@@ -110,11 +110,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
<# } #>

View File

@@ -171,11 +171,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyLRPromise()
{
core.Reset();
}
}
@@ -268,11 +263,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
sealed class WhenAnyPromise : IUniTaskSource<int>
@@ -363,11 +353,6 @@ namespace Cysharp.Threading.Tasks
{
GetResult(token);
}
~WhenAnyPromise()
{
core.Reset();
}
}
}
}

View File

@@ -1,6 +1,7 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
@@ -38,13 +39,42 @@ namespace Cysharp.Threading.Tasks
{
}
internal class ExceptionHolder
{
ExceptionDispatchInfo exception;
bool calledGet = false;
public ExceptionHolder(ExceptionDispatchInfo exception)
{
this.exception = exception;
}
public ExceptionDispatchInfo GetException()
{
if (!calledGet)
{
calledGet = true;
GC.SuppressFinalize(this);
}
return exception;
}
~ExceptionHolder()
{
if (!calledGet)
{
UniTaskScheduler.PublishUnobservedTaskException(exception.SourceException);
}
}
}
[StructLayout(LayoutKind.Auto)]
public struct UniTaskCompletionSourceCore<TResult>
{
// Struct Size: TResult + (8 + 2 + 1 + 1 + 8 + 8)
TResult result;
object error; // ExceptionDispatchInfo or OperationCanceledException
object error; // ExceptionHolder or OperationCanceledException
short version;
bool hasUnhandledError;
int completedCount; // 0: completed == false
@@ -78,9 +108,9 @@ namespace Cysharp.Threading.Tasks
{
UniTaskScheduler.PublishUnobservedTaskException(oc);
}
else if (error is ExceptionDispatchInfo ei)
else if (error is ExceptionHolder e)
{
UniTaskScheduler.PublishUnobservedTaskException(ei.SourceException);
UniTaskScheduler.PublishUnobservedTaskException(e.GetException().SourceException);
}
}
catch
@@ -129,7 +159,7 @@ namespace Cysharp.Threading.Tasks
}
else
{
this.error = ExceptionDispatchInfo.Capture(error);
this.error = new ExceptionHolder(ExceptionDispatchInfo.Capture(error));
}
if (continuation != null || Interlocked.CompareExchange(ref this.continuation, UniTaskCompletionSourceCoreShared.s_sentinel, null) != null)
@@ -209,9 +239,9 @@ namespace Cysharp.Threading.Tasks
{
throw oce;
}
else if (error is ExceptionDispatchInfo edi)
else if (error is ExceptionHolder eh)
{
edi.Throw();
eh.GetException().Throw();
}
throw new InvalidOperationException("Critical: invalid exception type was held.");
@@ -286,95 +316,6 @@ namespace Cysharp.Threading.Tasks
}
}
public class UniTaskCompletionSource : IUniTaskSource, IPromise
{
UniTaskCompletionSourceCore<AsyncUnit> core;
bool handled = false;
public UniTaskCompletionSource()
{
TaskTracker.TrackActiveTask(this, 2);
}
[DebuggerHidden]
internal void MarkHandled()
{
if (!handled)
{
handled = true;
core.MarkHandled();
TaskTracker.RemoveTracking(this);
}
}
public UniTask Task
{
[DebuggerHidden]
get
{
return new UniTask(this, core.Version);
}
}
[DebuggerHidden]
public void Reset()
{
// Reset, re-active tracker
handled = false;
TaskTracker.TrackActiveTask(this, 2);
core.Reset();
}
[DebuggerHidden]
public bool TrySetResult()
{
return core.TrySetResult(AsyncUnit.Default);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return core.TrySetException(exception);
}
[DebuggerHidden]
public void GetResult(short token)
{
MarkHandled();
core.GetResult(token);
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
~UniTaskCompletionSource()
{
// clear error information.
core.Reset();
}
}
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
{
static TaskPool<AutoResetUniTaskCompletionSource> pool;
@@ -495,110 +436,6 @@ namespace Cysharp.Threading.Tasks
core.Reset();
return pool.TryPush(this);
}
~AutoResetUniTaskCompletionSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
return;
}
}
}
public class UniTaskCompletionSource<T> : IUniTaskSource<T>, IPromise<T>
{
UniTaskCompletionSourceCore<T> core;
bool handled = false;
[DebuggerHidden]
public UniTaskCompletionSource()
{
TaskTracker.TrackActiveTask(this, 2);
}
[DebuggerHidden]
internal void MarkHandled()
{
if (!handled)
{
handled = true;
core.MarkHandled();
TaskTracker.RemoveTracking(this);
}
}
[DebuggerHidden]
public UniTask<T> Task
{
get
{
return new UniTask<T>(this, core.Version);
}
}
[DebuggerHidden]
public void Reset()
{
handled = false;
core.Reset();
TaskTracker.TrackActiveTask(this, 2);
}
[DebuggerHidden]
public bool TrySetResult(T result)
{
return core.TrySetResult(result);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
return core.TrySetCanceled(cancellationToken);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
return core.TrySetException(exception);
}
[DebuggerHidden]
public T GetResult(short token)
{
MarkHandled();
return core.GetResult(token);
}
[DebuggerHidden]
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return core.GetStatus(token);
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return core.UnsafeGetStatus();
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
core.OnCompleted(continuation, state, token);
}
~UniTaskCompletionSource()
{
// clear error information.
core.Reset();
}
}
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
@@ -726,15 +563,377 @@ namespace Cysharp.Threading.Tasks
core.Reset();
return pool.TryPush(this);
}
}
public class UniTaskCompletionSource : IUniTaskSource, IPromise
{
CancellationToken cancellationToken;
ExceptionHolder exception;
object gate;
Action<object> singleContinuation;
object singleState;
List<(Action<object>, object)> secondaryContinuationList;
~AutoResetUniTaskCompletionSource()
int intStatus; // UniTaskStatus
bool handled = false;
public UniTaskCompletionSource()
{
if (TryReturn())
TaskTracker.TrackActiveTask(this, 2);
}
[DebuggerHidden]
internal void MarkHandled()
{
if (!handled)
{
GC.ReRegisterForFinalize(this);
handled = true;
TaskTracker.RemoveTracking(this);
}
}
}
}
public UniTask Task
{
[DebuggerHidden]
get
{
return new UniTask(this, 0);
}
}
[DebuggerHidden]
public bool TrySetResult()
{
return TrySignalCompletion(UniTaskStatus.Succeeded);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
if (UnsafeGetStatus() != UniTaskStatus.Pending) return false;
this.cancellationToken = cancellationToken;
return TrySignalCompletion(UniTaskStatus.Canceled);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
if (exception is OperationCanceledException oce)
{
return TrySetCanceled(oce.CancellationToken);
}
if (UnsafeGetStatus() != UniTaskStatus.Pending) return false;
this.exception = new ExceptionHolder(ExceptionDispatchInfo.Capture(exception));
return TrySignalCompletion(UniTaskStatus.Faulted);
}
[DebuggerHidden]
public void GetResult(short token)
{
MarkHandled();
var status = (UniTaskStatus)intStatus;
switch (status)
{
case UniTaskStatus.Succeeded:
return;
case UniTaskStatus.Faulted:
exception.GetException().Throw();
return;
case UniTaskStatus.Canceled:
throw new OperationCanceledException(cancellationToken);
default:
case UniTaskStatus.Pending:
throw new InvalidOperationException("not yet completed.");
}
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return (UniTaskStatus)intStatus;
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return (UniTaskStatus)intStatus;
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
if (gate == null)
{
Interlocked.CompareExchange(ref gate, new object(), null);
}
var lockGate = Thread.VolatileRead(ref gate);
lock (lockGate) // wait TrySignalCompletion, after status is not pending.
{
if ((UniTaskStatus)intStatus != UniTaskStatus.Pending)
{
continuation(state);
return;
}
if (singleContinuation == null)
{
singleContinuation = continuation;
singleState = state;
}
else
{
if (secondaryContinuationList == null)
{
secondaryContinuationList = new List<(Action<object>, object)>();
}
secondaryContinuationList.Add((continuation, state));
}
}
}
[DebuggerHidden]
bool TrySignalCompletion(UniTaskStatus status)
{
if (Interlocked.CompareExchange(ref intStatus, (int)status, (int)UniTaskStatus.Pending) == (int)UniTaskStatus.Pending)
{
if (gate == null)
{
Interlocked.CompareExchange(ref gate, new object(), null);
}
var lockGate = Thread.VolatileRead(ref gate);
lock (lockGate) // wait OnCompleted.
{
if (singleContinuation != null)
{
try
{
singleContinuation(singleState);
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
}
if (secondaryContinuationList != null)
{
foreach (var (c, state) in secondaryContinuationList)
{
try
{
c(state);
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
}
}
singleContinuation = null;
singleState = null;
secondaryContinuationList = null;
}
return true;
}
return false;
}
}
public class UniTaskCompletionSource<T> : IUniTaskSource<T>, IPromise<T>
{
CancellationToken cancellationToken;
T result;
ExceptionHolder exception;
object gate;
Action<object> singleContinuation;
object singleState;
List<(Action<object>, object)> secondaryContinuationList;
int intStatus; // UniTaskStatus
bool handled = false;
public UniTaskCompletionSource()
{
TaskTracker.TrackActiveTask(this, 2);
}
[DebuggerHidden]
internal void MarkHandled()
{
if (!handled)
{
handled = true;
TaskTracker.RemoveTracking(this);
}
}
public UniTask<T> Task
{
[DebuggerHidden]
get
{
return new UniTask<T>(this, 0);
}
}
[DebuggerHidden]
public bool TrySetResult(T result)
{
if (UnsafeGetStatus() != UniTaskStatus.Pending) return false;
this.result = result;
return TrySignalCompletion(UniTaskStatus.Succeeded);
}
[DebuggerHidden]
public bool TrySetCanceled(CancellationToken cancellationToken = default)
{
if (UnsafeGetStatus() != UniTaskStatus.Pending) return false;
this.cancellationToken = cancellationToken;
return TrySignalCompletion(UniTaskStatus.Canceled);
}
[DebuggerHidden]
public bool TrySetException(Exception exception)
{
if (exception is OperationCanceledException oce)
{
return TrySetCanceled(oce.CancellationToken);
}
if (UnsafeGetStatus() != UniTaskStatus.Pending) return false;
this.exception = new ExceptionHolder(ExceptionDispatchInfo.Capture(exception));
return TrySignalCompletion(UniTaskStatus.Faulted);
}
[DebuggerHidden]
public T GetResult(short token)
{
MarkHandled();
var status = (UniTaskStatus)intStatus;
switch (status)
{
case UniTaskStatus.Succeeded:
return result;
case UniTaskStatus.Faulted:
exception.GetException().Throw();
return default;
case UniTaskStatus.Canceled:
throw new OperationCanceledException(cancellationToken);
default:
case UniTaskStatus.Pending:
throw new InvalidOperationException("not yet completed.");
}
}
[DebuggerHidden]
void IUniTaskSource.GetResult(short token)
{
GetResult(token);
}
[DebuggerHidden]
public UniTaskStatus GetStatus(short token)
{
return (UniTaskStatus)intStatus;
}
[DebuggerHidden]
public UniTaskStatus UnsafeGetStatus()
{
return (UniTaskStatus)intStatus;
}
[DebuggerHidden]
public void OnCompleted(Action<object> continuation, object state, short token)
{
if (gate == null)
{
Interlocked.CompareExchange(ref gate, new object(), null);
}
var lockGate = Thread.VolatileRead(ref gate);
lock (lockGate) // wait TrySignalCompletion, after status is not pending.
{
if ((UniTaskStatus)intStatus != UniTaskStatus.Pending)
{
continuation(state);
return;
}
if (singleContinuation == null)
{
singleContinuation = continuation;
singleState = state;
}
else
{
if (secondaryContinuationList == null)
{
secondaryContinuationList = new List<(Action<object>, object)>();
}
secondaryContinuationList.Add((continuation, state));
}
}
}
[DebuggerHidden]
bool TrySignalCompletion(UniTaskStatus status)
{
if (Interlocked.CompareExchange(ref intStatus, (int)status, (int)UniTaskStatus.Pending) == (int)UniTaskStatus.Pending)
{
if (gate == null)
{
Interlocked.CompareExchange(ref gate, new object(), null);
}
var lockGate = Thread.VolatileRead(ref gate);
lock (lockGate) // wait OnCompleted.
{
if (singleContinuation != null)
{
try
{
singleContinuation(singleState);
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
}
if (secondaryContinuationList != null)
{
foreach (var (c, state) in secondaryContinuationList)
{
try
{
c(state);
}
catch (Exception ex)
{
UniTaskScheduler.PublishUnobservedTaskException(ex);
}
}
}
singleContinuation = null;
singleState = null;
secondaryContinuationList = null;
}
return true;
}
return false;
}
}
}

View File

@@ -181,12 +181,12 @@ namespace Cysharp.Threading.Tasks
public static AsyncLazy ToAsyncLazy(this UniTask task)
{
return new AsyncLazy(task.Preserve()); // require Preserve
return new AsyncLazy(task);
}
public static AsyncLazy<T> ToAsyncLazy<T>(this UniTask<T> task)
{
return new AsyncLazy<T>(task.Preserve()); // require Preserve
return new AsyncLazy<T>(task);
}
#if UNITY_2018_3_OR_NEWER
@@ -315,7 +315,7 @@ namespace Cysharp.Threading.Tasks
taskCancellationTokenSource.Dispose();
}
throw new TimeoutException("Exceed Timeout:" + timeout);
return true;
}
else
{
@@ -325,7 +325,7 @@ namespace Cysharp.Threading.Tasks
if (taskResultIsCanceled)
{
Error.ThrowOperationCanceledException();
return true;
}
return false;
@@ -361,7 +361,7 @@ namespace Cysharp.Threading.Tasks
taskCancellationTokenSource.Dispose();
}
throw new TimeoutException("Exceed Timeout:" + timeout);
return (true, default);
}
else
{
@@ -371,7 +371,7 @@ namespace Cysharp.Threading.Tasks
if (taskResult.IsCanceled)
{
Error.ThrowOperationCanceledException();
return (true, default);
}
return (false, taskResult.Result);

View File

@@ -160,7 +160,7 @@ namespace Cysharp.Threading.Tasks
}
public bool MoveNext()
{
{
if (completed)
{
TryReturn();
@@ -185,14 +185,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
@@ -299,14 +291,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AsyncOperationConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion
@@ -466,7 +450,7 @@ namespace Cysharp.Threading.Tasks
}
public bool MoveNext()
{
{
if (completed)
{
TryReturn();
@@ -491,14 +475,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~ResourceRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
@@ -609,14 +585,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~ResourceRequestConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion
@@ -776,7 +744,7 @@ namespace Cysharp.Threading.Tasks
}
public bool MoveNext()
{
{
if (completed)
{
TryReturn();
@@ -801,14 +769,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
@@ -919,14 +879,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleRequestConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion
@@ -1086,7 +1038,7 @@ namespace Cysharp.Threading.Tasks
}
public bool MoveNext()
{
{
if (completed)
{
TryReturn();
@@ -1111,14 +1063,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleCreateRequestWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
@@ -1229,14 +1173,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~AssetBundleCreateRequestConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion
@@ -1285,12 +1221,20 @@ namespace Cysharp.Threading.Tasks
continuationAction = null;
var result = asyncOperation.webRequest;
asyncOperation = null;
if (result.isHttpError || result.isNetworkError)
{
throw new UnityWebRequestException(result);
}
return result;
}
else
{
var result = asyncOperation.webRequest;
asyncOperation = null;
if (result.isHttpError || result.isNetworkError)
{
throw new UnityWebRequestException(result);
}
return result;
}
}
@@ -1367,7 +1311,15 @@ namespace Cysharp.Threading.Tasks
else
{
completed = true;
core.TrySetResult(asyncOperation.webRequest);
var result = asyncOperation.webRequest;
if (result.isHttpError || result.isNetworkError)
{
core.TrySetException(new UnityWebRequestException(result));
}
else
{
core.TrySetResult(result);
}
}
}
@@ -1397,7 +1349,7 @@ namespace Cysharp.Threading.Tasks
}
public bool MoveNext()
{
{
if (completed)
{
TryReturn();
@@ -1423,14 +1375,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~UnityWebRequestAsyncOperationWithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
@@ -1526,7 +1470,14 @@ namespace Cysharp.Threading.Tasks
if (asyncOperation.isDone)
{
core.TrySetResult(asyncOperation.webRequest);
if (asyncOperation.webRequest.isHttpError || asyncOperation.webRequest.isNetworkError)
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
return false;
}
@@ -1542,14 +1493,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~UnityWebRequestAsyncOperationConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion

View File

@@ -81,6 +81,12 @@ namespace Cysharp.Threading.Tasks
<# if (!IsVoid(t)) { #>
var result = <#= $"asyncOperation.{t.returnField}" #>;
asyncOperation = null;
<# if(t.returnType == "UnityWebRequest") { #>
if (result.isHttpError || result.isNetworkError)
{
throw new UnityWebRequestException(result);
}
<# } #>
return result;
<# } else { #>
asyncOperation = null;
@@ -91,6 +97,12 @@ namespace Cysharp.Threading.Tasks
<# if (!IsVoid(t)) { #>
var result = <#= $"asyncOperation.{t.returnField}" #>;
asyncOperation = null;
<# if(t.returnType == "UnityWebRequest") { #>
if (result.isHttpError || result.isNetworkError)
{
throw new UnityWebRequestException(result);
}
<# } #>
return result;
<# } else { #>
asyncOperation = null;
@@ -170,7 +182,19 @@ namespace Cysharp.Threading.Tasks
else
{
completed = true;
<# if(t.returnType == "UnityWebRequest") { #>
var result = asyncOperation.webRequest;
if (result.isHttpError || result.isNetworkError)
{
core.TrySetException(new UnityWebRequestException(result));
}
else
{
core.TrySetResult(result);
}
<# } else { #>
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
<# } #>
}
}
@@ -234,14 +258,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~<#= t.typeName #>WithCancellationSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
sealed class <#= t.typeName #>ConfiguredSource : <#= ToIUniTaskSourceReturnType(t.returnType) #>, IPlayerLoopItem, ITaskPoolNode<<#= t.typeName #>ConfiguredSource>
@@ -345,7 +361,18 @@ namespace Cysharp.Threading.Tasks
if (asyncOperation.isDone)
{
<# if(t.returnType == "UnityWebRequest") { #>
if (asyncOperation.webRequest.isHttpError || asyncOperation.webRequest.isNetworkError)
{
core.TrySetException(new UnityWebRequestException(asyncOperation.webRequest));
}
else
{
core.TrySetResult(asyncOperation.webRequest);
}
<# } else { #>
core.TrySetResult(<#= IsVoid(t) ? "AsyncUnit.Default" : $"asyncOperation.{t.returnField}" #>);
<# } #>
return false;
}
@@ -361,14 +388,6 @@ namespace Cysharp.Threading.Tasks
cancellationToken = default;
return pool.TryPush(this);
}
~<#= t.typeName #>ConfiguredSource()
{
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}
}
}
#endregion

View File

@@ -0,0 +1,24 @@
#if ENABLE_UNITYWEBREQUEST
using System;
using UnityEngine.Networking;
namespace Cysharp.Threading.Tasks
{
public class UnityWebRequestException : Exception
{
public UnityWebRequest UnityWebRequest { get; }
public bool IsNetworkError { get; }
public bool IsHttpError { get; }
public UnityWebRequestException(UnityWebRequest unityWebRequest)
: base(unityWebRequest.error + Environment.NewLine + unityWebRequest.downloadHandler.text)
{
this.UnityWebRequest = unityWebRequest;
this.IsNetworkError = unityWebRequest.isNetworkError;
this.IsHttpError = unityWebRequest.isHttpError;
}
}
}
#endif

View File

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

View File

@@ -1,7 +1,7 @@
{
"name": "com.cysharp.unitask",
"displayName": "UniTask",
"version": "2.0.16",
"version": "2.0.19",
"unity": "2018.4",
"description": "Provides an efficient async/await integration to Unity.",
"keywords": [ "async/await", "async", "Task", "UniTask" ],

View File

@@ -1,77 +1,28 @@
// Provided from: https://github.com/Cysharp/UniTask/issues/40
using System;
using System;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// Example script for comparing how exceptions in unobserved tasks are handled between
/// UniTask and normal tasks. This helps in verifying that unobserved exceptions are
/// logged in a way that it useful to developers.
/// </summary>
public class ExceptionExamples : MonoBehaviour
{
[SerializeField] private LogType _unobservedExceptionLogType = LogType.Exception;
private void Awake()
{
UniTaskScheduler.UnobservedExceptionWriteLogType = _unobservedExceptionLogType;
}
private void Start()
{
UnityEngine.Debug.Log("ExceptionScene, LoopType:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
//TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
//ThrowFromAsyncVoid();
//_ = ThrowFromTask();
//_ = ThrowFromUniTask();
//ThrowFromNonAsync();
}
private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
public static async Task Test()
{
UnityEngine.Debug.LogException(e.Exception);
}
private void ThrowFromNonAsync()
{
throw new Exception("Thrown from non-async function");
}
private async void ThrowFromAsyncVoid()
{
await ThrowInner();
async Task ThrowInner()
{
await UniTask.Yield();
throw new Exception("Thrown from `async void` function");
}
}
private async Task ThrowFromTask()
{
await ThrowInner();
async Task ThrowInner()
{
await UniTask.Yield();
throw new Exception("Thrown from `async Task` function");
}
}
private async UniTask ThrowFromUniTask()
{
await ThrowInner();
async UniTask ThrowInner()
{
await UniTask.Yield();
throw new Exception("Thrown from `async UniTask` function");
}
var webRequest = UnityWebRequest.Get("http");
var request = webRequest.SendWebRequest();
await request;
}
}

View File

@@ -184,6 +184,7 @@ public class SandboxMain : MonoBehaviour
}
async UniTask RunStandardDelayAsync()
{
UnityEngine.Debug.Log("DEB");
@@ -415,20 +416,30 @@ public class SandboxMain : MonoBehaviour
private async UniTaskVoid ExecuteAsync()
{
Debug.Log("1");
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
}
Debug.Log("------------------");
{
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).ToArrayAsync();
Debug.Log("2");
}
var req = UnityWebRequest.Get("https://google.com/");
var v = await req.SendWebRequest().ToUniTask();
// req.Dispose();
Debug.Log($"{v.isDone} {v.isHttpError} {v.isNetworkError}");
Debug.Log(v.downloadHandler.text);
}
private async void Go()
{
await UniTask.DelayFrame(0);
}
async UniTask Foo()
{
await UniTask.DelayFrame(10);
throw new Exception("yeah");
}
void Start()
{
_ = Foo(); // unhandled.
Go();
UnityEngine.Debug.Log("Start:" + PlayerLoopInfo.CurrentLoopType);
//PlayerLoopInfo.Inject();
@@ -444,76 +455,76 @@ public class SandboxMain : MonoBehaviour
// rp.AddTo(this.GetCancellationTokenOnDestroy());
var cts = new CancellationTokenSource();
//var cts = new CancellationTokenSource();
okButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
_ = ExecuteAsync();
await UniTask.Yield();
//await DelayCheck();
/*
UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
StartCoroutine(CoroutineRun());
StartCoroutine(CoroutineRun2());
_ = AsyncRun();
_ = AsyncLastUpdate();
_ = AsyncLastLast();
*/
//await UniTask.Yield();
//_ = Test2();
// EarlyUpdate.ExecuteMainThreadJobs
// _ = Test2();
//var t = await Resources.LoadAsync<TextAsset>(Application.streamingAssetsPath + "test.txt");
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + (t != null));
//Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + ((TextAsset)t).text);
//await UniTask.Yield(PlayerLoopTiming.LastUpdate);
//UnityEngine.Debug.Log("after update:" + Time.frameCount);
////await UniTask.NextFrame();
////await UniTask.Yield();
////UnityEngine.Debug.Log("after update nextframe:" + Time.frameCount);
//okButton.onClick.AddListener(UniTask.UnityAction(async () =>
//{
// _ = ExecuteAsync();
//StartCoroutine(CoroutineRun2());
////StartCoroutine(CoroutineRun());
//UnityEngine.Debug.Log("FOO?");
// await UniTask.Yield();
//_ = DelayFrame3_Pre();
//await UniTask.Yield();
// //await DelayCheck();
// /*
// UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
// StartCoroutine(CoroutineRun());
// StartCoroutine(CoroutineRun2());
// _ = AsyncRun();
// _ = AsyncLastUpdate();
// _ = AsyncLastLast();
// */
// //await UniTask.Yield();
// //_ = Test2();
// // EarlyUpdate.ExecuteMainThreadJobs
// // _ = Test2();
}));
// //var t = await Resources.LoadAsync<TextAsset>(Application.streamingAssetsPath + "test.txt");
// //Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + (t != null));
// //Debug.Log("LoadEnd" + PlayerLoopInfo.CurrentLoopType + ", " + ((TextAsset)t).text);
cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>
{
_ = DelayFrame3_Post();
await UniTask.Yield();
//await UniTask.Yield(PlayerLoopTiming.LastPreUpdate);
//UnityEngine.Debug.Log("before update:" + Time.frameCount);
//await UniTask.NextFrame();
//await UniTask.Yield();
//UnityEngine.Debug.Log("before update nextframe:" + Time.frameCount);
// //await UniTask.Yield(PlayerLoopTiming.LastUpdate);
// //UnityEngine.Debug.Log("after update:" + Time.frameCount);
// ////await UniTask.NextFrame();
// ////await UniTask.Yield();
// ////UnityEngine.Debug.Log("after update nextframe:" + Time.frameCount);
//StartCoroutine(CoroutineRun());
// //StartCoroutine(CoroutineRun2());
// ////StartCoroutine(CoroutineRun());
// //UnityEngine.Debug.Log("FOO?");
//UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
//_ = Yieldding();
// //_ = DelayFrame3_Pre();
// //await UniTask.Yield();
//var cts = new CancellationTokenSource();
//}));
//UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
//var la = SceneManager.LoadSceneAsync("Scenes/ExceptionExamples").WithCancellation(cts.Token);
////cts.Cancel();
//await la;
//UnityEngine.Debug.Log("End LoadSceneAsync" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
}));
//cancelButton.onClick.AddListener(UniTask.UnityAction(async () =>
//{
// _ = DelayFrame3_Post();
// await UniTask.Yield();
// //await UniTask.Yield(PlayerLoopTiming.LastPreUpdate);
// //UnityEngine.Debug.Log("before update:" + Time.frameCount);
// //await UniTask.NextFrame();
// //await UniTask.Yield();
// //UnityEngine.Debug.Log("before update nextframe:" + Time.frameCount);
// //StartCoroutine(CoroutineRun());
// //UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType);
// //_ = Yieldding();
// //var cts = new CancellationTokenSource();
// //UnityEngine.Debug.Log("click:" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
// //var la = SceneManager.LoadSceneAsync("Scenes/ExceptionExamples").WithCancellation(cts.Token);
// ////cts.Cancel();
// //await la;
// //UnityEngine.Debug.Log("End LoadSceneAsync" + PlayerLoopInfo.CurrentLoopType + ":" + Time.frameCount);
//}));
//return;
//await UniTask.SwitchToMainThread();

View File

@@ -16,168 +16,180 @@ namespace Cysharp.Threading.TasksTests
{
public class DelayTest
{
[UnityTest]
public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
{
for (int i = 1; i < 5; i++)
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var frameCount = Time.frameCount;
await UniTask.DelayFrame(i);
Time.frameCount.Should().Be(frameCount + i);
}
//[UnityTest]
//public IEnumerator DelayFrame() => UniTask.ToCoroutine(async () =>
//{
// for (int i = 1; i < 5; i++)
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(i);
// Time.frameCount.Should().Be(frameCount + i);
// }
for (int i = 1; i < 5; i++)
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var frameCount = Time.frameCount;
await UniTask.DelayFrame(i);
Time.frameCount.Should().Be(frameCount + i);
}
});
// for (int i = 1; i < 5; i++)
// {
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(i);
// Time.frameCount.Should().Be(frameCount + i);
// }
//});
[UnityTest]
public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
{
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var frameCount = Time.frameCount;
await UniTask.DelayFrame(0);
Time.frameCount.Should().Be(frameCount); // same frame
}
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var frameCount = Time.frameCount;
await UniTask.DelayFrame(0);
Time.frameCount.Should().Be(frameCount + 1); // next frame
}
});
//[UnityTest]
//public IEnumerator DelayFrameZero() => UniTask.ToCoroutine(async () =>
//{
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(0);
// Time.frameCount.Should().Be(frameCount); // same frame
// }
// {
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var frameCount = Time.frameCount;
// await UniTask.DelayFrame(0);
// Time.frameCount.Should().Be(frameCount + 1); // next frame
// }
//});
[UnityTest]
public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
//[UnityTest]
//public IEnumerator TimerFramePre() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame + 2);
xs[1].Should().Be(initialFrame + 2 + (3 * 1));
xs[2].Should().Be(initialFrame + 2 + (3 * 2));
xs[3].Should().Be(initialFrame + 2 + (3 * 3));
xs[4].Should().Be(initialFrame + 2 + (3 * 4));
});
// xs[0].Should().Be(initialFrame + 2);
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
//});
//[UnityTest]
//public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// xs[1].Should().Be(initialFrame + 2 + (3 * 1));
// xs[2].Should().Be(initialFrame + 2 + (3 * 2));
// xs[3].Should().Be(initialFrame + 2 + (3 * 3));
// xs[4].Should().Be(initialFrame + 2 + (3 * 4));
//});
//[UnityTest]
//public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame);
// xs[1].Should().Be(initialFrame + 1);
// xs[2].Should().Be(initialFrame + 2);
// xs[3].Should().Be(initialFrame + 3);
// xs[4].Should().Be(initialFrame + 4);
//});
//[UnityTest]
//public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
//{
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame);
// }
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ =>
// {
// var t = Time.frameCount;
// return t;
// }).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 1);
// }
// {
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// }
//});
//[UnityTest]
//public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () =>
//{
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// //var initialFrame = Time.frameCount;
// //var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
// //xs[0].Should().Be(initialFrame);
// }
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 1);
// }
// {
// //await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
// var initialFrame = Time.frameCount;
// var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
// xs[0].Should().Be(initialFrame + 2);
// }
//});
//[UnityTest]
//public IEnumerator Timer() => UniTask.ToCoroutine(async () =>
//{
// await UniTask.Yield(PlayerLoopTiming.PreUpdate);
// {
// var initialSeconds = Time.realtimeSinceStartup;
// var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync();
// Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse();
// Debug.Log("Init:" + initialSeconds);
// Debug.Log("After:" + xs[0]);
// }
//});
[UnityTest]
public IEnumerator TimerFramePost() => UniTask.ToCoroutine(async () =>
public IEnumerator DelayInThreadPool() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
await UniTask.Run(async () =>
{
Debug.Log("Go Delay?");
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(2, 3).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
await UniTask.Delay(TimeSpan.FromSeconds(2));
xs[0].Should().Be(initialFrame + 2);
xs[1].Should().Be(initialFrame + 2 + (3 * 1));
xs[2].Should().Be(initialFrame + 2 + (3 * 2));
xs[3].Should().Be(initialFrame + 2 + (3 * 3));
xs[4].Should().Be(initialFrame + 2 + (3 * 4));
Debug.Log("OK?");
});
});
[UnityTest]
public IEnumerator TimerFrameTest() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(0, 0).Take(5).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame);
xs[1].Should().Be(initialFrame + 1);
xs[2].Should().Be(initialFrame + 2);
xs[3].Should().Be(initialFrame + 3);
xs[4].Should().Be(initialFrame + 4);
});
[UnityTest]
public IEnumerator TimerFrameSinglePre() => UniTask.ToCoroutine(async () =>
{
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame);
}
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ =>
{
var t = Time.frameCount;
return t;
}).ToArrayAsync();
xs[0].Should().Be(initialFrame + 1);
}
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame + 2);
}
});
[UnityTest]
public IEnumerator TimerFrameSinglePost() => UniTask.ToCoroutine(async () =>
{
{
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
//var initialFrame = Time.frameCount;
//var xs = await UniTaskAsyncEnumerable.TimerFrame(0).Select(_ => Time.frameCount).ToArrayAsync();
//xs[0].Should().Be(initialFrame);
}
{
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(1).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame + 1);
}
{
//await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);
var initialFrame = Time.frameCount;
var xs = await UniTaskAsyncEnumerable.TimerFrame(2).Select(_ => Time.frameCount).ToArrayAsync();
xs[0].Should().Be(initialFrame + 2);
}
});
[UnityTest]
public IEnumerator Timer() => UniTask.ToCoroutine(async () =>
{
await UniTask.Yield(PlayerLoopTiming.PreUpdate);
{
var initialSeconds = Time.realtimeSinceStartup;
var xs = await UniTaskAsyncEnumerable.Timer(TimeSpan.FromSeconds(2)).Select(_ => Time.realtimeSinceStartup).ToArrayAsync();
Mathf.Approximately(initialSeconds, xs[0]).Should().BeFalse();
Debug.Log("Init:" + initialSeconds);
Debug.Log("After:" + xs[0]);
}
});
}

View File

@@ -78,7 +78,9 @@ namespace Cysharp.Threading.TasksTests
var main = Thread.CurrentThread.ManagedThreadId;
try
{
await UniTask.Run<int>(() => throw new Exception(), true);
#pragma warning disable CS1998
await UniTask.Run<int>(async () => throw new Exception(), true);
#pragma warning restore CS1998
}
catch
{

View File

@@ -557,7 +557,7 @@ PlayerSettings:
platformArchitecture: {}
scriptingBackend:
Android: 1
Standalone: 1
Standalone: 0
il2cppCompilerConfiguration: {}
managedStrippingLevel: {}
incrementalIl2cppBuild: {}