diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c02ed3735..a544c5c16c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 0.7.5 + +* `Common`: + * Type `Either` got its own serializer + ## 0.7.4 * `Common`: diff --git a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Either.kt b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Either.kt index f57136aefb6..35a984d7003 100644 --- a/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Either.kt +++ b/common/src/commonMain/kotlin/dev/inmo/micro_utils/common/Either.kt @@ -1,5 +1,10 @@ package dev.inmo.micro_utils.common +import kotlinx.serialization.* +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* + /** * Realization of this interface will contains at least one not null - [t1] or [t2] * @@ -10,16 +15,90 @@ package dev.inmo.micro_utils.common * @see Either.onFirst * @see Either.onSecond */ +@Serializable(EitherSerializer::class) sealed interface Either { val t1: T1? val t2: T2? - companion object + companion object { + fun serializer( + t1Serializer: KSerializer, + t2Serializer: KSerializer, + ): KSerializer> = EitherSerializer(t1Serializer, t2Serializer) + } +} + +class EitherSerializer( + t1Serializer: KSerializer, + t2Serializer: KSerializer, +) : KSerializer> { + @ExperimentalSerializationApi + @InternalSerializationApi + override val descriptor: SerialDescriptor = buildSerialDescriptor( + "TypedSerializer", + SerialKind.CONTEXTUAL + ) { + element("type", String.serializer().descriptor) + element("value", ContextualSerializer(Either::class).descriptor) + } + private val t1EitherSerializer = EitherFirst.serializer(t1Serializer, t2Serializer) + private val t2EitherSerializer = EitherSecond.serializer(t1Serializer, t2Serializer) + + @ExperimentalSerializationApi + @InternalSerializationApi + override fun deserialize(decoder: Decoder): Either { + return decoder.decodeStructure(descriptor) { + var type: String? = null + lateinit var result: Either + while (true) { + when (val index = decodeElementIndex(descriptor)) { + 0 -> type = decodeStringElement(descriptor, 0) + 1 -> { + result = when (type) { + "t1" -> decodeSerializableElement( + descriptor, + 1, + t1EitherSerializer + ) + "t2" -> decodeSerializableElement( + descriptor, + 1, + t2EitherSerializer + ) + else -> error("Unknown type of either: $type") + } + } + CompositeDecoder.DECODE_DONE -> break + else -> error("Unexpected index: $index") + } + } + result + } + } + + + @ExperimentalSerializationApi + @InternalSerializationApi + override fun serialize(encoder: Encoder, value: Either) { + encoder.encodeStructure(descriptor) { + when (value) { + is EitherFirst -> { + encodeStringElement(descriptor, 0, "t1") + encodeSerializableElement(descriptor, 1, t1EitherSerializer, value) + } + is EitherSecond -> { + encodeStringElement(descriptor, 0, "t2") + encodeSerializableElement(descriptor, 1, t2EitherSerializer, value) + } + } + } + } } /** * This type [Either] will always have not nullable [t1] */ +@Serializable data class EitherFirst( override val t1: T1 ) : Either { @@ -30,6 +109,7 @@ data class EitherFirst( /** * This type [Either] will always have not nullable [t2] */ +@Serializable data class EitherSecond( override val t2: T2 ) : Either { diff --git a/gradle.properties b/gradle.properties index 20f356055d4..729022615a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -45,5 +45,5 @@ dokka_version=1.5.31 # Project data group=dev.inmo -version=0.7.4 -android_code_version=78 +version=0.7.5 +android_code_version=79