commonMain.org.brightify.hyperdrive.property.impl.AsyncMapDeferredObservableProperty.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of runtime Show documentation
Show all versions of runtime Show documentation
Hyperdrive implementation that's needed for observations and such
package org.brightify.hyperdrive.property.impl
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.first
import org.brightify.hyperdrive.CancellationToken
import org.brightify.hyperdrive.Lifecycle
import org.brightify.hyperdrive.property.DeferredObservableProperty
import org.brightify.hyperdrive.property.ObservableProperty
import org.brightify.hyperdrive.util.AsyncQueue
import org.brightify.hyperdrive.utils.Optional
import org.brightify.hyperdrive.utils.filterSome
import org.brightify.hyperdrive.utils.someOrDefault
internal class AsyncMapDeferredObservableProperty(
private val source: ObservableProperty,
private val asyncMap: suspend (T) -> U,
private val lifecycle: Lifecycle,
private val equalityPolicy: ObservableProperty.EqualityPolicy,
private val overflowPolicy: AsyncQueue.OverflowPolicy,
): DeferredObservableProperty, ObservableProperty.Listener {
override val latestValue: Optional
get() = storage.value
private val listeners = ValueChangeListenerHandler(this)
// FIXME: This won't support identityEqualityPolicy/neverEqualityPolicy!
private val storage = MutableStateFlow>(Optional.None)
private val queue = AsyncQueue(overflowPolicy, lifecycle) {
val newValue = asyncMap(it)
val oldMappedValue = storage.value
val shouldSave = oldMappedValue !is Optional.Some || equalityPolicy.isEqual(oldMappedValue.value, newValue)
if (shouldSave) {
listeners.runNotifyingListeners(newValue) {
storage.value = Optional.Some(it)
}
}
}
init {
source.addListener(this)
}
override fun valueDidChange(oldValue: T, newValue: T) {
queue.push(newValue)
}
override suspend fun await(): U = coroutineScope {
storage.value.someOrDefault { storage.filterSome().first() }
}
override suspend fun nextValue(): U = coroutineScope {
storage.drop(1).filterSome().first()
}
override fun addListener(listener: DeferredObservableProperty.Listener): CancellationToken = listeners.addListener(listener)
override fun removeListener(listener: DeferredObservableProperty.Listener) = listeners.removeListener(listener)
}