mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-06-01 23:45:28 +00:00
87 lines
3.1 KiB
Kotlin
87 lines
3.1 KiB
Kotlin
package dev.inmo.micro_utils.serialization.typed_serializer
|
|
|
|
import kotlinx.serialization.*
|
|
import kotlinx.serialization.builtins.serializer
|
|
import kotlinx.serialization.descriptors.*
|
|
import kotlinx.serialization.encoding.*
|
|
import kotlin.reflect.KClass
|
|
|
|
open class TypedSerializer<T : Any>(
|
|
kClass: KClass<T>,
|
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap(),
|
|
) : KSerializer<T> {
|
|
protected val serializers = presetSerializers.toMutableMap()
|
|
@InternalSerializationApi
|
|
override val descriptor: SerialDescriptor = buildSerialDescriptor(
|
|
"TypedSerializer",
|
|
SerialKind.CONTEXTUAL
|
|
) {
|
|
element("type", String.serializer().descriptor)
|
|
element("value", ContextualSerializer(kClass).descriptor)
|
|
}
|
|
@InternalSerializationApi
|
|
@Deprecated(
|
|
"This descriptor was deprecated due to incorrect serial name. You may use it in case something require it, " +
|
|
"but it is strongly recommended to migrate onto new descriptor"
|
|
)
|
|
protected val oldDescriptor: SerialDescriptor = buildSerialDescriptor(
|
|
"TextSourceSerializer",
|
|
SerialKind.CONTEXTUAL
|
|
) {
|
|
element("type", String.serializer().descriptor)
|
|
element("value", ContextualSerializer(kClass).descriptor)
|
|
}
|
|
|
|
@InternalSerializationApi
|
|
open override fun deserialize(decoder: Decoder): T {
|
|
return decoder.decodeStructure(descriptor) {
|
|
var type: String? = null
|
|
lateinit var result: T
|
|
while (true) {
|
|
when (val index = decodeElementIndex(descriptor)) {
|
|
0 -> type = decodeStringElement(descriptor, 0)
|
|
1 -> {
|
|
require(type != null) { "Type is null, but it is expected that was inited already" }
|
|
result = decodeSerializableElement(
|
|
descriptor,
|
|
1,
|
|
serializers.getValue(type)
|
|
)
|
|
}
|
|
CompositeDecoder.DECODE_DONE -> break
|
|
else -> error("Unexpected index: $index")
|
|
}
|
|
}
|
|
result
|
|
}
|
|
}
|
|
|
|
@InternalSerializationApi
|
|
protected open fun <O: T> CompositeEncoder.encode(value: O) {
|
|
encodeSerializableElement(descriptor, 1, value::class.serializer() as KSerializer<O>, value)
|
|
}
|
|
|
|
@InternalSerializationApi
|
|
open override fun serialize(encoder: Encoder, value: T) {
|
|
encoder.encodeStructure(descriptor) {
|
|
val valueSerializer = value::class.serializer()
|
|
val type = serializers.keys.first { serializers[it] == valueSerializer }
|
|
encodeStringElement(descriptor, 0, type)
|
|
encode(value)
|
|
}
|
|
}
|
|
|
|
|
|
open fun <O: T> include(type: String, serializer: KSerializer<O>) {
|
|
serializers[type] = serializer
|
|
}
|
|
|
|
open fun exclude(type: String) {
|
|
serializers.remove(type)
|
|
}
|
|
}
|
|
|
|
inline fun <reified T : Any> TypedSerializer(
|
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap()
|
|
) = TypedSerializer(T::class, presetSerializers)
|