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( kClass: KClass, presetSerializers: Map> = emptyMap(), ) : KSerializer { protected val serializers = presetSerializers.toMutableMap() @OptIn(InternalSerializationApi::class) override val descriptor: SerialDescriptor = buildSerialDescriptor( "TypedSerializer", SerialKind.CONTEXTUAL ) { element("type", String.serializer().descriptor) element("value", ContextualSerializer(kClass).descriptor) } @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) 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 } } @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) protected open fun CompositeEncoder.encode(value: O) { encodeSerializableElement(descriptor, 1, value::class.serializer() as KSerializer, value) } @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) 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 include(type: String, serializer: KSerializer) { serializers[type] = serializer } open fun exclude(type: String) { serializers.remove(type) } } @InternalSerializationApi operator fun TypedSerializer.plusAssign(kClass: KClass) { include(kClass.simpleName!!, kClass.serializer()) } @InternalSerializationApi operator fun TypedSerializer.minusAssign(kClass: KClass) { exclude(kClass.simpleName!!) } inline fun TypedSerializer( presetSerializers: Map> = emptyMap() ) = TypedSerializer(T::class, presetSerializers) inline fun TypedSerializer( vararg presetSerializers: Pair> ) = TypedSerializer(presetSerializers.toMap())