From a7109d8d0dae37f4b2907b8f3329c79288556d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Do=C4=9Fa=C3=A7=20Eldenk?= Date: Mon, 14 Aug 2023 18:15:50 +0300 Subject: [PATCH] Fix negative enums in protobuf not serializing & de-serializing (#2400) From language guide: Enumerator constants must be in the range of a 32-bit integer. Since enum values use varint encoding on the wire, negative values are inefficient and thus not recommended (but still possible). --- .../serialization/protobuf/internal/ProtobufDecoding.kt | 2 +- .../jvmTest/src/kotlinx/serialization/protobuf/RandomTests.kt | 4 ++-- formats/protobuf/testProto/test_data.proto | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index 09773919ad..d2a28b5c43 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -80,7 +80,7 @@ internal open class ProtobufDecoder( private fun findIndexByTag(descriptor: SerialDescriptor, protoTag: Int): Int { // Fast-path: tags are incremental, 1-based - if (protoTag < descriptor.elementsCount) { + if (protoTag < descriptor.elementsCount && protoTag >= 0) { val protoId = extractProtoId(descriptor, protoTag, true) if (protoId == protoTag) return protoTag } diff --git a/formats/protobuf/jvmTest/src/kotlinx/serialization/protobuf/RandomTests.kt b/formats/protobuf/jvmTest/src/kotlinx/serialization/protobuf/RandomTests.kt index 0c94c6e327..2a12424d13 100644 --- a/formats/protobuf/jvmTest/src/kotlinx/serialization/protobuf/RandomTests.kt +++ b/formats/protobuf/jvmTest/src/kotlinx/serialization/protobuf/RandomTests.kt @@ -162,11 +162,11 @@ class RandomTest : ShouldSpec() { } } - enum class KCoffee { AMERICANO, LATTE, CAPPUCCINO } + enum class KCoffee(val value: Int) { AMERICANO(0), LATTE(1), CAPPUCCINO(2), @ProtoNumber(-1) NO_COFFEE(-1) } @Serializable data class KTestEnum(@ProtoNumber(1) val a: KCoffee): IMessage { - override fun toProtobufMessage() = TestEnum.newBuilder().setA(TestEnum.Coffee.forNumber(a.ordinal)).build() + override fun toProtobufMessage() = TestEnum.newBuilder().setA(TestEnum.Coffee.forNumber(a.value)).build() companion object : Gen { override fun generate(): KTestEnum = KTestEnum(Gen.oneOf().generate()) diff --git a/formats/protobuf/testProto/test_data.proto b/formats/protobuf/testProto/test_data.proto index f4b1f5f043..2b50c6002b 100644 --- a/formats/protobuf/testProto/test_data.proto +++ b/formats/protobuf/testProto/test_data.proto @@ -59,6 +59,7 @@ message TestEnum { Americano = 0; Latte = 1; Capuccino = 2; + NoCoffee = -1; } required Coffee a = 1; }