From 5fbcdb7544bba5b0260c8783fa1febb0f7e9edfa Mon Sep 17 00:00:00 2001 From: Joseph Ivie Date: Wed, 4 Dec 2024 09:20:42 -0700 Subject: [PATCH] Shared bug fix --- .../kiteui/reactive/DependencyTracker.kt | 1 + .../kiteui/reactive/SharedReadable.kt | 11 +++++- .../kiteui/reactive/SharedTest.kt | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/DependencyTracker.kt b/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/DependencyTracker.kt index 25deacc1..aa11d74f 100644 --- a/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/DependencyTracker.kt +++ b/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/DependencyTracker.kt @@ -25,6 +25,7 @@ abstract class DependencyTracker{ open fun cancel() { dependencies.forEach { it.second() } dependencies.clear() + log?.log("Cleared dependencies") } protected fun dependencyBlockStart() { diff --git a/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/SharedReadable.kt b/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/SharedReadable.kt index ad784732..eece2e68 100644 --- a/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/SharedReadable.kt +++ b/library/src/commonMain/kotlin/com/lightningkite/kiteui/reactive/SharedReadable.kt @@ -2,6 +2,7 @@ package com.lightningkite.kiteui.reactive +import com.lightningkite.kiteui.Console import com.lightningkite.kiteui.InternalKiteUi import com.lightningkite.kiteui.printStackTrace2 import com.lightningkite.kiteui.report @@ -18,6 +19,7 @@ fun shared(coroutineContext: CoroutineContext = Dispatchers.Unconfined, useL class SharedReadable( coroutineContext: CoroutineContext = Dispatchers.Unconfined, + val log: Console? = null, useLastWhileLoading: Boolean = false, private val action: ReactiveContext.() -> T ) : Readable, CalculationContext { @@ -29,11 +31,13 @@ class SharedReadable( throwable.report("SharedReadable") } } - override val coroutineContext = job + restOfContext +// override val coroutineContext = job + restOfContext + override val coroutineContext get() = job + restOfContext private fun cancel() { job.cancel() job = Job() + scope.cancel() } private val scope = TypedReactiveContext(this, action = action) @@ -45,16 +49,21 @@ class SharedReadable( } private var lcount = 0 override fun addListener(listener: () -> Unit): () -> Unit { + log?.log("addListener $lcount $listener") if (lcount++ == 0) { + log?.log("startCalculation") scope.startCalculation() } val r = scope.addListener(listener) var removed = false return label@{ + log?.log("remover called ($removed) for $listener") if(removed) return@label removed = true + log?.log("remover activated ($removed, $lcount) for $listener") r() if (--lcount == 0) { + log?.log("cancelling") cancel() } } diff --git a/library/src/commonTest/kotlin/com/lightningkite/kiteui/reactive/SharedTest.kt b/library/src/commonTest/kotlin/com/lightningkite/kiteui/reactive/SharedTest.kt index 1ae23d8f..ae121d97 100644 --- a/library/src/commonTest/kotlin/com/lightningkite/kiteui/reactive/SharedTest.kt +++ b/library/src/commonTest/kotlin/com/lightningkite/kiteui/reactive/SharedTest.kt @@ -58,6 +58,43 @@ class SharedTest { assertEquals(1, onRemoveCalled) } + @Test fun sharedTerminatesWhenNoOneIsListeningCancelDeps() { + var onRemoveCalled = 0 + var scopeCalled = 0 + var dependencyListeners = 0 + val listener = object: Listenable { + override fun addListener(listener: () -> Unit): () -> Unit { + dependencyListeners++ + return { dependencyListeners-- } + } + } + val shared = shared { + rerunOn(listener) + scopeCalled++ + onRemove { onRemoveCalled++ } + 42 + } + assertEquals(0, scopeCalled) + assertEquals(0, onRemoveCalled) + assertEquals(0, dependencyListeners) + var removeListener = shared.addListener { } + assertEquals(1, dependencyListeners) + assertEquals(1, scopeCalled) + assertEquals(0, onRemoveCalled) + removeListener() + assertEquals(0, dependencyListeners) + assertEquals(1, scopeCalled) + assertEquals(1, onRemoveCalled) + removeListener = shared.addListener { } + assertEquals(1, dependencyListeners) + assertEquals(2, scopeCalled) + assertEquals(1, onRemoveCalled) + removeListener() + assertEquals(0, dependencyListeners) + assertEquals(2, scopeCalled) + assertEquals(2, onRemoveCalled) + } + @Test fun sharedSharesCalculations() { var hits = 0 val property = Property(1)