Hello folks! I had to map a `StateFlow` to another...
# coroutines
l
Hello folks! I had to map a
StateFlow
to another
StateFlow
with a synchronous operation (it's quite cheap, it's only one object allocation), and I didn't want to have to link it to a
CoroutineScope
this time, so I wrote this
mapSync
extension function, which you can criticize, and copy at will. I'm using it in a single-thread context, but I think it'd work just fine in multi-thread so long as the mapping operation is cheap and doesn't cause heavy recomputations on concurrent accesses.
Copy code
import kotlinx.coroutines.flow.*

fun <T, R> StateFlow<T>.mapSync(transform: (T) -> R): StateFlow<R> = object : StateFlow<R> {

    override val replayCache: List<R> get() = listOf(value)

    override suspend fun collect(collector: FlowCollector<R>): Nothing {
        this@mapSync.collect {
            collector.emit(transform(it))
        }
    }

    private var lastUpstreamValue = this@mapSync.value

    override var value: R = transform(lastUpstreamValue)
        private set
        get() {
            val currentUpstreamValue: T = this@mapSync.value
            if (currentUpstreamValue == lastUpstreamValue) return field
            field = transform(currentUpstreamValue)
            lastUpstreamValue = currentUpstreamValue
            return field
        }
}
I hope it's helpful to some of you!
👌 4
r
StateFlow
interface is still not stable for inheritance, isn't it?
l
I'm not sure if Flow is still in that case, but StateFlow is not unstable for inheritance.
r
It's actually not stable for inheritance in 3rd party libraries (just like all other Flow interfaces), but it should be fine in your application code (although you can expect new methods in the future). https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/