TriggerEvent becomes linkedlist
parent
a9baa52309
commit
130286e8c2
|
@ -0,0 +1,39 @@
|
||||||
|
//using Cysharp.Threading.Tasks.Internal;
|
||||||
|
//using System;
|
||||||
|
//using System.Collections.Concurrent;
|
||||||
|
//using System.Runtime.CompilerServices;
|
||||||
|
//using System.Threading;
|
||||||
|
|
||||||
|
//namespace Cysharp.Threading.Tasks
|
||||||
|
//{
|
||||||
|
// public partial struct UniTask
|
||||||
|
// {
|
||||||
|
// public static UniTask Delay()
|
||||||
|
// {
|
||||||
|
// return default;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// sealed class DelayPromise : IUniTaskSource
|
||||||
|
// {
|
||||||
|
// public void GetResult(short token)
|
||||||
|
// {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public UniTaskStatus GetStatus(short token)
|
||||||
|
// {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
// {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public UniTaskStatus UnsafeGetStatus()
|
||||||
|
// {
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
|
@ -0,0 +1,637 @@
|
||||||
|
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 TriggerEventTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void SimpleAdd()
|
||||||
|
{
|
||||||
|
var ev = new TriggerEvent<int>();
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.SetCompleted();
|
||||||
|
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
}
|
||||||
|
// after removed, onemore
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.SetCompleted();
|
||||||
|
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddFour()
|
||||||
|
{
|
||||||
|
var ev = new TriggerEvent<int>();
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
var four = new TestEvent(4);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(four);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.SetCompleted();
|
||||||
|
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.CompletedCalled.Count.Should().Be(1);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// after removed, onemore.
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
var four = new TestEvent(4);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(four);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
ev.Add(four);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.SetCompleted();
|
||||||
|
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.CompletedCalled.Count.Should().Be(1);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
|
||||||
|
|
||||||
|
// do nothing
|
||||||
|
ev.SetResult(0);
|
||||||
|
ev.SetError(null);
|
||||||
|
ev.SetCompleted();
|
||||||
|
ev.SetCanceled(default);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
one.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.CompletedCalled.Count.Should().Be(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void OneRemove()
|
||||||
|
{
|
||||||
|
var ev = new TriggerEvent<int>();
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.Remove(one);
|
||||||
|
|
||||||
|
ev.SetResult(40);
|
||||||
|
ev.SetResult(50);
|
||||||
|
ev.SetResult(60);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TwoRemove()
|
||||||
|
{
|
||||||
|
var ev = new TriggerEvent<int>();
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.Remove(two);
|
||||||
|
|
||||||
|
ev.SetResult(40);
|
||||||
|
ev.SetResult(50);
|
||||||
|
ev.SetResult(60);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ThreeRemove()
|
||||||
|
{
|
||||||
|
var ev = new TriggerEvent<int>();
|
||||||
|
{
|
||||||
|
var one = new TestEvent(1);
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
|
||||||
|
ev.Remove(three);
|
||||||
|
|
||||||
|
ev.SetResult(40);
|
||||||
|
ev.SetResult(50);
|
||||||
|
ev.SetResult(60);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40, 50, 60);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RemoveSelf()
|
||||||
|
{
|
||||||
|
new RemoveMe().Run1();
|
||||||
|
new RemoveMe().Run2();
|
||||||
|
new RemoveMe().Run3();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RemoveNextInIterating()
|
||||||
|
{
|
||||||
|
new RemoveNext().Run1();
|
||||||
|
new RemoveNext().Run2();
|
||||||
|
new RemoveNext().Run3();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RemoveNextNextTest()
|
||||||
|
{
|
||||||
|
new RemoveNextNext().Run1();
|
||||||
|
new RemoveNextNext().Run2();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddTest()
|
||||||
|
{
|
||||||
|
new AddMe().Run1();
|
||||||
|
new AddMe().Run2();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RemoveMe
|
||||||
|
{
|
||||||
|
TriggerEvent<int> ev;
|
||||||
|
|
||||||
|
public void Run1()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(one));
|
||||||
|
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run2()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(one));
|
||||||
|
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(one); // add second.
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run3()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(one));
|
||||||
|
|
||||||
|
var two = new TestEvent(2);
|
||||||
|
var three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(one); // add thired.
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RemoveNext
|
||||||
|
{
|
||||||
|
TriggerEvent<int> ev;
|
||||||
|
|
||||||
|
public void Run1()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(two));
|
||||||
|
two = new TestEvent(2);
|
||||||
|
three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Count.Should().Be(0);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run2()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(two));
|
||||||
|
two = new TestEvent(2);
|
||||||
|
three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(one); // add second
|
||||||
|
ev.Add(three);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run3()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
one = new TestEvent(1, () => ev.Remove(two));
|
||||||
|
two = new TestEvent(2);
|
||||||
|
three = new TestEvent(3);
|
||||||
|
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(one); // add thired.
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RemoveNextNext
|
||||||
|
{
|
||||||
|
TriggerEvent<int> ev;
|
||||||
|
|
||||||
|
public void Run1()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
TestEvent four = default;
|
||||||
|
one = new TestEvent(1, () => { ev.Remove(two); ev.Remove(three); });
|
||||||
|
two = new TestEvent(2);
|
||||||
|
three = new TestEvent(3);
|
||||||
|
four = new TestEvent(4);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(four);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
two.NextCalled.Count.Should().Be(0);
|
||||||
|
three.NextCalled.Count.Should().Be(0);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run2()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
TestEvent four = default;
|
||||||
|
one = new TestEvent(1, () => { ev.Remove(one); ev.Remove(two); ev.Remove(three); });
|
||||||
|
two = new TestEvent(2);
|
||||||
|
three = new TestEvent(3);
|
||||||
|
four = new TestEvent(4);
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
ev.Add(two);
|
||||||
|
ev.Add(three);
|
||||||
|
ev.Add(four);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10);
|
||||||
|
two.NextCalled.Count.Should().Be(0);
|
||||||
|
three.NextCalled.Count.Should().Be(0);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(10, 20, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddMe
|
||||||
|
{
|
||||||
|
TriggerEvent<int> ev;
|
||||||
|
|
||||||
|
public void Run1()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
TestEvent four = default;
|
||||||
|
|
||||||
|
one = new TestEvent(1, () =>
|
||||||
|
{
|
||||||
|
if (two == null)
|
||||||
|
{
|
||||||
|
ev.Add(two = new TestEvent(2));
|
||||||
|
}
|
||||||
|
else if (three == null)
|
||||||
|
{
|
||||||
|
ev.Add(three = new TestEvent(3));
|
||||||
|
}
|
||||||
|
else if (four == null)
|
||||||
|
{
|
||||||
|
ev.Add(four = new TestEvent(4));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
ev.SetResult(40);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(30, 40);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(40);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Run2()
|
||||||
|
{
|
||||||
|
TestEvent one = default;
|
||||||
|
TestEvent two = default;
|
||||||
|
TestEvent three = default;
|
||||||
|
TestEvent four = default;
|
||||||
|
|
||||||
|
one = new TestEvent(1, () =>
|
||||||
|
{
|
||||||
|
if (two == null)
|
||||||
|
{
|
||||||
|
ev.Add(two = new TestEvent(2, () =>
|
||||||
|
{
|
||||||
|
if (three == null)
|
||||||
|
{
|
||||||
|
ev.Add(three = new TestEvent(3, () =>
|
||||||
|
{
|
||||||
|
if (four == null)
|
||||||
|
{
|
||||||
|
ev.Add(four = new TestEvent(4));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ev.Add(one);
|
||||||
|
|
||||||
|
ev.SetResult(10);
|
||||||
|
ev.SetResult(20);
|
||||||
|
ev.SetResult(30);
|
||||||
|
ev.SetResult(40);
|
||||||
|
|
||||||
|
one.NextCalled.Should().BeEquivalentTo(10, 20, 30, 40);
|
||||||
|
two.NextCalled.Should().BeEquivalentTo(20, 30, 40);
|
||||||
|
three.NextCalled.Should().BeEquivalentTo(30, 40);
|
||||||
|
four.NextCalled.Should().BeEquivalentTo(40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestEvent : ITriggerHandler<int>
|
||||||
|
{
|
||||||
|
public readonly int Id;
|
||||||
|
readonly Action iteratingEvent;
|
||||||
|
|
||||||
|
public TestEvent(int id)
|
||||||
|
{
|
||||||
|
this.Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestEvent(int id, Action iteratingEvent)
|
||||||
|
{
|
||||||
|
this.Id = id;
|
||||||
|
this.iteratingEvent = iteratingEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<int> NextCalled = new List<int>();
|
||||||
|
public List<Exception> ErrorCalled = new List<Exception>();
|
||||||
|
public List<object> CompletedCalled = new List<object>();
|
||||||
|
public List<CancellationToken> CancelCalled = new List<CancellationToken>();
|
||||||
|
|
||||||
|
public ITriggerHandler<int> Prev { get; set; }
|
||||||
|
public ITriggerHandler<int> Next { get; set; }
|
||||||
|
|
||||||
|
public void OnCanceled(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
CancelCalled.Add(cancellationToken);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted()
|
||||||
|
{
|
||||||
|
CompletedCalled.Add(new object());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnError(Exception ex)
|
||||||
|
{
|
||||||
|
ErrorCalled.Add(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnNext(int value)
|
||||||
|
{
|
||||||
|
NextCalled.Add(value);
|
||||||
|
iteratingEvent?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Id.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -120,6 +120,9 @@ namespace Cysharp.Threading.Tasks
|
||||||
|
|
||||||
public T Current => value;
|
public T Current => value;
|
||||||
|
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
public UniTask<bool> MoveNextAsync()
|
||||||
{
|
{
|
||||||
// raise latest value on first call.
|
// raise latest value on first call.
|
||||||
|
@ -300,6 +303,8 @@ namespace Cysharp.Threading.Tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Current => value;
|
public T Current => value;
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
public UniTask<bool> MoveNextAsync()
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,6 +115,8 @@ namespace Cysharp.Threading.Tasks.Linq
|
||||||
}
|
}
|
||||||
|
|
||||||
public TSource Current { get; private set; }
|
public TSource Current { get; private set; }
|
||||||
|
ITriggerHandler<TSource> ITriggerHandler<TSource>.Prev { get; set; }
|
||||||
|
ITriggerHandler<TSource> ITriggerHandler<TSource>.Next { get; set; }
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
public UniTask<bool> MoveNextAsync()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Cysharp.Threading.Tasks.Internal;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Cysharp.Threading.Tasks
|
namespace Cysharp.Threading.Tasks
|
||||||
|
@ -10,341 +9,283 @@ namespace Cysharp.Threading.Tasks
|
||||||
void OnError(Exception ex);
|
void OnError(Exception ex);
|
||||||
void OnCompleted();
|
void OnCompleted();
|
||||||
void OnCanceled(CancellationToken cancellationToken);
|
void OnCanceled(CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
// set/get from TriggerEvent<T>
|
||||||
|
ITriggerHandler<T> Prev { get; set; }
|
||||||
|
ITriggerHandler<T> Next { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// be careful to use, itself is struct.
|
// be careful to use, itself is struct.
|
||||||
public struct TriggerEvent<T>
|
public struct TriggerEvent<T>
|
||||||
{
|
{
|
||||||
// optimize: many cases, handler is single.
|
ITriggerHandler<T> head; // head.prev is last.
|
||||||
ITriggerHandler<T> singleHandler;
|
ITriggerHandler<T> iteratingHead;
|
||||||
|
|
||||||
ITriggerHandler<T>[] handlers;
|
bool preserveRemoveSelf;
|
||||||
|
ITriggerHandler<T> iteratingNode;
|
||||||
|
|
||||||
// when running(in TrySetResult), does not add immediately(trampoline).
|
|
||||||
bool isRunning;
|
void LogError(Exception ex)
|
||||||
ITriggerHandler<T> waitHandler;
|
{
|
||||||
MinimumQueue<ITriggerHandler<T>> waitQueue;
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
UnityEngine.Debug.LogException(ex);
|
||||||
|
#else
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
public void SetResult(T value)
|
public void SetResult(T value)
|
||||||
{
|
{
|
||||||
isRunning = true;
|
var h = head;
|
||||||
|
while (h != null)
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
{
|
||||||
|
iteratingNode = h;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
singleHandler.OnNext(value);
|
h.OnNext(value);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
#if UNITY_2018_3_OR_NEWER
|
LogError(ex);
|
||||||
UnityEngine.Debug.LogException(ex);
|
Remove(h);
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (handlers != null)
|
if (preserveRemoveSelf)
|
||||||
{
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (handlers[i] != null)
|
preserveRemoveSelf = false;
|
||||||
{
|
iteratingNode = null;
|
||||||
try
|
var next = h.Next;
|
||||||
{
|
Remove(h);
|
||||||
handlers[i].OnNext(value);
|
h = next;
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
handlers[i] = null;
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
{
|
||||||
Add(waitQueue.Dequeue());
|
h = h.Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iteratingNode = null;
|
||||||
|
if (iteratingHead != null)
|
||||||
|
{
|
||||||
|
Add(iteratingHead);
|
||||||
|
iteratingHead = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCanceled(CancellationToken cancellationToken)
|
public void SetCanceled(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
isRunning = true;
|
var h = head;
|
||||||
|
while (h != null)
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
{
|
||||||
|
iteratingNode = h;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(singleHandler).OnCanceled(cancellationToken);
|
h.OnCanceled(cancellationToken);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
#if UNITY_2018_3_OR_NEWER
|
LogError(ex);
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preserveRemoveSelf = false;
|
||||||
|
iteratingNode = null;
|
||||||
|
var next = h.Next;
|
||||||
|
Remove(h);
|
||||||
|
h = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlers != null)
|
iteratingNode = null;
|
||||||
|
if (iteratingHead != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
Add(iteratingHead);
|
||||||
{
|
iteratingHead = null;
|
||||||
if (handlers[i] != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
(handlers[i]).OnCanceled(cancellationToken);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
handlers[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
|
||||||
Add(waitQueue.Dequeue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCompleted()
|
public void SetCompleted()
|
||||||
{
|
{
|
||||||
isRunning = true;
|
var h = head;
|
||||||
|
while (h != null)
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
{
|
||||||
|
iteratingNode = h;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
(singleHandler).OnCompleted();
|
h.OnCompleted();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
#if UNITY_2018_3_OR_NEWER
|
LogError(ex);
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preserveRemoveSelf = false;
|
||||||
|
iteratingNode = null;
|
||||||
|
var next = h.Next;
|
||||||
|
Remove(h);
|
||||||
|
h = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlers != null)
|
iteratingNode = null;
|
||||||
|
if (iteratingHead != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
Add(iteratingHead);
|
||||||
{
|
iteratingHead = null;
|
||||||
if (handlers[i] != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
(handlers[i]).OnCompleted();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
handlers[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
|
||||||
Add(waitQueue.Dequeue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetError(Exception exception)
|
public void SetError(Exception exception)
|
||||||
{
|
{
|
||||||
isRunning = true;
|
var h = head;
|
||||||
|
while (h != null)
|
||||||
if (singleHandler != null)
|
|
||||||
{
|
{
|
||||||
|
iteratingNode = h;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
singleHandler.OnError(exception);
|
h.OnError(exception);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
#if UNITY_2018_3_OR_NEWER
|
LogError(ex);
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preserveRemoveSelf = false;
|
||||||
|
iteratingNode = null;
|
||||||
|
var next = h.Next;
|
||||||
|
Remove(h);
|
||||||
|
h = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlers != null)
|
iteratingNode = null;
|
||||||
|
if (iteratingHead != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
Add(iteratingHead);
|
||||||
{
|
iteratingHead = null;
|
||||||
if (handlers[i] != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handlers[i].OnError(exception);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
handlers[i] = null;
|
|
||||||
#if UNITY_2018_3_OR_NEWER
|
|
||||||
UnityEngine.Debug.LogException(ex);
|
|
||||||
#else
|
|
||||||
Console.WriteLine(ex);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isRunning = false;
|
|
||||||
|
|
||||||
if (waitHandler != null)
|
|
||||||
{
|
|
||||||
var h = waitHandler;
|
|
||||||
waitHandler = null;
|
|
||||||
Add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue != null)
|
|
||||||
{
|
|
||||||
while (waitQueue.Count != 0)
|
|
||||||
{
|
|
||||||
Add(waitQueue.Dequeue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(ITriggerHandler<T> handler)
|
public void Add(ITriggerHandler<T> handler)
|
||||||
{
|
{
|
||||||
if (isRunning)
|
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||||
{
|
|
||||||
if (waitHandler == null)
|
|
||||||
{
|
|
||||||
waitHandler = handler;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (waitQueue == null)
|
// zero node.
|
||||||
{
|
if (head == null)
|
||||||
waitQueue = new MinimumQueue<ITriggerHandler<T>>(4);
|
{
|
||||||
}
|
head = handler;
|
||||||
waitQueue.Enqueue(handler);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (singleHandler == null)
|
if (iteratingNode != null)
|
||||||
{
|
{
|
||||||
singleHandler = handler;
|
if (iteratingHead == null)
|
||||||
|
{
|
||||||
|
iteratingHead = handler;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var last = iteratingHead.Prev;
|
||||||
|
if (last == null)
|
||||||
|
{
|
||||||
|
// single node.
|
||||||
|
iteratingHead.Prev = handler;
|
||||||
|
iteratingHead.Next = handler;
|
||||||
|
handler.Prev = iteratingHead;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// multi node
|
||||||
|
iteratingHead.Prev = handler;
|
||||||
|
last.Next = handler;
|
||||||
|
handler.Prev = last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (handlers == null)
|
var last = head.Prev;
|
||||||
|
if (last == null)
|
||||||
{
|
{
|
||||||
handlers = new ITriggerHandler<T>[4];
|
// single node.
|
||||||
|
head.Prev = handler;
|
||||||
|
head.Next = handler;
|
||||||
|
handler.Prev = head;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// check empty
|
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (handlers[i] == null)
|
// multi node
|
||||||
{
|
head.Prev = handler;
|
||||||
handlers[i] = handler;
|
last.Next = handler;
|
||||||
return;
|
handler.Prev = last;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// full, ensure capacity
|
|
||||||
var last = handlers.Length;
|
|
||||||
{
|
|
||||||
EnsureCapacity(ref handlers);
|
|
||||||
handlers[last] = handler;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EnsureCapacity(ref ITriggerHandler<T>[] array)
|
|
||||||
{
|
|
||||||
var newSize = array.Length * 2;
|
|
||||||
var newArray = new ITriggerHandler<T>[newSize];
|
|
||||||
Array.Copy(array, 0, newArray, 0, array.Length);
|
|
||||||
array = newArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(ITriggerHandler<T> handler)
|
public void Remove(ITriggerHandler<T> handler)
|
||||||
{
|
{
|
||||||
if (singleHandler == handler)
|
if (handler == null) throw new ArgumentNullException(nameof(handler));
|
||||||
|
|
||||||
|
if (iteratingNode != null && iteratingNode == handler)
|
||||||
{
|
{
|
||||||
singleHandler = null;
|
// if remove self, reserve remove self after invoke completed.
|
||||||
|
preserveRemoveSelf = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (handlers != null)
|
var prev = handler.Prev;
|
||||||
|
var next = handler.Next;
|
||||||
|
|
||||||
|
if (next != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < handlers.Length; i++)
|
next.Prev = prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handler == head)
|
||||||
|
{
|
||||||
|
head = next;
|
||||||
|
}
|
||||||
|
else if (handler == iteratingHead)
|
||||||
|
{
|
||||||
|
iteratingHead = next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// when handler is head, prev indicate last so don't use it.
|
||||||
|
if (prev != null)
|
||||||
{
|
{
|
||||||
if (handlers[i] == handler)
|
prev.Next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head != null)
|
||||||
|
{
|
||||||
|
if (head.Prev == handler)
|
||||||
|
{
|
||||||
|
if (prev != head)
|
||||||
{
|
{
|
||||||
// fill null.
|
head.Prev = prev;
|
||||||
handlers[i] = null;
|
}
|
||||||
return;
|
else
|
||||||
|
{
|
||||||
|
head.Prev = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (iteratingHead != null)
|
||||||
|
{
|
||||||
|
if (iteratingHead.Prev == handler)
|
||||||
|
{
|
||||||
|
if (prev != iteratingHead.Prev)
|
||||||
|
{
|
||||||
|
iteratingHead.Prev = prev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iteratingHead.Prev = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.Prev = null;
|
||||||
|
handler.Next = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,8 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Current { get; private set; }
|
public T Current { get; private set; }
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||||
|
|
||||||
public UniTask<bool> MoveNextAsync()
|
public UniTask<bool> MoveNextAsync()
|
||||||
{
|
{
|
||||||
|
@ -189,6 +191,9 @@ namespace Cysharp.Threading.Tasks.Triggers
|
||||||
|
|
||||||
internal CancellationToken CancellationToken => cancellationToken;
|
internal CancellationToken CancellationToken => cancellationToken;
|
||||||
|
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Prev { get; set; }
|
||||||
|
ITriggerHandler<T> ITriggerHandler<T>.Next { get; set; }
|
||||||
|
|
||||||
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
|
internal AsyncTriggerHandler(AsyncTriggerBase<T> trigger, bool callOnce)
|
||||||
{
|
{
|
||||||
if (cancellationToken.IsCancellationRequested)
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
|
|
@ -67,12 +67,12 @@ namespace Cysharp.Threading.Tasks
|
||||||
|
|
||||||
public static ReturnToSynchronizationContext ReturnToSynchronizationContext(SynchronizationContext synchronizationContext)
|
public static ReturnToSynchronizationContext ReturnToSynchronizationContext(SynchronizationContext synchronizationContext)
|
||||||
{
|
{
|
||||||
return new ReturnToSynchronizationContext(synchronizationContext);
|
return new ReturnToSynchronizationContext(synchronizationContext, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReturnToSynchronizationContext ReturnToCurrentSynchronizationContext()
|
public static ReturnToSynchronizationContext ReturnToCurrentSynchronizationContext(bool dontPostWhenSameContext = true)
|
||||||
{
|
{
|
||||||
return new ReturnToSynchronizationContext(SynchronizationContext.Current);
|
return new ReturnToSynchronizationContext(SynchronizationContext.Current, dontPostWhenSameContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,15 +319,67 @@ namespace Cysharp.Threading.Tasks
|
||||||
public struct ReturnToSynchronizationContext
|
public struct ReturnToSynchronizationContext
|
||||||
{
|
{
|
||||||
readonly SynchronizationContext syncContext;
|
readonly SynchronizationContext syncContext;
|
||||||
|
readonly bool dontPostWhenSameContext;
|
||||||
|
|
||||||
public ReturnToSynchronizationContext(SynchronizationContext syncContext)
|
public ReturnToSynchronizationContext(SynchronizationContext syncContext, bool dontPostWhenSameContext)
|
||||||
{
|
{
|
||||||
this.syncContext = syncContext;
|
this.syncContext = syncContext;
|
||||||
|
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SwitchToSynchronizationContextAwaitable DisposeAsync()
|
public Awaiter DisposeAsync()
|
||||||
{
|
{
|
||||||
return UniTask.SwitchToSynchronizationContext(syncContext);
|
return new Awaiter(syncContext, dontPostWhenSameContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Awaiter : ICriticalNotifyCompletion
|
||||||
|
{
|
||||||
|
static readonly SendOrPostCallback switchToCallback = Callback;
|
||||||
|
|
||||||
|
readonly SynchronizationContext synchronizationContext;
|
||||||
|
readonly bool dontPostWhenSameContext;
|
||||||
|
|
||||||
|
public Awaiter(SynchronizationContext synchronizationContext, bool dontPostWhenSameContext)
|
||||||
|
{
|
||||||
|
this.synchronizationContext = synchronizationContext;
|
||||||
|
this.dontPostWhenSameContext = dontPostWhenSameContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Awaiter GetAwaiter() => this;
|
||||||
|
|
||||||
|
public bool IsCompleted
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var current = SynchronizationContext.Current;
|
||||||
|
if (current == synchronizationContext)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult() { }
|
||||||
|
|
||||||
|
public void OnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
synchronizationContext.Post(switchToCallback, continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnsafeOnCompleted(Action continuation)
|
||||||
|
{
|
||||||
|
synchronizationContext.Post(switchToCallback, continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Callback(object state)
|
||||||
|
{
|
||||||
|
var continuation = (Action)state;
|
||||||
|
continuation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue