All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.brightify.hyperdrive.property.impl.MapDeferredObservableProperty.kt Maven / Gradle / Ivy

There is a newer version: 0.1.159
Show newest version
package org.brightify.hyperdrive.property.impl

import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.first
import org.brightify.hyperdrive.CancellationToken
import org.brightify.hyperdrive.property.DeferredObservableProperty
import org.brightify.hyperdrive.property.ObservableProperty
import org.brightify.hyperdrive.utils.Optional
import org.brightify.hyperdrive.utils.map
import org.brightify.hyperdrive.utils.someOrDefault

internal class MapDeferredObservableProperty(
    private val mapped: DeferredObservableProperty,
    private val transform: (T) -> U,
    private val equalityPolicy: ObservableProperty.EqualityPolicy,
): DeferredObservableProperty, DeferredObservableProperty.Listener {
    private val listeners = ValueChangeListenerHandler(this)

    override var latestValue: Optional = mapped.latestValue.map(transform)

    private val valueFlow = MutableSharedFlow(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)

    init {
        mapped.addListener(this)
    }

    override suspend fun await(): U = coroutineScope {
        latestValue.someOrDefault {
            nextValue()
        }
    }

    override suspend fun nextValue(): U = coroutineScope {
        valueFlow.first()
    }

    override fun valueDidChange(oldValue: Optional, newValue: T) {
        val currentValue = latestValue
        val newTransformedValue = transform(newValue)
        if (currentValue is Optional.Some && equalityPolicy.isEqual(currentValue.value, newTransformedValue)) { return }
        listeners.runNotifyingListeners(newTransformedValue) {
            latestValue = Optional.Some(it)
            valueFlow.tryEmit(it)
        }
    }

    override fun addListener(listener: DeferredObservableProperty.Listener): CancellationToken = listeners.addListener(listener)

    override fun removeListener(listener: DeferredObservableProperty.Listener) = listeners.removeListener(listener)
}