Peter
11/26/2023, 9:48 PMval state = MutableStateFlow(State(email = ""))
var email: String
get() = state.value.email
set(value) { state.update { email = value } }
Is there some KProperty
trick, that I could use, to delegate email
to state
?Peter
11/26/2023, 9:59 PMvar email by mutableStateDelegate(state::email)
Daniel Pitts
11/27/2023, 2:18 AMDaniel Pitts
11/27/2023, 3:22 AMimport kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.instanceParameter
import kotlin.reflect.full.isSupertypeOf
import kotlin.reflect.full.starProjectedType
import kotlin.reflect.full.valueParameters
data class State(
val email: String,
)
val state = MutableStateFlow(State(email = ""))
var MutableStateFlow<State>.email by property(State::email)
fun main(): Unit = runBlocking {
launch {
state.collect {
println(it)
}
}
launch {
repeat(10) {
state.email = "email$it@example.com"
delay(1000)
}
}
}
inline fun <reified T : Any, V> property(property: KProperty1<T, V>): PropertyUpdater<T, V> {
val kClass = T::class
val type = kClass.starProjectedType
val copy = kClass.declaredFunctions.asSequence()
.filter { it.name == "copy" }
.filter { it.returnType.classifier?.starProjectedType == type }
.filter { it.valueParameters.any { param -> param.name == property.name && param.type.isSupertypeOf(property.returnType) } }
.filter {
it.valueParameters.all { param -> param.isOptional || param.name == property.name }
}
.firstOrNull() ?: error("No suitable copy method found")
val instanceParameter = copy.instanceParameter!!
val propertyParameter = copy.valueParameters.single { it.name == property.name }
val copyDelegate: T.(V) -> T = {
copy.callBy(
mapOf(
instanceParameter to this,
propertyParameter to it
)
) as T
}
return PropertyUpdater(property, copyDelegate)
}
class PropertyUpdater<T : Any, V>(private val get: T.() -> V, private val update: T.(V) -> T) {
operator fun getValue(thisRef: MutableStateFlow<T>, property: KProperty<*>): V {
return thisRef.value.get()
}
operator fun setValue(thisRef: MutableStateFlow<T>, property: KProperty<*>, value: V) {
thisRef.update { it.update(value) }
}
}
Daniel Pitts
11/27/2023, 3:25 AMPeter
11/27/2023, 8:20 PMcopy()
is the biggest pain.Daniel Pitts
11/28/2023, 2:02 AMclass StatePropertyDelegate(val get: T.()->V, val update: T.(V)->T) {...}
var MutableStateFlow<State>.email by StatePropertyDelegate({email}, {copy(email=it)})
Daniel Pitts
11/28/2023, 2:03 AM