Renamed StaticCell to ImmutableCell and StaticListCell to ImmutableListCell.

This commit is contained in:
Daan Vanden Bosch 2021-11-30 15:59:28 +01:00
parent b7fc6a260b
commit 5c605fafbc
14 changed files with 108 additions and 94 deletions

View File

@ -1,21 +1,27 @@
package world.phantasmal.observable.cell package world.phantasmal.observable.cell
private val TRUE_CELL: Cell<Boolean> = StaticCell(true) private val TRUE_CELL: Cell<Boolean> = ImmutableCell(true)
private val FALSE_CELL: Cell<Boolean> = StaticCell(false) private val FALSE_CELL: Cell<Boolean> = ImmutableCell(false)
private val NULL_CELL: Cell<Nothing?> = StaticCell(null) private val NULL_CELL: Cell<Nothing?> = ImmutableCell(null)
private val ZERO_INT_CELL: Cell<Int> = StaticCell(0) private val ZERO_INT_CELL: Cell<Int> = ImmutableCell(0)
private val EMPTY_STRING_CELL: Cell<String> = StaticCell("") private val EMPTY_STRING_CELL: Cell<String> = ImmutableCell("")
fun <T> cell(value: T): Cell<T> = StaticCell(value) /** Returns an immutable cell containing [value]. */
fun <T> cell(value: T): Cell<T> = ImmutableCell(value)
/** Returns a singleton immutable cell containing the value `true`. */
fun trueCell(): Cell<Boolean> = TRUE_CELL fun trueCell(): Cell<Boolean> = TRUE_CELL
/** Returns a singleton immutable cell containing the value `false`. */
fun falseCell(): Cell<Boolean> = FALSE_CELL fun falseCell(): Cell<Boolean> = FALSE_CELL
/** Returns a singleton immutable cell containing the value `null`. */
fun nullCell(): Cell<Nothing?> = NULL_CELL fun nullCell(): Cell<Nothing?> = NULL_CELL
/** Returns a singleton immutable cell containing the integer value `0`. */
fun zeroIntCell(): Cell<Int> = ZERO_INT_CELL fun zeroIntCell(): Cell<Int> = ZERO_INT_CELL
/** Returns a singleton immutable cell containing the empty string (""). */
fun emptyStringCell(): Cell<String> = EMPTY_STRING_CELL fun emptyStringCell(): Cell<String> = EMPTY_STRING_CELL
/** /**

View File

@ -6,7 +6,7 @@ import world.phantasmal.observable.AbstractDependency
import world.phantasmal.observable.ChangeEvent import world.phantasmal.observable.ChangeEvent
import world.phantasmal.observable.Observer import world.phantasmal.observable.Observer
class StaticCell<T>(override val value: T) : AbstractDependency(), Cell<T> { class ImmutableCell<T>(override val value: T) : AbstractDependency(), Cell<T> {
override fun observe(callNow: Boolean, observer: Observer<T>): Disposable { override fun observe(callNow: Boolean, observer: Observer<T>): Disposable {
if (callNow) { if (callNow) {
observer(ChangeEvent(value)) observer(ChangeEvent(value))

View File

@ -1,6 +1,5 @@
package world.phantasmal.observable.cell.list package world.phantasmal.observable.cell.list
import world.phantasmal.core.unsafe.unsafeAssertNotNull
import world.phantasmal.observable.ChangeEvent import world.phantasmal.observable.ChangeEvent
import world.phantasmal.observable.Dependency import world.phantasmal.observable.Dependency
import world.phantasmal.observable.Dependent import world.phantasmal.observable.Dependent

View File

@ -8,7 +8,7 @@ import world.phantasmal.observable.ChangeEvent
import world.phantasmal.observable.Observer import world.phantasmal.observable.Observer
import world.phantasmal.observable.cell.* import world.phantasmal.observable.cell.*
class StaticListCell<E>(private val elements: List<E>) : AbstractDependency(), ListCell<E> { class ImmutableListCell<E>(private val elements: List<E>) : AbstractDependency(), ListCell<E> {
private var firstOrNull: Cell<E?>? = null private var firstOrNull: Cell<E?>? = null
override val size: Cell<Int> = cell(elements.size) override val size: Cell<Int> = cell(elements.size)
@ -40,13 +40,13 @@ class StaticListCell<E>(private val elements: List<E>) : AbstractDependency(), L
override fun firstOrNull(): Cell<E?> { override fun firstOrNull(): Cell<E?> {
if (firstOrNull == null) { if (firstOrNull == null) {
firstOrNull = StaticCell(elements.firstOrNull()) firstOrNull = ImmutableCell(elements.firstOrNull())
} }
return unsafeAssertNotNull(firstOrNull) return unsafeAssertNotNull(firstOrNull)
} }
override fun emitDependencyChanged() { override fun emitDependencyChanged() {
error("StaticListCell can't change.") error("ImmutableListCell can't change.")
} }
} }

View File

@ -2,12 +2,15 @@ package world.phantasmal.observable.cell.list
import world.phantasmal.observable.cell.Cell import world.phantasmal.observable.cell.Cell
private val EMPTY_LIST_CELL = StaticListCell<Nothing>(emptyList()) private val EMPTY_LIST_CELL = ImmutableListCell<Nothing>(emptyList())
fun <E> listCell(vararg elements: E): ListCell<E> = StaticListCell(elements.toList()) /** Returns an immutable list cell containing [elements]. */
fun <E> listCell(vararg elements: E): ListCell<E> = ImmutableListCell(elements.toList())
/** Returns a singleton empty immutable cell. */
fun <E> emptyListCell(): ListCell<E> = EMPTY_LIST_CELL fun <E> emptyListCell(): ListCell<E> = EMPTY_LIST_CELL
/** Returns a mutable list cell containing [elements]. */
fun <E> mutableListCell( fun <E> mutableListCell(
vararg elements: E, vararg elements: E,
extractDependencies: DependenciesExtractor<E>? = null, extractDependencies: DependenciesExtractor<E>? = null,

View File

@ -55,7 +55,7 @@ interface CellTests : ObservableTests {
fun propagates_changes_to_flat_mapped_cell() = test { fun propagates_changes_to_flat_mapped_cell() = test {
val p = createProvider() val p = createProvider()
val mapped = p.observable.flatMap { StaticCell(it.hashCode()) } val mapped = p.observable.flatMap { ImmutableCell(it.hashCode()) }
val initialValue = mapped.value val initialValue = mapped.value
var observedValue: Int? = null var observedValue: Int? = null

View File

@ -6,7 +6,7 @@ package world.phantasmal.observable.cell
class FlatteningDependentCellDirectDependencyEmitsTests : RegularCellTests { class FlatteningDependentCellDirectDependencyEmitsTests : RegularCellTests {
override fun createProvider() = object : CellTests.Provider { override fun createProvider() = object : CellTests.Provider {
// The transitive dependency can't change. // The transitive dependency can't change.
val transitiveDependency = StaticCell(5) val transitiveDependency = ImmutableCell(5)
// The direct dependency of the cell under test can change. // The direct dependency of the cell under test can change.
val directDependency = SimpleCell(transitiveDependency) val directDependency = SimpleCell(transitiveDependency)
@ -17,12 +17,12 @@ class FlatteningDependentCellDirectDependencyEmitsTests : RegularCellTests {
override fun emit() { override fun emit() {
// Update the direct dependency. // Update the direct dependency.
val oldTransitiveDependency = directDependency.value val oldTransitiveDependency = directDependency.value
directDependency.value = StaticCell(oldTransitiveDependency.value + 5) directDependency.value = ImmutableCell(oldTransitiveDependency.value + 5)
} }
} }
override fun <T> createWithValue(value: T): FlatteningDependentCell<T> { override fun <T> createWithValue(value: T): FlatteningDependentCell<T> {
val v = StaticCell(StaticCell(value)) val v = ImmutableCell(ImmutableCell(value))
return FlatteningDependentCell(v) { v.value } return FlatteningDependentCell(v) { v.value }
} }
} }

View File

@ -10,7 +10,7 @@ class FlatteningDependentCellTransitiveDependencyEmitsTests :
override fun createProvider() = Provider() override fun createProvider() = Provider()
override fun <T> createWithValue(value: T): FlatteningDependentCell<T> { override fun <T> createWithValue(value: T): FlatteningDependentCell<T> {
val dependency = StaticCell(StaticCell(value)) val dependency = ImmutableCell(ImmutableCell(value))
return FlatteningDependentCell(dependency) { dependency.value } return FlatteningDependentCell(dependency) { dependency.value }
} }
@ -19,7 +19,7 @@ class FlatteningDependentCellTransitiveDependencyEmitsTests :
private val transitiveDependency = SimpleCell(5) private val transitiveDependency = SimpleCell(5)
// The direct dependency of the cell under test can't change. // The direct dependency of the cell under test can't change.
private val directDependency = StaticCell(transitiveDependency) private val directDependency = ImmutableCell(transitiveDependency)
override val observable = override val observable =
FlatteningDependentCell(directDependency) { directDependency.value } FlatteningDependentCell(directDependency) { directDependency.value }
@ -30,6 +30,6 @@ class FlatteningDependentCellTransitiveDependencyEmitsTests :
} }
override fun createWithDependencies(vararg dependencies: Cell<Int>): Cell<Any> = override fun createWithDependencies(vararg dependencies: Cell<Int>): Cell<Any> =
FlatteningDependentCell(*dependencies) { StaticCell(dependencies.sumOf { it.value }) } FlatteningDependentCell(*dependencies) { ImmutableCell(dependencies.sumOf { it.value }) }
} }
} }

View File

@ -0,0 +1,31 @@
package world.phantasmal.observable.cell
import world.phantasmal.core.disposable.TrackedDisposable
import world.phantasmal.observable.test.ObservableTestSuite
import kotlin.test.Test
import kotlin.test.assertEquals
class ImmutableCellTests : ObservableTestSuite {
@Test
fun observing_it_should_never_create_leaks() = test {
val cell = ImmutableCell("test value")
TrackedDisposable.checkNoLeaks {
// We never call dispose on the returned disposables.
cell.observe {}
cell.observe(callNow = false) {}
cell.observe(callNow = true) {}
}
}
@Test
fun observe_respects_callNow() = test {
val cell = ImmutableCell("test value")
var calls = 0
cell.observe(callNow = false) { calls++ }
cell.observe(callNow = true) { calls++ }
assertEquals(1, calls)
}
}

View File

@ -1,28 +0,0 @@
package world.phantasmal.observable.cell
import world.phantasmal.observable.test.ObservableTestSuite
import kotlin.test.Test
import kotlin.test.assertEquals
class StaticCellTests : ObservableTestSuite {
@Test
fun observing_StaticCell_should_never_create_leaks() = test {
val static = StaticCell("test value")
// We never call dispose on the returned disposables.
static.observe {}
static.observe(callNow = false) {}
static.observe(callNow = true) {}
}
@Test
fun observe_respects_callNow() = test {
val static = StaticCell("test value")
var calls = 0
static.observe(callNow = false) { calls++ }
static.observe(callNow = true) { calls++ }
assertEquals(1, calls)
}
}

View File

@ -8,7 +8,7 @@ import world.phantasmal.observable.cell.SimpleCell
class FlatteningDependentListCellDirectDependencyEmitsTests : ListCellTests { class FlatteningDependentListCellDirectDependencyEmitsTests : ListCellTests {
override fun createListProvider(empty: Boolean) = object : ListCellTests.Provider { override fun createListProvider(empty: Boolean) = object : ListCellTests.Provider {
// The transitive dependency can't change. // The transitive dependency can't change.
private val transitiveDependency = StaticListCell(if (empty) emptyList() else listOf(7)) private val transitiveDependency = ImmutableListCell(if (empty) emptyList() else listOf(7))
// The direct dependency of the list under test can change. // The direct dependency of the list under test can change.
private val directDependency = SimpleCell<ListCell<Int>>(transitiveDependency) private val directDependency = SimpleCell<ListCell<Int>>(transitiveDependency)
@ -19,7 +19,7 @@ class FlatteningDependentListCellDirectDependencyEmitsTests : ListCellTests {
override fun addElement() { override fun addElement() {
// Update the direct dependency. // Update the direct dependency.
val oldTransitiveDependency: ListCell<Int> = directDependency.value val oldTransitiveDependency: ListCell<Int> = directDependency.value
directDependency.value = StaticListCell(oldTransitiveDependency.value + 4) directDependency.value = ImmutableListCell(oldTransitiveDependency.value + 4)
} }
} }
} }

View File

@ -2,7 +2,7 @@ package world.phantasmal.observable.cell.list
import world.phantasmal.observable.cell.Cell import world.phantasmal.observable.cell.Cell
import world.phantasmal.observable.cell.CellWithDependenciesTests import world.phantasmal.observable.cell.CellWithDependenciesTests
import world.phantasmal.observable.cell.StaticCell import world.phantasmal.observable.cell.ImmutableCell
/** /**
* In these tests the dependency of the [FlatteningDependentListCell]'s direct dependency changes. * In these tests the dependency of the [FlatteningDependentListCell]'s direct dependency changes.
@ -21,7 +21,7 @@ class FlatteningDependentListCellTransitiveDependencyEmitsTests :
SimpleListCell(if (empty) mutableListOf() else mutableListOf(7)) SimpleListCell(if (empty) mutableListOf() else mutableListOf(7))
// The direct dependency of the list under test can't change. // The direct dependency of the list under test can't change.
private val directDependency = StaticCell<ListCell<Int>>(transitiveDependency) private val directDependency = ImmutableCell<ListCell<Int>>(transitiveDependency)
override val observable = override val observable =
FlatteningDependentListCell(directDependency) { directDependency.value } FlatteningDependentListCell(directDependency) { directDependency.value }
@ -33,7 +33,7 @@ class FlatteningDependentListCellTransitiveDependencyEmitsTests :
override fun createWithDependencies(vararg dependencies: Cell<Int>): Cell<Any> = override fun createWithDependencies(vararg dependencies: Cell<Int>): Cell<Any> =
FlatteningDependentListCell(*dependencies) { FlatteningDependentListCell(*dependencies) {
StaticListCell(dependencies.map { it.value }) ImmutableListCell(dependencies.map { it.value })
} }
} }
} }

View File

@ -0,0 +1,44 @@
package world.phantasmal.observable.cell.list
import world.phantasmal.core.disposable.TrackedDisposable
import world.phantasmal.observable.test.ObservableTestSuite
import kotlin.test.Test
import kotlin.test.assertEquals
class ImmutableListCellTests : ObservableTestSuite {
@Test
fun observing_it_should_never_create_leaks() = test {
val listCell = ImmutableListCell(listOf(1, 2, 3))
TrackedDisposable.checkNoLeaks {
// We never call dispose on the returned disposables.
listCell.observe {}
listCell.observe(callNow = false) {}
listCell.observe(callNow = true) {}
listCell.observeList(callNow = false) {}
listCell.observeList(callNow = true) {}
}
}
@Test
fun observe_respects_callNow() = test {
val listCell = ImmutableListCell(listOf(1, 2, 3))
var calls = 0
listCell.observe(callNow = false) { calls++ }
listCell.observe(callNow = true) { calls++ }
assertEquals(1, calls)
}
@Test
fun observeList_respects_callNow() = test {
val listCell = ImmutableListCell(listOf(1, 2, 3))
var calls = 0
listCell.observeList(callNow = false) { calls++ }
listCell.observeList(callNow = true) { calls++ }
assertEquals(1, calls)
}
}

View File

@ -1,41 +0,0 @@
package world.phantasmal.observable.cell.list
import world.phantasmal.observable.test.ObservableTestSuite
import kotlin.test.Test
import kotlin.test.assertEquals
class StaticListCellTests : ObservableTestSuite {
@Test
fun observing_StaticListCell_should_never_create_leaks() = test {
val static = StaticListCell(listOf(1, 2, 3))
// We never call dispose on the returned disposables.
static.observe {}
static.observe(callNow = false) {}
static.observe(callNow = true) {}
static.observeList(callNow = false) {}
static.observeList(callNow = true) {}
}
@Test
fun observe_respects_callNow() = test {
val static = StaticListCell(listOf(1, 2, 3))
var calls = 0
static.observe(callNow = false) { calls++ }
static.observe(callNow = true) { calls++ }
assertEquals(1, calls)
}
@Test
fun observeList_respects_callNow() = test {
val static = StaticListCell(listOf(1, 2, 3))
var calls = 0
static.observeList(callNow = false) { calls++ }
static.observeList(callNow = true) { calls++ }
assertEquals(1, calls)
}
}