mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-03 13:58:28 +08:00
Added some observe extension methods, added a mutation test and removed old commented-out code.
This commit is contained in:
parent
c33d8c0b77
commit
4a2b859cad
@ -48,10 +48,46 @@ fun <T> mutableCell(getter: () -> T, setter: (T) -> Unit): MutableCell<T> =
|
||||
fun <T> Cell<T>.observe(observer: (T) -> Unit): Disposable =
|
||||
observeChange { observer(it.value) }
|
||||
|
||||
fun <T1, T2> observe(
|
||||
c1: Cell<T1>,
|
||||
c2: Cell<T2>,
|
||||
observer: (T1, T2) -> Unit,
|
||||
): Disposable =
|
||||
CallbackObserver(c1, c2) { observer(c1.value, c2.value) }
|
||||
|
||||
fun <T1, T2, T3> observe(
|
||||
c1: Cell<T1>,
|
||||
c2: Cell<T2>,
|
||||
c3: Cell<T3>,
|
||||
observer: (T1, T2, T3) -> Unit,
|
||||
): Disposable =
|
||||
CallbackObserver(c1, c2, c3) { observer(c1.value, c2.value, c3.value) }
|
||||
|
||||
fun <T1, T2, T3, T4> observe(
|
||||
c1: Cell<T1>,
|
||||
c2: Cell<T2>,
|
||||
c3: Cell<T3>,
|
||||
c4: Cell<T4>,
|
||||
observer: (T1, T2, T3, T4) -> Unit,
|
||||
): Disposable =
|
||||
CallbackObserver(c1, c2, c3, c4) { observer(c1.value, c2.value, c3.value, c4.value) }
|
||||
|
||||
fun <T1, T2, T3, T4, T5> observe(
|
||||
c1: Cell<T1>,
|
||||
c2: Cell<T2>,
|
||||
c3: Cell<T3>,
|
||||
c4: Cell<T4>,
|
||||
c5: Cell<T5>,
|
||||
observer: (T1, T2, T3, T4, T5) -> Unit,
|
||||
): Disposable =
|
||||
CallbackObserver(c1, c2, c3, c4, c5) {
|
||||
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
||||
}
|
||||
|
||||
fun <T> Cell<T>.observeNow(
|
||||
observer: (T) -> Unit,
|
||||
): Disposable {
|
||||
val disposable = observeChange { observer(it.value) }
|
||||
val disposable = observe(observer)
|
||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||
observer(value)
|
||||
return disposable
|
||||
@ -62,7 +98,7 @@ fun <T1, T2> observeNow(
|
||||
c2: Cell<T2>,
|
||||
observer: (T1, T2) -> Unit,
|
||||
): Disposable {
|
||||
val disposable = CallbackObserver(c1, c2) { observer(c1.value, c2.value) }
|
||||
val disposable = observe(c1, c2, observer)
|
||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||
observer(c1.value, c2.value)
|
||||
return disposable
|
||||
@ -74,7 +110,7 @@ fun <T1, T2, T3> observeNow(
|
||||
c3: Cell<T3>,
|
||||
observer: (T1, T2, T3) -> Unit,
|
||||
): Disposable {
|
||||
val disposable = CallbackObserver(c1, c2, c3) { observer(c1.value, c2.value, c3.value) }
|
||||
val disposable = observe(c1, c2, c3, observer)
|
||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||
observer(c1.value, c2.value, c3.value)
|
||||
return disposable
|
||||
@ -87,8 +123,7 @@ fun <T1, T2, T3, T4> observeNow(
|
||||
c4: Cell<T4>,
|
||||
observer: (T1, T2, T3, T4) -> Unit,
|
||||
): Disposable {
|
||||
val disposable =
|
||||
CallbackObserver(c1, c2, c3, c4) { observer(c1.value, c2.value, c3.value, c4.value) }
|
||||
val disposable = observe(c1, c2, c3, c4, observer)
|
||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||
observer(c1.value, c2.value, c3.value, c4.value)
|
||||
return disposable
|
||||
@ -102,9 +137,7 @@ fun <T1, T2, T3, T4, T5> observeNow(
|
||||
c5: Cell<T5>,
|
||||
observer: (T1, T2, T3, T4, T5) -> Unit,
|
||||
): Disposable {
|
||||
val disposable = CallbackObserver(c1, c2, c3, c4, c5) {
|
||||
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
||||
}
|
||||
val disposable = observe(c1, c2, c3, c4, c5, observer)
|
||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
||||
return disposable
|
||||
|
@ -2,12 +2,7 @@ package world.phantasmal.cell
|
||||
|
||||
import world.phantasmal.cell.test.CellTestSuite
|
||||
import world.phantasmal.core.disposable.use
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.*
|
||||
|
||||
/**
|
||||
* Test suite for all [Cell] implementations. There is a subclass of this suite for every [Cell]
|
||||
@ -243,7 +238,7 @@ interface CellTests : CellTestSuite {
|
||||
}
|
||||
)
|
||||
|
||||
// Repeat 3 times to check if temporary state is always reset.
|
||||
// Repeat 3 times to check that temporary state is always reset.
|
||||
repeat(3) {
|
||||
changes = 0
|
||||
|
||||
@ -261,6 +256,37 @@ interface CellTests : CellTestSuite {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When two dependencies of an observer are changed in a single mutation, the observer is called
|
||||
* just once.
|
||||
*/
|
||||
@Test
|
||||
fun changing_two_dependencies_during_a_mutation_results_in_one_callback_call() = test {
|
||||
val p1 = createProvider()
|
||||
val p2 = createProvider()
|
||||
var callbackCalled = 0
|
||||
|
||||
disposer.add(
|
||||
observe(p1.cell, p2.cell) { _, _ -> callbackCalled++ }
|
||||
)
|
||||
|
||||
// Repeat 3 times to check that temporary state is always reset.
|
||||
repeat(3) {
|
||||
callbackCalled = 0
|
||||
|
||||
mutate {
|
||||
p1.emit()
|
||||
p2.emit()
|
||||
|
||||
// Change should be deferred until this mutation finishes.
|
||||
assertEquals(0, callbackCalled)
|
||||
}
|
||||
|
||||
// All changes should result in a single callback call.
|
||||
assertEquals(1, callbackCalled)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun value_can_be_accessed_during_a_mutation() = test {
|
||||
val p = createProvider()
|
||||
|
@ -25,118 +25,6 @@ interface MutableCellTests<T : Any> : CellTests {
|
||||
assertEquals(newValue, observedValue)
|
||||
}
|
||||
|
||||
// TODO: Figure out change set bug and enable change sets again.
|
||||
/**
|
||||
* Modifying mutable cells in a change set doesn't result in calls to
|
||||
* [Dependent.dependencyChanged] of their dependents until the change set is completed.
|
||||
*/
|
||||
// @Test
|
||||
// fun cell_changes_in_change_set_dont_immediately_produce_dependencyChanged_calls() = test {
|
||||
// val dependencies = (1..5).map { createProvider() }
|
||||
//
|
||||
// var dependencyMightChangeCount = 0
|
||||
// var dependencyChangedCount = 0
|
||||
//
|
||||
// val dependent = object : Dependent {
|
||||
// override fun dependencyMightChange() {
|
||||
// dependencyMightChangeCount++
|
||||
// }
|
||||
//
|
||||
// override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) {
|
||||
// dependencyChangedCount++
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// for (dependency in dependencies) {
|
||||
// dependency.observable.addDependent(dependent)
|
||||
// }
|
||||
//
|
||||
// change {
|
||||
// for (dependency in dependencies) {
|
||||
// dependency.observable.value = dependency.createValue()
|
||||
// }
|
||||
//
|
||||
// // Calls to dependencyMightChange happen immediately.
|
||||
// assertEquals(dependencies.size, dependencyMightChangeCount)
|
||||
// // Calls to dependencyChanged happen later.
|
||||
// assertEquals(0, dependencyChangedCount)
|
||||
// }
|
||||
//
|
||||
// assertEquals(dependencies.size, dependencyMightChangeCount)
|
||||
// assertEquals(dependencies.size, dependencyChangedCount)
|
||||
// }
|
||||
|
||||
// TODO: Figure out change set bug and enable change sets again.
|
||||
/**
|
||||
* Modifying a mutable cell multiple times in one change set results in a single call to
|
||||
* [Dependent.dependencyInvalidated] and [Dependent.dependencyChanged].
|
||||
*/
|
||||
// @Test
|
||||
// fun multiple_changes_to_one_cell_in_change_set() = test {
|
||||
// val dependency = createProvider()
|
||||
//
|
||||
// var dependencyMightChangeCount = 0
|
||||
// var dependencyChangedCount = 0
|
||||
//
|
||||
// val dependent = object : Dependent {
|
||||
// override fun dependencyMightChange() {
|
||||
// dependencyMightChangeCount++
|
||||
// }
|
||||
//
|
||||
// override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) {
|
||||
// dependencyChangedCount++
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// dependency.observable.addDependent(dependent)
|
||||
//
|
||||
// // Change the dependency multiple times in a transaction.
|
||||
// change {
|
||||
// repeat(5) {
|
||||
// dependency.observable.value = dependency.createValue()
|
||||
// }
|
||||
//
|
||||
// // Calls to dependencyMightChange happen immediately.
|
||||
// assertEquals(1, dependencyMightChangeCount)
|
||||
// // Calls to dependencyChanged happen later.
|
||||
// assertEquals(0, dependencyChangedCount)
|
||||
// }
|
||||
//
|
||||
// assertEquals(1, dependencyMightChangeCount)
|
||||
// assertEquals(1, dependencyChangedCount)
|
||||
// }
|
||||
|
||||
// TODO: Figure out change set bug and enable change sets again.
|
||||
/**
|
||||
* Modifying two mutable cells in a change set results in a single recomputation of their
|
||||
* dependent.
|
||||
*/
|
||||
// @Test
|
||||
// fun modifying_two_cells_together_results_in_one_recomputation() = test {
|
||||
// val dependency1 = createProvider()
|
||||
// val dependency2 = createProvider()
|
||||
//
|
||||
// var computeCount = 0
|
||||
//
|
||||
// val dependent = DependentCell(dependency1.observable, dependency2.observable) {
|
||||
// computeCount++
|
||||
// Unit
|
||||
// }
|
||||
//
|
||||
// // Observe dependent to ensure it gets recomputed when its dependencies change.
|
||||
// disposer.add(dependent.observe {})
|
||||
//
|
||||
// // DependentCell's compute function is called once when we start observing.
|
||||
// assertEquals(1, computeCount)
|
||||
//
|
||||
// change {
|
||||
// dependency1.observable.value = dependency1.createValue()
|
||||
// dependency2.observable.value = dependency2.createValue()
|
||||
// }
|
||||
//
|
||||
// assertEquals(2, computeCount)
|
||||
// }
|
||||
|
||||
interface Provider<T : Any> : CellTests.Provider {
|
||||
override val cell: MutableCell<T>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user