mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-11-26 03:58:45 +00:00
add project typed serializer
This commit is contained in:
parent
49b009e59b
commit
ffc2d23be7
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
* `Versions`:
|
* `Versions`:
|
||||||
* `Kotlin Exposed`: `0.30.1` -> `0.30.2`
|
* `Kotlin Exposed`: `0.30.1` -> `0.30.2`
|
||||||
|
* `Serialization`:
|
||||||
|
* `TypedSerializer`:
|
||||||
|
* Project has been inited
|
||||||
|
|
||||||
## 0.4.34
|
## 0.4.34
|
||||||
|
|
||||||
|
7
serialization/typed_serializer/build.gradle
Normal file
7
serialization/typed_serializer/build.gradle
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
@ -0,0 +1,76 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
class TypedSerializer<T : Any>(
|
||||||
|
kClass: KClass<T>,
|
||||||
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap()
|
||||||
|
) : KSerializer<T> {
|
||||||
|
private val serializers = presetSerializers.toMutableMap()
|
||||||
|
@InternalSerializationApi
|
||||||
|
override val descriptor: SerialDescriptor = buildSerialDescriptor(
|
||||||
|
"TextSourceSerializer",
|
||||||
|
SerialKind.CONTEXTUAL
|
||||||
|
) {
|
||||||
|
element("type", String.serializer().descriptor)
|
||||||
|
element("value", ContextualSerializer(kClass).descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InternalSerializationApi
|
||||||
|
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
|
||||||
|
private fun <O: T> CompositeEncoder.encode(value: O) {
|
||||||
|
encodeSerializableElement(descriptor, 1, value::class.serializer() as KSerializer<O>, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InternalSerializationApi
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <O: T> include(type: String, serializer: KSerializer<O>) {
|
||||||
|
require(type !in serializers.keys)
|
||||||
|
serializers[type] = serializer
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exclude(type: String) {
|
||||||
|
require(type !in serializers.keys)
|
||||||
|
serializers.remove(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> TypedSerializer(
|
||||||
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap()
|
||||||
|
) = TypedSerializer(T::class, presetSerializers)
|
@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.typed_serializer
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.builtins.ListSerializer
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class TypedSerializerTests {
|
||||||
|
interface Example {
|
||||||
|
val number: Number
|
||||||
|
}
|
||||||
|
val serialFormat = Json { }
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Example1(override val number: Long) : Example
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Example2(override val number: Double) : Example
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThatSerializerWorksCorrectly() {
|
||||||
|
val serializer = TypedSerializer(
|
||||||
|
mapOf(
|
||||||
|
"long" to Example1.serializer(),
|
||||||
|
"double" to Example2.serializer()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val value1 = Example1(Random.nextLong())
|
||||||
|
val value2 = Example2(Random.nextDouble())
|
||||||
|
|
||||||
|
val list = listOf(value1, value2)
|
||||||
|
val serialized = serialFormat.encodeToString(ListSerializer(serializer), list)
|
||||||
|
val deserialized = serialFormat.decodeFromString(ListSerializer(serializer), serialized)
|
||||||
|
|
||||||
|
assertEquals(list, deserialized)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.serialization.typed_serializer"/>
|
@ -26,6 +26,7 @@ String[] includes = [
|
|||||||
":android:alerts:recyclerview",
|
":android:alerts:recyclerview",
|
||||||
":serialization:base64",
|
":serialization:base64",
|
||||||
":serialization:encapsulator",
|
":serialization:encapsulator",
|
||||||
|
":serialization:typed_serializer",
|
||||||
|
|
||||||
":dokka"
|
":dokka"
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user