Compare commits

...

5 Commits

Author SHA1 Message Date
Scormave 2ee247c48a
Merge 76697eb172 into 4c3d6938ed 2023-08-31 14:29:23 +03:00
hadashiA 4c3d6938ed
Merge pull request #484 from Cysharp/hadashiA/fix-async-enumerable
Fix problem with finally in UniTaskAsyncEnumerable.Create not being executed
2023-08-31 19:17:31 +09:00
hadashiA b4486802f2 Fix problem with part of await foreach not executing on break 2023-08-31 12:42:53 +09:00
Sergey Andreev 76697eb172 Removed default for CancellationToken, since there can be ambiguous calls 2023-05-09 15:50:52 +02:00
Sergey Andreev 7cba23dd62 Added AsUniTask methods with CancellationToken support 2023-05-09 15:38:06 +02:00
3 changed files with 97 additions and 1 deletions

View File

@ -159,6 +159,30 @@ namespace NetCoreTests.Linq
list.Should().Equal(100, 200, 300, 400);
}
[Fact]
public async Task AwaitForeachBreak()
{
var finallyCalled = false;
var enumerable = UniTaskAsyncEnumerable.Create<int>(async (writer, _) =>
{
try
{
await writer.YieldAsync(1);
}
finally
{
finallyCalled = true;
}
});
await foreach (var x in enumerable)
{
x.Should().Be(1);
break;
}
finallyCalled.Should().BeTrue();
}
async IAsyncEnumerable<int> Range(int from, int count)
{
for (int i = 0; i < count; i++)

View File

@ -52,6 +52,7 @@ namespace Cysharp.Threading.Tasks.Linq
public UniTask DisposeAsync()
{
TaskTracker.RemoveTracking(this);
writer.Dispose();
return default;
}
@ -127,7 +128,7 @@ namespace Cysharp.Threading.Tasks.Linq
}
}
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>
sealed class AsyncWriter : IUniTaskSource, IAsyncWriter<T>, IDisposable
{
readonly _Create enumerator;
@ -137,6 +138,15 @@ namespace Cysharp.Threading.Tasks.Linq
{
this.enumerator = enumerator;
}
public void Dispose()
{
var status = core.GetStatus(core.Version);
if (status == UniTaskStatus.Pending)
{
core.TrySetCanceled();
}
}
public void GetResult(short token)
{

View File

@ -41,6 +41,37 @@ namespace Cysharp.Threading.Tasks
return promise.Task;
}
public static UniTask<T> AsUniTask<T>(this Task<T> task, CancellationToken cancellationToken, bool useCurrentSynchronizationContext = true)
{
var promise = new UniTaskCompletionSource<T>();
var state = StatePool<UniTaskCompletionSource<T>, CancellationToken>.Create(promise, cancellationToken);
task.ContinueWith((x, state) =>
{
var tuple = (StateTuple<UniTaskCompletionSource<T>, CancellationToken>)state;
tuple.Deconstruct(out var p, out var token);
switch (x.Status)
{
case TaskStatus.Canceled:
p.TrySetCanceled(token);
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult(x.Result);
break;
default:
throw new NotSupportedException();
}
tuple.Dispose();
}, state, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current);
return promise.Task;
}
/// <summary>
/// Convert Task -> UniTask.
/// </summary>
@ -71,6 +102,37 @@ namespace Cysharp.Threading.Tasks
return promise.Task;
}
public static UniTask AsUniTask(this Task task, CancellationToken cancellationToken, bool useCurrentSynchronizationContext = true)
{
var promise = new UniTaskCompletionSource();
var state = StatePool<UniTaskCompletionSource, CancellationToken>.Create(promise, cancellationToken);
task.ContinueWith((x, state) =>
{
var tuple = (StateTuple<UniTaskCompletionSource, CancellationToken>)state;
tuple.Deconstruct(out var p, out var token);
switch (x.Status)
{
case TaskStatus.Canceled:
p.TrySetCanceled(token);
break;
case TaskStatus.Faulted:
p.TrySetException(x.Exception);
break;
case TaskStatus.RanToCompletion:
p.TrySetResult();
break;
default:
throw new NotSupportedException();
}
tuple.Dispose();
}, state, useCurrentSynchronizationContext ? TaskScheduler.FromCurrentSynchronizationContext() : TaskScheduler.Current);
return promise.Task;
}
public static Task<T> AsTask<T>(this UniTask<T> task)
{
try