Add IUniTaskAsyncEnumerable.Queue
parent
49ba57f20a
commit
ec0a8f5a8b
|
@ -0,0 +1,29 @@
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace NetCoreTests.Linq
|
||||||
|
{
|
||||||
|
public class QueueTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Q()
|
||||||
|
{
|
||||||
|
var rp = new AsyncReactiveProperty<int>(100);
|
||||||
|
|
||||||
|
var l = new List<int>();
|
||||||
|
await rp.Take(10).Queue().ForEachAsync(x =>
|
||||||
|
{
|
||||||
|
rp.Value += 10;
|
||||||
|
l.Add(x);
|
||||||
|
});
|
||||||
|
|
||||||
|
l.Should().BeEquivalentTo(100, 110, 120, 130, 140, 150, 160, 170, 180, 190);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using Cysharp.Threading.Tasks.Linq;
|
||||||
|
using FluentAssertions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace NetCoreTests.Linq
|
||||||
|
{
|
||||||
|
public class TakeInfinityTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Take()
|
||||||
|
{
|
||||||
|
var rp = new AsyncReactiveProperty<int>(1);
|
||||||
|
|
||||||
|
var xs = rp.Take(5).ToArrayAsync();
|
||||||
|
|
||||||
|
rp.Value = 2;
|
||||||
|
rp.Value = 3;
|
||||||
|
rp.Value = 4;
|
||||||
|
rp.Value = 5;
|
||||||
|
|
||||||
|
(await xs).Should().BeEquivalentTo(1, 2, 3, 4, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TakeWhile()
|
||||||
|
{
|
||||||
|
var rp = new AsyncReactiveProperty<int>(1);
|
||||||
|
|
||||||
|
var xs = rp.TakeWhile(x => x != 5).ToArrayAsync();
|
||||||
|
|
||||||
|
rp.Value = 2;
|
||||||
|
rp.Value = 3;
|
||||||
|
rp.Value = 4;
|
||||||
|
rp.Value = 5;
|
||||||
|
|
||||||
|
(await xs).Should().BeEquivalentTo(1, 2, 3, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks.Linq
|
||||||
|
{
|
||||||
|
public static partial class UniTaskAsyncEnumerable
|
||||||
|
{
|
||||||
|
public static IUniTaskAsyncEnumerable<TSource> Queue<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
|
||||||
|
{
|
||||||
|
return new QueueOperator<TSource>(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class QueueOperator<TSource> : IUniTaskAsyncEnumerable<TSource>
|
||||||
|
{
|
||||||
|
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||||
|
|
||||||
|
public QueueOperator(IUniTaskAsyncEnumerable<TSource> source)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return new _Queue(source, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class _Queue : IUniTaskAsyncEnumerator<TSource>
|
||||||
|
{
|
||||||
|
readonly IUniTaskAsyncEnumerable<TSource> source;
|
||||||
|
CancellationToken cancellationToken;
|
||||||
|
|
||||||
|
Channel<TSource> channel;
|
||||||
|
IUniTaskAsyncEnumerator<TSource> channelEnumerator;
|
||||||
|
IUniTaskAsyncEnumerator<TSource> sourceEnumerator;
|
||||||
|
|
||||||
|
public _Queue(IUniTaskAsyncEnumerable<TSource> source, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.cancellationToken = cancellationToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TSource Current => channelEnumerator.Current;
|
||||||
|
|
||||||
|
public UniTask<bool> MoveNextAsync()
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (sourceEnumerator == null)
|
||||||
|
{
|
||||||
|
sourceEnumerator = source.GetAsyncEnumerator(cancellationToken);
|
||||||
|
channel = Channel.CreateSingleConsumerUnbounded<TSource>();
|
||||||
|
|
||||||
|
channelEnumerator = channel.Reader.ReadAllAsync().GetAsyncEnumerator(cancellationToken);
|
||||||
|
|
||||||
|
ConsumeAll(sourceEnumerator, channel).Forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelEnumerator.MoveNextAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async UniTaskVoid ConsumeAll(IUniTaskAsyncEnumerator<TSource> enumerator, ChannelWriter<TSource> writer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (await enumerator.MoveNextAsync())
|
||||||
|
{
|
||||||
|
writer.TryWrite(enumerator.Current);
|
||||||
|
}
|
||||||
|
writer.TryComplete();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
writer.TryComplete(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await enumerator.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async UniTask DisposeAsync()
|
||||||
|
{
|
||||||
|
if (sourceEnumerator != null)
|
||||||
|
{
|
||||||
|
await sourceEnumerator.DisposeAsync();
|
||||||
|
}
|
||||||
|
if (channelEnumerator != null)
|
||||||
|
{
|
||||||
|
await channelEnumerator.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue