From e3ed0f5b53e53175a8219f058c349f6232e60eae Mon Sep 17 00:00:00 2001 From: Gene Pavlovsky Date: Mon, 26 Feb 2024 11:10:48 +0100 Subject: [PATCH 1/3] Update haxe to 4.3.3, tink_core to 2.1.1 --- .haxerc | 2 +- haxe_libraries/tink_core.hxml | 6 +++--- tests.hxml | 1 - tests/TestArrays.hx | 8 ++++---- tests/TestAuto.hx | 14 +++++++------- tests/TestBasic.hx | 5 ++++- tests/TestDate.hx | 8 ++++---- tests/TestScheduler.hx | 4 ++-- 8 files changed, 25 insertions(+), 23 deletions(-) diff --git a/.haxerc b/.haxerc index f8137ff..3ee99dd 100644 --- a/.haxerc +++ b/.haxerc @@ -1,4 +1,4 @@ { - "version": "4.2.0", + "version": "4.3.3", "resolveLibs": "scoped" } \ No newline at end of file diff --git a/haxe_libraries/tink_core.hxml b/haxe_libraries/tink_core.hxml index 0a415b3..4fa6607 100644 --- a/haxe_libraries/tink_core.hxml +++ b/haxe_libraries/tink_core.hxml @@ -1,3 +1,3 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_core#e0ed6c33f6f396fb83397a590bee4c3d48ab2e17" into tink_core/2.0.2/github/e0ed6c33f6f396fb83397a590bee4c3d48ab2e17 --cp ${HAXE_LIBCACHE}/tink_core/2.0.2/github/e0ed6c33f6f396fb83397a590bee4c3d48ab2e17/src --D tink_core=2.0.2 \ No newline at end of file +# @install: lix --silent download "haxelib:/tink_core#2.1.1" into tink_core/2.1.1/haxelib +-cp ${HAXE_LIBCACHE}/tink_core/2.1.1/haxelib/src +-D tink_core=2.1.1 \ No newline at end of file diff --git a/tests.hxml b/tests.hxml index 26f6852..cfa47b8 100644 --- a/tests.hxml +++ b/tests.hxml @@ -1,4 +1,3 @@ --cp src -cp tests -D no-deprecation-warnings -lib tink_unittest diff --git a/tests/TestArrays.hx b/tests/TestArrays.hx index 533b7cb..dcbe907 100644 --- a/tests/TestArrays.hx +++ b/tests/TestArrays.hx @@ -3,9 +3,9 @@ package ; import tink.state.*; import tink.state.Scheduler.direct; -using tink.CoreApi; using Lambda; using StringTools; +using tink.CoreApi; @:asserts class TestArrays { @@ -97,7 +97,7 @@ class TestArrays { .bind(() -> keysChanges++, direct); Observable.auto(() -> { - final first = 0; + var first = 0; for (v in a) { first += v; break; @@ -131,7 +131,7 @@ class TestArrays { public function clear() { final o = new ObservableArray>([1,2,3]); - final log = ''; + var log = ''; Observable.auto(() -> o.length).bind(v -> log += 'len:$v', direct); for(i in 0...o.length) o.entry(i).bind(v -> log += ',$i:$v', direct); @@ -152,4 +152,4 @@ class TestArrays { asserts.assert(v.value == '0:20:30:40:50:60:70:80:90:123:'); return asserts.done(); } -} \ No newline at end of file +} diff --git a/tests/TestAuto.hx b/tests/TestAuto.hx index 5a6ea9d..b8905ea 100644 --- a/tests/TestAuto.hx +++ b/tests/TestAuto.hx @@ -1,9 +1,9 @@ package; -import tink.state.Scheduler.direct; -import tink.state.Promised; -import tink.state.Observable; import tink.state.*; +import tink.state.Observable; +import tink.state.Promised; +import tink.state.Scheduler.direct; using tink.CoreApi; @@ -89,9 +89,9 @@ class TestAuto { function inc() counter.set(counter.value + 1); - var last = None; + var last:Option<{ t:Int, c:Int }> = None; - final o = Observable.auto(l -> { + final o = Observable.auto((l:Option<{ t:Int, c:Int }>) -> { final t = new FutureTrigger(); last = l; triggers.push(t); @@ -231,7 +231,7 @@ class TestAuto { final select = new State([for (i in 0...states.length) i % 3 == 0]); function add() { - final ret = 0; + var ret = 0; for (i => s in select.value) if (s) ret += states[i].value; return ret; @@ -258,4 +258,4 @@ class TestAuto { return asserts.done(); } -} \ No newline at end of file +} diff --git a/tests/TestBasic.hx b/tests/TestBasic.hx index 8f23719..1679123 100644 --- a/tests/TestBasic.hx +++ b/tests/TestBasic.hx @@ -13,7 +13,7 @@ class TestBasic { public function donotFireEqual() { final s = new State(0), sLog = []; - final watch = s.observe().bind(sLog.push, (_, _) -> true, direct); + var watch = s.observe().bind(sLog.push, (_, _) -> true, direct); final o1Log = [], o1 = Observable.auto(() -> { @@ -127,6 +127,9 @@ class TestBasic { asserts.assert(fired == 4); await(o.nextTime({ hires: true, })); + + asserts.assert(fired == 4); + set(0); asserts.assert(fired == 5); diff --git a/tests/TestDate.hx b/tests/TestDate.hx index 89ebc43..8ad3bc8 100644 --- a/tests/TestDate.hx +++ b/tests/TestDate.hx @@ -1,10 +1,10 @@ package ; -import tink.state.*; import deepequal.DeepEqual.*; +import tink.state.*; -using tink.CoreApi; using DateTools; +using tink.CoreApi; @:asserts class TestDate { @@ -15,7 +15,7 @@ class TestDate { final d = new ObservableDate(), log = []; - final watch = d.becomesOlderThan(1.seconds()).bind(log.push); + var watch = d.becomesOlderThan(1.seconds()).bind(log.push); watch &= d.becomesOlderThan(10.seconds()).bind(log.push); Observable.updateAll(); @@ -27,4 +27,4 @@ class TestDate { return asserts.done(); }); } -} \ No newline at end of file +} diff --git a/tests/TestScheduler.hx b/tests/TestScheduler.hx index 0135312..6573723 100644 --- a/tests/TestScheduler.hx +++ b/tests/TestScheduler.hx @@ -36,7 +36,7 @@ class TestScheduler { final log = []; - final watch = s1.observe().bind(v -> { + var watch = s1.observe().bind(v -> { s2.set('foo($v)'); s3.set('bar($v)'); }); @@ -83,4 +83,4 @@ class TestScheduler { return asserts.done(); } -} \ No newline at end of file +} From 46cc001772f19879261682cf551cb48681fd29d8 Mon Sep 17 00:00:00 2001 From: Gene Pavlovsky Date: Mon, 26 Feb 2024 11:11:16 +0100 Subject: [PATCH 2/3] Actually skip the current value for nextTime when `condition` is null --- src/tink/state/Observable.hx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tink/state/Observable.hx b/src/tink/state/Observable.hx index 090aa9d..f21d01e 100644 --- a/src/tink/state/Observable.hx +++ b/src/tink/state/Observable.hx @@ -78,14 +78,16 @@ abstract Observable(ObservableObject) from ObservableObject to Observab return Observable.auto(() -> f(value, that.value)); public function nextTime(?options:{ ?butNotNow: Bool, ?hires:Bool }, ?condition:T->Bool):Future - return getNext(options, - if (condition == null) Some - else v -> if (condition(v)) Some(v) else None - ); + return + if (condition == null) { + var i = 0; + getNext({ butNotNow: true, hires: options?.hires ?? false }, v -> if (i++ == 0) None else Some(v)); + } + else getNext(options, v -> if (condition(v)) Some(v) else None); public function getNext(?options:{ ?butNotNow: Bool, ?hires:Bool }, select:T->Option):Future { var ret = Future.trigger(), - waiting = options != null && options.butNotNow; + waiting = options?.butNotNow; var link = bind(value -> { var out = select(value); @@ -95,7 +97,7 @@ abstract Observable(ObservableObject) from ObservableObject to Observab case Some(value): ret.trigger(value); case None: } - }, if (options != null && options.hires) Scheduler.direct else null); + }, if (options?.hires) Scheduler.direct else null); ret.handle(link.cancel); From c765f74999dc3b89ea856af57a590ea079866363 Mon Sep 17 00:00:00 2001 From: Gene Pavlovsky Date: Mon, 26 Feb 2024 11:18:20 +0100 Subject: [PATCH 3/3] Add `butNotNow` warning --- src/tink/state/Observable.hx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tink/state/Observable.hx b/src/tink/state/Observable.hx index f21d01e..ab5d2d2 100644 --- a/src/tink/state/Observable.hx +++ b/src/tink/state/Observable.hx @@ -77,6 +77,14 @@ abstract Observable(ObservableObject) from ObservableObject to Observab public function combine(that:Observable, f:T->A->R):Observable return Observable.auto(() -> f(value, that.value)); + /** + * Be careful with `butNotNow`, its semantics are a bit counter-intuitive: + * If the condition returns true for the current value, it will skip the current value, + * then all future values as long as the condition keeps returning true, + * then the first and all consecutive future values for which the condition returns false. + * Example: If the condition is `v -> v > 0`, and the values sequence is [ 0, 10, 20, -1, -2, 42 ], + * the future will resolve to 42. + */ public function nextTime(?options:{ ?butNotNow: Bool, ?hires:Bool }, ?condition:T->Bool):Future return if (condition == null) { @@ -85,6 +93,7 @@ abstract Observable(ObservableObject) from ObservableObject to Observab } else getNext(options, v -> if (condition(v)) Some(v) else None); + // Be careful with `butNotNow`, its semantics has the same peculiarity as when using `nextTime`, see the comments above. public function getNext(?options:{ ?butNotNow: Bool, ?hires:Bool }, select:T->Option):Future { var ret = Future.trigger(), waiting = options?.butNotNow;