Skip to content

Commit

Permalink
Swap between two List for the UnityBatchScheduler queues instead of a…
Browse files Browse the repository at this point in the history
…llocating a new one each time (closes #19)

Also add tests for the case of one binding scheduling another
  • Loading branch information
nadako committed Jun 13, 2023
1 parent 3d10b19 commit 71c0e3b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 4 deletions.
11 changes: 8 additions & 3 deletions src/TinkState-Unity/Runtime/UnityBatchScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static void OnUpdate()
static readonly UnityBatchScheduler Instance = new UnityBatchScheduler();

List<Schedulable> queue = new List<Schedulable>();
List<Schedulable> nextQueue = new List<Schedulable>();
bool scheduled;

UnityBatchScheduler() { }
Expand All @@ -45,9 +46,13 @@ void Progress(float maxSeconds)
var end = GetTimeStamp() + maxSeconds;
do
{
var old = queue;
queue = new List<Schedulable>();
foreach (var o in old) o.Run();
// to handle the unfortunate case where a binding invocation schedules another one
// we have two queues and swap between them to avoid allocating a new list every time
var currentQueue = queue;
queue = nextQueue;
foreach (var o in currentQueue) o.Run();
currentQueue.Clear();
nextQueue = currentQueue;
}
while (queue.Count > 0 && GetTimeStamp() < end);

Expand Down
42 changes: 41 additions & 1 deletion src/TinkState-Unity/Tests/TestUnityBatchScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using NUnit.Framework;
using UnityEngine.TestTools;
using TinkState;
using UnityEngine;

public class TestUnityBatchScheduler
{
Expand Down Expand Up @@ -64,4 +65,43 @@ public IEnumerator TestBindingNotInvokedIfFinalValueIsSame()
yield return null;
Assert.That(bindingCalls, Is.EqualTo(1));
}
}

// NOTE: this is not an intended usage for bindings, as one shouldn't
// trigger bindings from other bindings (e.g. by changing a State) and
// instead make use of auto-Observables and such, but we still test
// that this works as expected and doesn't hang
[UnityTest]
public IEnumerator TestTriggerBindingFromBinding()
{
var s = Observable.State(2);
var s2 = Observable.State(2);

var bindingCalls = 0;
var expectedValue = 2;
void BindCallback(int value)
{
bindingCalls++;
Assert.That(value, Is.EqualTo(expectedValue));
}

s2.Bind(BindCallback);
Assert.That(bindingCalls, Is.EqualTo(1));

s.Bind(v => s2.Value = v * 2);

// first binding was still not called because it's scheduled!
Assert.That(bindingCalls, Is.EqualTo(1));

// it will be called as scheduled though
expectedValue = 4;
yield return null;
Assert.That(bindingCalls, Is.EqualTo(2));

// changing the value will invoke the binding for `s` which will in its turn schedule the binding for `s2`,
// which should be processed right after, let's check that
s.Value = 3;
expectedValue = 6;
yield return null;
Assert.That(bindingCalls, Is.EqualTo(3));
}
}
38 changes: 38 additions & 0 deletions src/TinkState/Tests/TestTriggerBindingFromBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using NUnit.Framework;
using TinkState;

namespace Test
{
// NOTE: this is not an intended usage for bindings, as one shouldn't
// trigger bindings from other bindings (e.g. by changing a State) and
// instead make use of auto-Observables and such, but we still test
// that this works as expected and doesn't hang
class TestTriggerBindingFromBinding : BaseTest
{
[Test]
public void Test()
{
var s = Observable.State(2);
var s2 = Observable.State(2);

var bindingCalls = 0;
var expectedValue = 2;
void BindCallback(int value)
{
bindingCalls++;
Assert.That(value, Is.EqualTo(expectedValue));
}

s2.Bind(BindCallback);
Assert.That(bindingCalls, Is.EqualTo(1));

expectedValue = 4;
s.Bind(v => s2.Value = v * 2);
Assert.That(bindingCalls, Is.EqualTo(2));

expectedValue = 6;
s.Value = 3;
Assert.That(bindingCalls, Is.EqualTo(3));
}
}
}
3 changes: 3 additions & 0 deletions src/TinkState/Tests/TestTriggerBindingFromBinding.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 71c0e3b

Please sign in to comment.