Skip to content

Commit

Permalink
KeyValueSerializer: Fix missing call to endStructure() (#2272)
Browse files Browse the repository at this point in the history
The sequential decoding path was missing it. Use decodeStructure() to
avoid this error.

Co-authored-by: Pavel Vasin <git@vasin.nl>
  • Loading branch information
recursive-rat4 and Pavel Vasin committed May 8, 2023
1 parent 8007574 commit ef67bce
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 14 deletions.
20 changes: 9 additions & 11 deletions core/commonMain/src/kotlinx/serialization/internal/Tuples.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,33 @@ internal sealed class KeyValueSerializer<K, V, R>(
structuredEncoder.endStructure(descriptor)
}

override fun deserialize(decoder: Decoder): R {
val composite = decoder.beginStructure(descriptor)
if (composite.decodeSequentially()) {
val key = composite.decodeSerializableElement(descriptor, 0, keySerializer)
val value = composite.decodeSerializableElement(descriptor, 1, valueSerializer)
return toResult(key, value)
override fun deserialize(decoder: Decoder): R = decoder.decodeStructure(descriptor) {
if (decodeSequentially()) {
val key = decodeSerializableElement(descriptor, 0, keySerializer)
val value = decodeSerializableElement(descriptor, 1, valueSerializer)
return@decodeStructure toResult(key, value)
}

var key: Any? = NULL
var value: Any? = NULL
mainLoop@ while (true) {
when (val idx = composite.decodeElementIndex(descriptor)) {
when (val idx = decodeElementIndex(descriptor)) {
CompositeDecoder.DECODE_DONE -> {
break@mainLoop
}
0 -> {
key = composite.decodeSerializableElement(descriptor, 0, keySerializer)
key = decodeSerializableElement(descriptor, 0, keySerializer)
}
1 -> {
value = composite.decodeSerializableElement(descriptor, 1, valueSerializer)
value = decodeSerializableElement(descriptor, 1, valueSerializer)
}
else -> throw SerializationException("Invalid index: $idx")
}
}
composite.endStructure(descriptor)
if (key === NULL) throw SerializationException("Element 'key' is missing")
if (value === NULL) throw SerializationException("Element 'value' is missing")
@Suppress("UNCHECKED_CAST")
return toResult(key as K, value as V)
return@decodeStructure toResult(key as K, value as V)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,17 @@ class DummySequentialDecoder(
override fun decodeSequentially(): Boolean = true
override fun decodeElementIndex(descriptor: SerialDescriptor): Int = throw Error("This method shouldn't be called in sequential mode")

override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder = this
override fun endStructure(descriptor: SerialDescriptor): Unit = Unit
var beginStructureCalled = 0
var endStructureCalled = 0

override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder {
++beginStructureCalled
return this
}
override fun endStructure(descriptor: SerialDescriptor): Unit {
++endStructureCalled
return Unit
}

override fun decodeInline(descriptor: SerialDescriptor): Decoder = notImplemented()

Expand Down Expand Up @@ -51,6 +60,6 @@ class DummySequentialDecoder(
override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String = notImplemented()

override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder = notImplemented()
override fun <T : Any?> decodeSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, previousValue: T?): T = notImplemented()
override fun <T : Any?> decodeSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T>, previousValue: T?): T = decodeSerializableValue(deserializer)
override fun <T : Any> decodeNullableSerializableElement(descriptor: SerialDescriptor, index: Int, deserializer: DeserializationStrategy<T?>, previousValue: T?): T? = notImplemented()
}
18 changes: 18 additions & 0 deletions core/commonTest/src/kotlinx/serialization/internal/TuplesTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.serialization.internal

import kotlin.test.*
import kotlinx.serialization.builtins.*

class TuplesTest {
@Test
fun testSequentialDecodingKeyValue() {
val decoder = DummySequentialDecoder()
val serializer = MapEntrySerializer(Unit.serializer(), Unit.serializer())
serializer.deserialize(decoder)
assertEquals(decoder.beginStructureCalled, decoder.endStructureCalled)
}
}

0 comments on commit ef67bce

Please sign in to comment.