dave08
01/24/2022, 3:11 PM@ExperimentalStdlibApi
inline fun <reified T> Data.getValue(obj: Any?, prop: KProperty<*>): T {
return when(T::class) {
String::class -> getString(prop.name) as T
Int::class -> getInt(prop.name, -1) as T
Boolean::class -> getBoolean(prop.name, false) as T
Enum::class -> getString(prop.name)?.let { enumValueOf<T>(it) } // This doesn't compile...
else -> error("Trying to retrieve invalid type in Data for ${prop.name}: ${T::class}")
}
}
enum Foo { BAZ, BAR }
class SomeData(val inputData: Data) {
val dataEnumKeyForFoo: Foo by inputData // Saved as a string in Data with the key `dataEnumKeyForFoo` and the value one of the enum value's names...
}
Javier
01/24/2022, 3:22 PMobj
is used for something?Joffrey
01/24/2022, 3:22 PMwhen
on the class of T
(even with a reified T
). This is why you needed to cast in the other cases.
I think you could use delegate providers instead of direct delegates. And for instance provide one for primitives and one for enums (with extra constraint on T : Enum<T>
which will allow enumValueOf
):
class SomeData(val inputData: Data) {
val dataEnumKeyForFoo: Foo by inputData.enum()
val otherProp: Int by inputData.primitive()
}
But you could even go as far as creating one for each primitive type tooobj
is necessary to conform to the delegate contract, even if not usedJavier
01/24/2022, 3:23 PMJoffrey
01/24/2022, 3:23 PMJavier
01/24/2022, 3:24 PMwhen(obj) {
is String -> ... as T
is Enum<*> -> ... as T
else -> ... as T
}
Joffrey
01/24/2022, 3:24 PMobj
is the instance of the class in which the property is declared, so it's not of type T
. In the given example, obj
would be of type SomeData
dave08
01/24/2022, 3:26 PMobj
isn't needed, since such a class just contains a Data instance... the truth is, if I make that obj
a DataProvider
then I wouldn't need the receiver to be Data
I could retrieve it from obj
, but I don't think that would help too much...enum()
would return a ReadWriteProperty
implementation...?class EnumDataProperty<T : Enum<T>>(): ReadWriteProperty<Data, T> {
override fun getValue(thisRef: Data, property: KProperty<*>): T {
return thisRef.getString(property.name)?.let { enumValueOf(it) }!!
}
override fun setValue(thisRef: Data, property: KProperty<*>, value: T) {
TODO("Not yet implemented")
}
}
inline fun <reified T : Enum<T>> Data.getEnum(key: String): T? =
getString(key)?.let { enumValueOf<T>(it) }
inline fun <reified T : Enum<T>> Data.Builder.putEnum(key: String, value: T): Data.Builder {
putString(key, value.name)
return this
}
inline fun buildData(configure: Data.Builder.() -> Data.Builder): Data = Data.Builder().apply {
configure()
}.build()