mirror of
https://github.com/DaanVandenBosch/phantasmal-world.git
synced 2025-04-04 06:28: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 =
|
fun <T> Cell<T>.observe(observer: (T) -> Unit): Disposable =
|
||||||
observeChange { observer(it.value) }
|
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(
|
fun <T> Cell<T>.observeNow(
|
||||||
observer: (T) -> Unit,
|
observer: (T) -> Unit,
|
||||||
): Disposable {
|
): Disposable {
|
||||||
val disposable = observeChange { observer(it.value) }
|
val disposable = observe(observer)
|
||||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||||
observer(value)
|
observer(value)
|
||||||
return disposable
|
return disposable
|
||||||
@ -62,7 +98,7 @@ fun <T1, T2> observeNow(
|
|||||||
c2: Cell<T2>,
|
c2: Cell<T2>,
|
||||||
observer: (T1, T2) -> Unit,
|
observer: (T1, T2) -> Unit,
|
||||||
): Disposable {
|
): 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.
|
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||||
observer(c1.value, c2.value)
|
observer(c1.value, c2.value)
|
||||||
return disposable
|
return disposable
|
||||||
@ -74,7 +110,7 @@ fun <T1, T2, T3> observeNow(
|
|||||||
c3: Cell<T3>,
|
c3: Cell<T3>,
|
||||||
observer: (T1, T2, T3) -> Unit,
|
observer: (T1, T2, T3) -> Unit,
|
||||||
): Disposable {
|
): 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.
|
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||||
observer(c1.value, c2.value, c3.value)
|
observer(c1.value, c2.value, c3.value)
|
||||||
return disposable
|
return disposable
|
||||||
@ -87,8 +123,7 @@ fun <T1, T2, T3, T4> observeNow(
|
|||||||
c4: Cell<T4>,
|
c4: Cell<T4>,
|
||||||
observer: (T1, T2, T3, T4) -> Unit,
|
observer: (T1, T2, T3, T4) -> Unit,
|
||||||
): Disposable {
|
): Disposable {
|
||||||
val disposable =
|
val disposable = observe(c1, c2, c3, c4, observer)
|
||||||
CallbackObserver(c1, c2, c3, c4) { observer(c1.value, c2.value, c3.value, c4.value) }
|
|
||||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||||
observer(c1.value, c2.value, c3.value, c4.value)
|
observer(c1.value, c2.value, c3.value, c4.value)
|
||||||
return disposable
|
return disposable
|
||||||
@ -102,9 +137,7 @@ fun <T1, T2, T3, T4, T5> observeNow(
|
|||||||
c5: Cell<T5>,
|
c5: Cell<T5>,
|
||||||
observer: (T1, T2, T3, T4, T5) -> Unit,
|
observer: (T1, T2, T3, T4, T5) -> Unit,
|
||||||
): Disposable {
|
): Disposable {
|
||||||
val disposable = CallbackObserver(c1, c2, c3, c4, c5) {
|
val disposable = observe(c1, c2, c3, c4, c5, observer)
|
||||||
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
|
||||||
}
|
|
||||||
// Call observer after observeChange to avoid double recomputation in most cells.
|
// Call observer after observeChange to avoid double recomputation in most cells.
|
||||||
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
observer(c1.value, c2.value, c3.value, c4.value, c5.value)
|
||||||
return disposable
|
return disposable
|
||||||
|
@ -2,12 +2,7 @@ package world.phantasmal.cell
|
|||||||
|
|
||||||
import world.phantasmal.cell.test.CellTestSuite
|
import world.phantasmal.cell.test.CellTestSuite
|
||||||
import world.phantasmal.core.disposable.use
|
import world.phantasmal.core.disposable.use
|
||||||
import kotlin.test.Test
|
import kotlin.test.*
|
||||||
import kotlin.test.assertEquals
|
|
||||||
import kotlin.test.assertNotEquals
|
|
||||||
import kotlin.test.assertNotNull
|
|
||||||
import kotlin.test.assertNull
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test suite for all [Cell] implementations. There is a subclass of this suite for every [Cell]
|
* 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) {
|
repeat(3) {
|
||||||
changes = 0
|
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
|
@Test
|
||||||
fun value_can_be_accessed_during_a_mutation() = test {
|
fun value_can_be_accessed_during_a_mutation() = test {
|
||||||
val p = createProvider()
|
val p = createProvider()
|
||||||
|
@ -25,118 +25,6 @@ interface MutableCellTests<T : Any> : CellTests {
|
|||||||
assertEquals(newValue, observedValue)
|
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 {
|
interface Provider<T : Any> : CellTests.Provider {
|
||||||
override val cell: MutableCell<T>
|
override val cell: MutableCell<T>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user