From 2dd454150e9c34915e2365360dd0890c3c32bbd6 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 30 Dec 2023 17:06:55 -0500 Subject: [PATCH 01/38] implement a converter to dynamic message --- buildSrc/src/main/kotlin/LocalProtoktBuild.kt | 4 +- .../kotlin/protokt/v1/gradle/ProtobufBuild.kt | 7 +- .../kotlin/protokt/v1/gradle/ProtoktBuild.kt | 9 +- gradle/libs.versions.toml | 4 + .../v1/codegen/generate/CodeGenerator.kt | 6 +- .../codegen/generate/DeserializerGenerator.kt | 6 +- .../v1/codegen/generate/MapEntryGenerator.kt | 6 +- .../kotlin/protokt/v1/codegen/util/Types.kt | 5 +- .../protokt/v1/google/protobuf/AnyUtil.kt | 4 - protokt-reflect/build.gradle.kts | 65 +++++ .../protokt/v1/google/protobuf/KtMessages.kt | 250 ++++++++++++++++++ .../v1/google/protobuf/ProtoktReflect.kt | 163 ++++++++++++ .../v1/google/protobuf/DynamicMessageTest.kt | 39 +++ .../protokt/v1/google/protobuf/TestUtil.kt | 77 ++++++ .../google/protobuf/unittest_import.proto | 51 ++++ .../protobuf/unittest_import_public.proto | 24 ++ .../google/protobuf/unittest_proto3.proto | 214 +++++++++++++++ .../protokt/v1/KtMessageDeserializer.kt | 2 +- .../protokt/v1/JsKtMessageDeserializer.kt | 14 +- .../toasttab/protokt/rt/KtGeneratedMessage.kt | 1 + .../protokt/v1/JvmKtMessageDeserializer.kt | 2 +- settings.gradle.kts | 1 + 22 files changed, 921 insertions(+), 33 deletions(-) create mode 100644 protokt-reflect/build.gradle.kts create mode 100644 protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt create mode 100644 protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt create mode 100644 protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt create mode 100644 protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt create mode 100644 protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto create mode 100644 protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto create mode 100644 protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto diff --git a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt index e77dcc141..a6834037f 100644 --- a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt +++ b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt @@ -25,8 +25,8 @@ import protokt.v1.gradle.CODEGEN_NAME import protokt.v1.gradle.configureProtokt import java.io.File -fun Project.localProtokt() { - configureProtokt(this, null) { +fun Project.localProtokt(disableJava: Boolean = true) { + configureProtokt(this, null, disableJava) { "$rootDir/protokt-codegen/build/install/$CODEGEN_NAME/bin/$CODEGEN_NAME" } diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt b/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt index 240c4d5ca..e5c8dd8ae 100644 --- a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt +++ b/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt @@ -33,6 +33,7 @@ import java.net.URLEncoder internal fun configureProtobufPlugin( project: Project, ext: ProtoktExtension, + disableJava: Boolean, binaryPath: String ) { project.apply() @@ -52,8 +53,10 @@ internal fun configureProtobufPlugin( generateProtoTasks { for (task in all()) { - task.builtins { - findByName("java")?.run(::remove) + if (disableJava) { + task.builtins { + findByName("java")?.run(::remove) + } } task.plugins { diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt b/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt index 1d27c00c0..736e79910 100644 --- a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt +++ b/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt @@ -48,10 +48,15 @@ const val EXTENSIONS = "protoktExtensions" const val TEST_EXTENSIONS = "testProtoktExtensions" -fun configureProtokt(project: Project, protoktVersion: Any?, resolveBinary: () -> String) { +fun configureProtokt( + project: Project, + protoktVersion: Any?, + disableJava: Boolean = true, + resolveBinary: () -> String +) { injectKotlinPluginsIntoProtobufGradle() val ext = project.extensions.create("protokt") - configureProtobufPlugin(project, ext, resolveBinary()) + configureProtobufPlugin(project, ext, disableJava, resolveBinary()) project.createExtensionConfigurationsAndConfigureProtobuf() diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 955ff90a7..1708966e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,8 +13,10 @@ [versions] autoService = "1.0.1" +classgraph = "4.8.153" grpc-java = "1.58.0" grpc-kotlin = "1.4.0" +guava = "33.0.0-android" kotlinLogging = "5.1.0" kotlinPoet = "1.14.2" kotlinx-coroutines = "1.6.0" @@ -60,9 +62,11 @@ wire = { id = "com.squareup.wire", version.ref = "wire" } [libraries] autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } autoServiceAnnotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoService" } +classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } grpc-kotlin-gen = { module = "io.grpc:protoc-gen-grpc-kotlin", version.ref = "grpc-kotlin" } grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc-java" } grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc-java" } +guava = { module = "com.google.guava:guava", version.ref = "guava" } kotlinLogging = { module = "io.github.oshai:kotlin-logging", version.ref = "kotlinLogging" } kotlinPoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt index a775d7cf2..10a06a04f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt @@ -35,11 +35,7 @@ object CodeGenerator { fun generate(contents: ProtoFileContents) = contents.types.flatMap { - generate( - it, - Context(emptyList(), contents.info) - ) - .map { type -> GeneratedType(it, type) } + generate(it, Context(emptyList(), contents.info)).map(::GeneratedType) } fun generate(type: TopLevelType, ctx: Context): Iterable = diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index e5d425ffc..08c73b7db 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -83,7 +83,7 @@ private class DeserializerGenerator( beginControlFlow("when (deserializer.readTag())") val constructor = buildCodeBlock { - add("0·->·return·%T(\n", msg.className) + add("0u·->·return·%T(\n", msg.className) withIndent { constructorLines(properties).forEach(::add) } @@ -92,7 +92,7 @@ private class DeserializerGenerator( addStatement("%L", constructor) deserializerInfo.forEach { addStatement( - "%L -> %N = %L", + "%Lu -> %N = %L", it.tag, it.fieldName, it.value @@ -156,7 +156,7 @@ private class DeserializerGenerator( CodeBlock.of("%T.from(unknownFields)", UnknownFieldSet::class) private class DeserializerInfo( - val tag: Int, + val tag: UInt, val fieldName: String, val value: CodeBlock ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index 02fc58d84..e8a2414cd 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -135,11 +135,11 @@ private class MapEntryGenerator( beginControlFlow("when (deserializer.readTag())") addStatement("%L", constructOnZero(value)) addStatement( - "${key.tag.value} -> key = %L", + "${key.tag.value}u -> key = %L", deserialize(key, ctx) ) addStatement( - "${value.tag.value} -> value = %L", + "${value.tag.value}u -> value = %L", deserialize(value, ctx) ) endControlFlow() @@ -170,7 +170,7 @@ private class MapEntryGenerator( private fun constructOnZero(f: StandardField) = buildCodeBlock { - add("0 -> return %T(key, value", msg.className) + add("0u -> return %T(key, value", msg.className) if (f.type == FieldType.Message) { add(" ?: %T{}", value.className) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt index 8a5f1b325..1227248f2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt @@ -166,11 +166,10 @@ class ProtoFileContents( ) class GeneratedType( - val rawType: TopLevelType, val typeSpec: TypeSpec ) -sealed class Tag(val value: Int) : Comparable { +sealed class Tag(val value: UInt) : Comparable { class Packed( number: Int ) : Tag(computeTag(number, 2)) @@ -188,4 +187,4 @@ sealed class Tag(val value: Int) : Comparable { } private fun computeTag(fieldNumber: Int, wireType: Int) = - (fieldNumber shl 3) or wireType + (fieldNumber shl 3).toUInt() or wireType.toUInt() diff --git a/protokt-core/src/jvmMain/kotlin/protokt/v1/google/protobuf/AnyUtil.kt b/protokt-core/src/jvmMain/kotlin/protokt/v1/google/protobuf/AnyUtil.kt index e49f3a546..301ca453c 100644 --- a/protokt-core/src/jvmMain/kotlin/protokt/v1/google/protobuf/AnyUtil.kt +++ b/protokt-core/src/jvmMain/kotlin/protokt/v1/google/protobuf/AnyUtil.kt @@ -49,17 +49,13 @@ inline fun Any.unpack(deserializer: KtDeserializer): return deserializer.deserialize(value) } -@Suppress("DEPRECATION") inline fun Any.isA() = typeUrl.substringAfterLast('/') == ( T::class.java.getAnnotation(KtGeneratedMessage::class.java)?.fullTypeName - ?: T::class.java.getAnnotation(com.toasttab.protokt.rt.KtGeneratedMessage::class.java)?.fullTypeName ?: error("class ${T::class} has no protokt generated message annotation") ) -@Suppress("DEPRECATION") private fun fullTypeName(klass: KClass<*>) = klass.java.getAnnotation(KtGeneratedMessage::class.java)?.fullTypeName - ?: klass.java.getAnnotation(com.toasttab.protokt.rt.KtGeneratedMessage::class.java)?.fullTypeName ?: error("class $klass has no protokt generated message annotation") diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts new file mode 100644 index 000000000..9ee0986fd --- /dev/null +++ b/protokt-reflect/build.gradle.kts @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.google.protobuf.gradle.proto + +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("protokt.multiplatform-conventions") +} + +localProtokt(false) +enablePublishing() +compatibleWithAndroid() +trackKotlinApiCompatibility() + +kotlin { + sourceSets { + val jvmMain by getting { + dependencies { + api(project(":protokt-core")) + api(libs.protobuf.java) + + implementation(kotlin("reflect")) + implementation(libs.guava) + implementation(libs.classgraph) + } + } + } +} + +tasks.withType { enabled = true } + +sourceSets { + main { + proto { + srcDir("../extensions/protokt-extensions-lite/src/main/proto") + } + } +} diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt new file mode 100644 index 000000000..1b7419bcf --- /dev/null +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@file:JvmName("KtMessages") + +package protokt.v1.google.protobuf + +import com.google.protobuf.DescriptorProtos +import com.google.protobuf.Descriptors +import com.google.protobuf.Descriptors.FieldDescriptor +import com.google.protobuf.DynamicMessage +import com.google.protobuf.MapEntry +import com.google.protobuf.Message +import com.google.protobuf.UnknownFieldSet +import com.google.protobuf.UnknownFieldSet.Field +import com.google.protobuf.UnsafeByteOperations +import com.google.protobuf.WireFormat +import com.toasttab.protokt.v1.ProtoktProtos +import io.github.classgraph.ClassGraph +import protokt.v1.Bytes +import protokt.v1.Converter +import protokt.v1.KtEnum +import protokt.v1.KtGeneratedFileDescriptor +import protokt.v1.KtGeneratedMessage +import protokt.v1.KtMessage +import protokt.v1.google.protobuf.RuntimeContext.Companion.DEFAULT_CONVERTERS +import kotlin.Any +import kotlin.reflect.KClass +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.findAnnotation + +fun KtMessage.toDynamicMessage(context: RuntimeContext): DynamicMessage = + context.protobufJavaValue(this) as DynamicMessage + +class RuntimeContext( + internal val descriptorsByFullTypeName: Map, + converters: Iterable>, +) { + private val convertersByWrappedType = converters.associateBy { it.wrapper } + + fun protobufJavaValue(value: Any?) = + when (value) { + is KtEnum -> value.value + is UInt -> value.toInt() + is ULong -> value.toLong() + is KtMessage -> toDynamicMessage(value, this) + is Bytes -> UnsafeByteOperations.unsafeWrap(value.asReadOnlyBuffer()) + + // pray + else -> value + } + + @Suppress("UNCHECKED_CAST") + fun unwrap( + value: Any, + field: FieldDescriptor, + ) = ((DEFAULT_CONVERTERS[field.messageType.fullName] ?: convertersByWrappedType.getValue(value::class)) as Converter).unwrap( + value, + ) + + companion object { + internal val DEFAULT_CONVERTERS: Map> = + mapOf( + "google.protobuf.DoubleValue" to DoubleValueConverter, + "google.protobuf.FloatValue" to FloatValueConverter, + "google.protobuf.Int64Value" to Int64ValueConverter, + "google.protobuf.UInt64Value" to UInt64ValueConverter, + "google.protobuf.Int32Value" to Int32ValueConverter, + "google.protobuf.UInt32Value" to UInt32ValueConverter, + "google.protobuf.BoolValue" to BoolValueConverter, + "google.protobuf.StringValue" to StringValueConverter, + "google.protobuf.BytesValue" to BytesValueConverter, + ) + + private val reflectiveContext by lazy { RuntimeContext(getDescriptorsByTypeName(), getConverters()) } + + fun getContextReflectively() = + reflectiveContext + } +} + +private fun getDescriptorsByTypeName() = + ClassGraph() + .enableAllInfo() + .scan() + .getClassesWithAnnotation(KtGeneratedFileDescriptor::class.java) + .asSequence() + .map { + @Suppress("UNCHECKED_CAST") + it.loadClass().kotlin as KClass + } + .map { klassWithDescriptor -> + klassWithDescriptor + .declaredMemberProperties + .single { it.returnType.classifier == FileDescriptor::class } + .get(klassWithDescriptor.objectInstance!!) as FileDescriptor + } + .flatMap { it.toProtobufJavaDescriptor().messageTypes } + .flatMap(::collectDescriptors) + .associateBy { it.fullName } + +private fun getConverters(): Iterable> { + val classLoader = Any::class.java.classLoader + + return classLoader.getResources("META-INF/services/${Converter::class.qualifiedName}") + .asSequence() + .flatMap { url -> + url.openStream() + .bufferedReader() + .useLines { lines -> + lines.map { it.substringBefore("#").trim() } + .filter { it.isNotEmpty() } + .map { classLoader.loadClass(it).kotlin.objectInstance as Converter<*, *> } + .toList() + } + }.asIterable() +} + +private fun collectDescriptors(descriptor: Descriptors.Descriptor): Iterable = + listOf(descriptor) + descriptor.nestedTypes.flatMap(::collectDescriptors) + +private fun FileDescriptor.toProtobufJavaDescriptor(): Descriptors.FileDescriptor = + Descriptors.FileDescriptor.buildFrom( + DescriptorProtos.FileDescriptorProto.parseFrom(proto.serialize()), + dependencies.map { it.toProtobufJavaDescriptor() }.toTypedArray(), + true, + ) + +private fun toDynamicMessage( + message: KtMessage, + context: RuntimeContext, +): Message { + val descriptor = + context.descriptorsByFullTypeName + .getValue(message::class.findAnnotation()!!.fullTypeName) + + return DynamicMessage.newBuilder(descriptor) + .apply { + descriptor.fields.forEach { field -> + ProtoktReflect.getField(message, field)?.let { value -> + setField( + field, + when { + field.type == Descriptors.FieldDescriptor.Type.ENUM -> + if (field.isRepeated) { + (value as List<*>).map { field.enumType.findValueByNumberCreatingIfUnknown(((it as KtEnum).value)) } + } else { + field.enumType.findValueByNumberCreatingIfUnknown(((value as KtEnum).value)) + } + + field.isMapField -> + convertMap(value, field, context) + + field.isRepeated -> + (value as List<*>).map(context::protobufJavaValue) + + isWrapped(field) -> + context.protobufJavaValue(context.unwrap(value, field)) + + else -> context.protobufJavaValue(value) + }, + ) + } + } + } + .setUnknownFields(mapUnknownFields(message)) + .build() +} + +private fun isWrapped(field: FieldDescriptor): Boolean { + val options = field.toProto().options.getExtension(ProtoktProtos.property) + return options.wrap.isNotEmpty() || + options.keyWrap.isNotEmpty() || + options.valueWrap.isNotEmpty() || + (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in DEFAULT_CONVERTERS) +} + +private fun convertMap( + value: Any, + field: FieldDescriptor, + context: RuntimeContext, +): List> { + val keyDesc = field.messageType.findFieldByNumber(1) + val valDesc = field.messageType.findFieldByNumber(2) + val keyDefault = + if (keyDesc.type == Descriptors.FieldDescriptor.Type.MESSAGE) { + null + } else { + keyDesc.defaultValue + } + + val valDefault = + if (valDesc.type == Descriptors.FieldDescriptor.Type.MESSAGE) { + null + } else { + valDesc.defaultValue + } + + val defaultEntry = + MapEntry.newDefaultInstance( + field.messageType, + WireFormat.FieldType.valueOf(keyDesc.type.name), + keyDefault, + WireFormat.FieldType.valueOf(valDesc.type.name), + valDefault, + ) as MapEntry + + return (value as Map<*, *>).map { (k, v) -> + defaultEntry.toBuilder() + .setKey(context.protobufJavaValue(k)) + .setValue(context.protobufJavaValue(v)) + .build() + } +} + +private fun mapUnknownFields(message: KtMessage): UnknownFieldSet { + val unknownFields = UnknownFieldSet.newBuilder() + + getUnknownFields(message).forEach { (number, field) -> + unknownFields.mergeField( + number.toInt(), + Field.newBuilder() + .apply { + field.varint.forEach { addVarint(it.value.toLong()) } + field.fixed32.forEach { addFixed32(it.value.toInt()) } + field.fixed64.forEach { addFixed64(it.value.toLong()) } + field.lengthDelimited.forEach { + addLengthDelimited( + UnsafeByteOperations.unsafeWrap(it.value.asReadOnlyBuffer()), + ) + } + } + .build(), + ) + } + + return unknownFields.build() +} diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt new file mode 100644 index 000000000..ac2c976bb --- /dev/null +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.google.protobuf + +import com.google.common.cache.CacheBuilder +import com.google.common.cache.CacheLoader +import com.google.protobuf.Descriptors +import com.google.protobuf.Descriptors.FieldDescriptor +import protokt.v1.Fixed32Val +import protokt.v1.Fixed64Val +import protokt.v1.KtEnum +import protokt.v1.KtMessage +import protokt.v1.KtProperty +import protokt.v1.LengthDelimitedVal +import protokt.v1.UnknownFieldSet +import protokt.v1.VarintVal +import java.nio.charset.StandardCharsets +import kotlin.Any +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.declaredMemberProperties +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.isSubclassOf + +internal object ProtoktReflect { + private val reflectedGettersByClass = + CacheBuilder.newBuilder() + .build( + object : CacheLoader, (FieldDescriptor, KtMessage) -> Any?>() { + override fun load(messageClass: KClass) = + { field: FieldDescriptor, message: KtMessage -> + topLevelProperty(messageClass)(field, message) + ?: oneofProperty(messageClass)(field, message) + ?: getUnknownField(field, message) + } + }, + ) + + private fun topLevelProperty(klass: KClass): (FieldDescriptor, KtMessage) -> Any? { + val gettersByNumber = gettersByNumber(klass) + return { field, instance -> gettersByNumber[field.number]?.invoke(instance) } + } + + private fun gettersByNumber(klass: KClass<*>): Map> = + klass.declaredMemberProperties + .map { it.findAnnotation()?.number to it } + .filter { (number, _) -> number != null } + .associate { (number, getter) -> + @Suppress("UNCHECKED_CAST") + number!! to getter as KProperty1 + } + + private fun oneofProperty(messageClass: KClass): (FieldDescriptor, KtMessage) -> Any? { + val oneofPropertiesSealedClasses = + messageClass + .nestedClasses + .filter { it.isSealed && !it.isSubclassOf(KtEnum::class) } + + val gettersByNumber = + buildMap { + oneofPropertiesSealedClasses.forEach { sealedClass -> + val oneofPropertyGetter = + messageClass.declaredMemberProperties + .single { it.returnType.classifier == sealedClass } + .let { + @Suppress("UNCHECKED_CAST") + it as KProperty1 + } + + sealedClass.nestedClasses.forEach { sealedClassSubtype -> + val (number, getterFromSubtype) = gettersByNumber(sealedClassSubtype).entries.single() + put(number) { msg: KtMessage -> + val oneofProperty = oneofPropertyGetter.get(msg) + if (sealedClassSubtype.isInstance(oneofProperty)) { + getterFromSubtype(oneofProperty!!) + } else { + null + } + } + } + } + } + + return { field, msg -> gettersByNumber[field.number]?.invoke(msg) } + } + + private fun getUnknownField( + field: FieldDescriptor, + message: KtMessage, + ) = getUnknownFields(message)[field.number.toUInt()]?.let { value -> + when { + value.varint.isNotEmpty() -> + value.varint + .map(VarintVal::value) + .map { + if (field.type == FieldDescriptor.Type.UINT64) { + it + } else { + it.toLong() + } + } + + value.fixed32.isNotEmpty() -> + value.fixed32.map(Fixed32Val::value) + + value.fixed64.isNotEmpty() -> + value.fixed64.map(Fixed64Val::value) + + value.lengthDelimited.isNotEmpty() -> + value.lengthDelimited + .map(LengthDelimitedVal::value) + .map { + if (field.type == Descriptors.FieldDescriptor.Type.STRING) { + StandardCharsets.UTF_8.decode(it.asReadOnlyBuffer()).toString() + } else { + it + } + } + + else -> error("unknown field for field number ${field.number} existed but was empty") + } + } + .let { + if (field.isRepeated) { + if (field.isMapField) { + it ?: emptyMap() + } else { + it ?: emptyList() + } + } else { + it?.first() + } + } + + fun getField( + message: KtMessage, + field: FieldDescriptor, + ): Any? = reflectedGettersByClass[message::class](field, message) +} + +fun getUnknownFields(message: KtMessage) = + message::class + .declaredMemberProperties + .firstOrNull { it.returnType.classifier == UnknownFieldSet::class } + .let { + @Suppress("UNCHECKED_CAST") + it as KProperty1 + } + .get(message) + .unknownFields diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt new file mode 100644 index 000000000..f280af7be --- /dev/null +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.google.protobuf + +import com.google.common.truth.Truth.assertThat +import org.junit.jupiter.api.Test + +class DynamicMessageTest { + @Test + fun `dynamic message serialized size`() { + val message = getAllSet() + + val dynamicMessage = message.toDynamicMessage(RuntimeContext.getContextReflectively()) + + assertThat(dynamicMessage.serializedSize).isEqualTo(message.messageSize) + } + + @Test + fun `dynamic message serialization`() { + val message = getAllSet() + + val dynamicMessage = message.toDynamicMessage(RuntimeContext.getContextReflectively()) + + assertThat(dynamicMessage.toByteArray()).isEqualTo(message.serialize()) + } +} diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt new file mode 100644 index 000000000..b6900d30e --- /dev/null +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.google.protobuf + +import protokt.v1.Bytes +import protokt.v1.proto3_unittest.ForeignEnum +import protokt.v1.proto3_unittest.ForeignMessage +import protokt.v1.proto3_unittest.TestAllTypes +import protokt.v1.protobuf_unittest_import.ImportMessage +import protokt.v1.protobuf_unittest_import.PublicImportMessage + +fun getAllSet() = + TestAllTypes { + optionalInt32 = 101 + optionalInt64 = 102 + optionalUint32 = 103u + optionalUint64 = 104u + optionalSint32 = 105 + optionalSint64 = 106 + optionalFixed32 = 107u + optionalFixed64 = 108u + optionalSfixed32 = 109 + optionalSfixed64 = 110 + optionalFloat = 111f + optionalDouble = 112.0 + optionalBool = true + optionalString = "114" + optionalNestedMessage = TestAllTypes.NestedMessage { bb = 115 } + optionalForeignMessage = ForeignMessage { c = 116 } + optionalNestedEnum = TestAllTypes.NestedEnum.FOO + optionalForeignEnum = ForeignEnum.FOREIGN_FOO + optionalStringPiece = "119" + optionalCord = "120" + optionalPublicImportMessage = PublicImportMessage { e = 121 } + optionalLazyMessage = TestAllTypes.NestedMessage { bb = 122 } + optionalUnverifiedLazyMessage = TestAllTypes.NestedMessage { bb = 123 } + + repeatedInt32 = listOf(124) + repeatedInt64 = listOf(125) + repeatedUint32 = listOf(126u) + repeatedUint64 = listOf(127u) + repeatedSint32 = listOf(128) + repeatedSint64 = listOf(129) + repeatedFixed32 = listOf(130u) + repeatedFixed64 = listOf(131u) + repeatedSfixed32 = listOf(132) + repeatedSfixed64 = listOf(133) + repeatedFloat = listOf(134f) + repeatedDouble = listOf(135.0) + repeatedBool = listOf(true) + repeatedString = listOf("136") + repeatedBytes = listOf(Bytes.from("137".toByteArray())) + repeatedNestedMessage = listOf(TestAllTypes.NestedMessage { bb = 138 }) + repeatedForeignMessage = listOf(ForeignMessage { c = 139 }) + repeatedImportMessage = listOf(ImportMessage { d = 140 }) + repeatedNestedEnum = listOf(TestAllTypes.NestedEnum.FOO) + repeatedForeignEnum = listOf(ForeignEnum.FOREIGN_FOO) + repeatedStringPiece = listOf("143") + repeatedCord = listOf("144") + repeatedLazyMessage = listOf(TestAllTypes.NestedMessage { bb = 145 }) + + oneofField = TestAllTypes.OneofField.OneofUint32(146u) + optionalLazyImportMessage = ImportMessage { d = 147 } + } diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto b/protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto new file mode 100644 index 000000000..6c2e6fff7 --- /dev/null +++ b/protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +// We don't put this in a package within proto2 because we need to make sure +// that the generated code doesn't depend on being in the proto2 namespace. +// In test_util.h we do +// "using namespace unittest_import = protobuf_unittest_import". +package protobuf_unittest_import; + +option optimize_for = SPEED; +option cc_enable_arenas = true; + +// Exercise the java_package option. +option java_package = "com.google.protobuf.test"; + +// Do not set a java_outer_classname here to verify that Proto2 works without +// one. + +// Test public import +import public "google/protobuf/unittest_import_public.proto"; + +message ImportMessage { + optional int32 d = 1; +} + +enum ImportEnum { + IMPORT_FOO = 7; + IMPORT_BAR = 8; + IMPORT_BAZ = 9; +} + +// To use an enum in a map, it must has the first value as 0. +enum ImportEnumForMap { + UNKNOWN = 0; + FOO = 1; + BAR = 2; +} diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto b/protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto new file mode 100644 index 000000000..a15e40e1d --- /dev/null +++ b/protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2008 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.test"; + +message PublicImportMessage { + optional int32 e = 1; +} diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto b/protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto new file mode 100644 index 000000000..03f370ce8 --- /dev/null +++ b/protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2008 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package proto3_unittest; + +import "google/protobuf/unittest_import.proto"; + +option optimize_for = SPEED; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + optional NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype = STRING_PIECE]; + string optional_cord = 25 [ctype = CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage optional_public_import_message = + 26; + + NestedMessage optional_lazy_message = 27 [lazy = true]; + NestedMessage optional_unverified_lazy_message = 28 [unverified_lazy = true]; + protobuf_unittest_import.ImportMessage optional_lazy_import_message = 115 + [lazy = true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; + repeated string repeated_cord = 55 [ctype = CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy = true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recursively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage {} + +// TestMessageWithDummy is also used to test behavior of unknown fields. +message TestMessageWithDummy { + // This field is only here for triggering copy-on-write; it's not intended to + // be serialized. + bool dummy = 536870911; +} + +// Same layout as TestOneof2 in unittest.proto to test unknown enum value +// parsing behavior in oneof. +message TestOneof2 { + oneof foo { + NestedEnum foo_enum = 6; + } + + enum NestedEnum { + UNKNOWN = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + } +} diff --git a/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt b/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt index bde4ab698..47f7357aa 100644 --- a/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt +++ b/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt @@ -29,7 +29,7 @@ interface KtMessageDeserializer { fun readSInt64(): Long fun readString(): String fun readUInt64(): ULong - fun readTag(): Int + fun readTag(): UInt fun readUnknown(): UnknownField fun readRepeated(packed: Boolean, acc: KtMessageDeserializer.() -> Unit) fun readMessage(m: KtDeserializer): T diff --git a/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt b/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt index 519f0dc1f..91ff7b642 100644 --- a/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt +++ b/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt @@ -17,7 +17,7 @@ package protokt.v1 internal fun deserializer(reader: Reader): KtMessageDeserializer { return object : KtMessageDeserializer { - var lastTag = 0 + var lastTag = 0u var endPosition = reader.len override fun readDouble() = @@ -53,14 +53,14 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { override fun readUInt64() = Long.fromProtobufJsLong(reader.uint64()).toULong() - override fun readTag(): Int { + override fun readTag(): UInt { lastTag = if (reader.pos == endPosition) { - 0 + 0u } else { val tag = readInt32() check(tag ushr 3 != 0) { "Invalid tag" } - tag + tag.toUInt() } return lastTag } @@ -73,7 +73,7 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { readBytes().toBytesSlice() override fun readUnknown(): UnknownField { - val fieldNumber = (lastTag ushr 3).toUInt() + val fieldNumber = (lastTag.toInt() ushr 3).toUInt() return when (tagWireType(lastTag)) { 0 -> UnknownField.varint(fieldNumber, readInt64()) @@ -115,5 +115,5 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { } } -private fun tagWireType(tag: Int) = - tag and ((1 shl 3) - 1) +private fun tagWireType(tag: UInt) = + tag.toInt() and ((1 shl 3) - 1) diff --git a/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt b/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt index 2a6c27b72..35edb64bc 100644 --- a/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt +++ b/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt @@ -15,6 +15,7 @@ package com.toasttab.protokt.rt +@Deprecated("use v1") @Target(AnnotationTarget.CLASS) annotation class KtGeneratedMessage( /** diff --git a/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt b/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt index 98bf6931f..a42e0632a 100644 --- a/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt +++ b/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt @@ -58,7 +58,7 @@ internal fun deserializer( stream.readUInt64().toULong() override fun readTag() = - stream.readTag() + stream.readTag().toUInt() override fun readBytes() = Bytes(stream.readByteArray()) diff --git a/settings.gradle.kts b/settings.gradle.kts index 220efaff0..bc1967b03 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -31,6 +31,7 @@ include( "protokt-codegen", "protokt-core", "protokt-core-lite", + "protokt-reflect", "protokt-runtime", "protokt-runtime-grpc", "protokt-runtime-grpc-lite", From dd96e8e2d23b88f171242ff24558806385f756cf Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 30 Dec 2023 17:11:25 -0500 Subject: [PATCH 02/38] api dump --- protokt-reflect/api/protokt-reflect.api | 1411 +++++++++++++++++++++++ protokt-runtime/api/protokt-runtime.api | 2 +- 2 files changed, 1412 insertions(+), 1 deletion(-) create mode 100644 protokt-reflect/api/protokt-reflect.api diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api new file mode 100644 index 000000000..d58278970 --- /dev/null +++ b/protokt-reflect/api/protokt-reflect.api @@ -0,0 +1,1411 @@ +public final class com/toasttab/protokt/v1/InetSocketAddressProto { + public static fun getDescriptor ()Lcom/google/protobuf/Descriptors$FileDescriptor; + public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistry;)V + public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistryLite;)V +} + +public final class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder { + public static final field ADDRESS_FIELD_NUMBER I + public static final field PORT_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public fun getAddress ()Lcom/google/protobuf/ByteString; + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getPort ()I + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun clearAddress ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun clearPort ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public fun getAddress ()Lcom/google/protobuf/ByteString; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getPort ()I + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun setAddress (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public fun setPort (I)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getAddress ()Lcom/google/protobuf/ByteString; + public abstract fun getPort ()I +} + +public final class com/toasttab/protokt/v1/ProtoktProtos { + public static final field CLASS_FIELD_NUMBER I + public static final field ENUM_FIELD_NUMBER I + public static final field ENUM_VALUE_FIELD_NUMBER I + public static final field FILE_FIELD_NUMBER I + public static final field METHOD_FIELD_NUMBER I + public static final field ONEOF_FIELD_NUMBER I + public static final field PROPERTY_FIELD_NUMBER I + public static final field SERVICE_FIELD_NUMBER I + public static final field class_ Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field enumValue Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field enum_ Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field file Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field method Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field oneof Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field property Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static final field service Lcom/google/protobuf/GeneratedMessage$GeneratedExtension; + public static fun getDescriptor ()Lcom/google/protobuf/Descriptors$FileDescriptor; + public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistry;)V + public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistryLite;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$EnumOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$EnumOptionsOrBuilder { + public static final field DEPRECATION_MESSAGE_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$EnumOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public fun clearDeprecationMessage ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public fun setDeprecationMessage (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public fun setDeprecationMessageBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$EnumOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getDeprecationMessage ()Ljava/lang/String; + public abstract fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$EnumValueOptionsOrBuilder { + public static final field DEPRECATION_MESSAGE_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$EnumValueOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public fun clearDeprecationMessage ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public fun setDeprecationMessage (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public fun setDeprecationMessageBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$EnumValueOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$EnumValueOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getDeprecationMessage ()Ljava/lang/String; + public abstract fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$FieldOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$FieldOptionsOrBuilder { + public static final field BYTES_SLICE_FIELD_NUMBER I + public static final field DEPRECATION_MESSAGE_FIELD_NUMBER I + public static final field KEY_WRAP_FIELD_NUMBER I + public static final field NON_NULL_FIELD_NUMBER I + public static final field VALUE_WRAP_FIELD_NUMBER I + public static final field WRAP_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public fun getBytesSlice ()Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getKeyWrap ()Ljava/lang/String; + public fun getKeyWrapBytes ()Lcom/google/protobuf/ByteString; + public fun getNonNull ()Z + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun getValueWrap ()Ljava/lang/String; + public fun getValueWrapBytes ()Lcom/google/protobuf/ByteString; + public fun getWrap ()Ljava/lang/String; + public fun getWrapBytes ()Lcom/google/protobuf/ByteString; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$FieldOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearBytesSlice ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearDeprecationMessage ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearKeyWrap ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearNonNull ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearValueWrap ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun clearWrap ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public fun getBytesSlice ()Z + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getKeyWrap ()Ljava/lang/String; + public fun getKeyWrapBytes ()Lcom/google/protobuf/ByteString; + public fun getNonNull ()Z + public fun getValueWrap ()Ljava/lang/String; + public fun getValueWrapBytes ()Lcom/google/protobuf/ByteString; + public fun getWrap ()Ljava/lang/String; + public fun getWrapBytes ()Lcom/google/protobuf/ByteString; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setBytesSlice (Z)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setDeprecationMessage (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setDeprecationMessageBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setKeyWrap (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setKeyWrapBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setNonNull (Z)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setValueWrap (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setValueWrapBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setWrap (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; + public fun setWrapBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FieldOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$FieldOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getBytesSlice ()Z + public abstract fun getDeprecationMessage ()Ljava/lang/String; + public abstract fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getKeyWrap ()Ljava/lang/String; + public abstract fun getKeyWrapBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getNonNull ()Z + public abstract fun getValueWrap ()Ljava/lang/String; + public abstract fun getValueWrapBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getWrap ()Ljava/lang/String; + public abstract fun getWrapBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$FileOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$FileOptionsOrBuilder { + public static final field FILE_DESCRIPTOR_OBJECT_NAME_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getFileDescriptorObjectName ()Ljava/lang/String; + public fun getFileDescriptorObjectNameBytes ()Lcom/google/protobuf/ByteString; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$FileOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public fun clearFileDescriptorObjectName ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getFileDescriptorObjectName ()Ljava/lang/String; + public fun getFileDescriptorObjectNameBytes ()Lcom/google/protobuf/ByteString; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public fun setFileDescriptorObjectName (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public fun setFileDescriptorObjectNameBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$FileOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$FileOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getFileDescriptorObjectName ()Ljava/lang/String; + public abstract fun getFileDescriptorObjectNameBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$MessageOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$MessageOptionsOrBuilder { + public static final field DEPRECATION_MESSAGE_FIELD_NUMBER I + public static final field IMPLEMENTS_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getImplements ()Ljava/lang/String; + public fun getImplementsBytes ()Lcom/google/protobuf/ByteString; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$MessageOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun clearDeprecationMessage ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun clearImplements ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getImplements ()Ljava/lang/String; + public fun getImplementsBytes ()Lcom/google/protobuf/ByteString; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun setDeprecationMessage (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun setDeprecationMessageBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun setImplements (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public fun setImplementsBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$MessageOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$MessageOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getDeprecationMessage ()Ljava/lang/String; + public abstract fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getImplements ()Ljava/lang/String; + public abstract fun getImplementsBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$MethodOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$MethodOptionsOrBuilder { + public static final field REQUEST_MARSHALLER_FIELD_NUMBER I + public static final field RESPONSE_MARSHALLER_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getRequestMarshaller ()Ljava/lang/String; + public fun getRequestMarshallerBytes ()Lcom/google/protobuf/ByteString; + public fun getResponseMarshaller ()Ljava/lang/String; + public fun getResponseMarshallerBytes ()Lcom/google/protobuf/ByteString; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$MethodOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun clearRequestMarshaller ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun clearResponseMarshaller ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getRequestMarshaller ()Ljava/lang/String; + public fun getRequestMarshallerBytes ()Lcom/google/protobuf/ByteString; + public fun getResponseMarshaller ()Ljava/lang/String; + public fun getResponseMarshallerBytes ()Lcom/google/protobuf/ByteString; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun setRequestMarshaller (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun setRequestMarshallerBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun setResponseMarshaller (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public fun setResponseMarshallerBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$MethodOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$MethodOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getRequestMarshaller ()Ljava/lang/String; + public abstract fun getRequestMarshallerBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getResponseMarshaller ()Ljava/lang/String; + public abstract fun getResponseMarshallerBytes ()Lcom/google/protobuf/ByteString; +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$OneofOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$OneofOptionsOrBuilder { + public static final field DEPRECATION_MESSAGE_FIELD_NUMBER I + public static final field IMPLEMENTS_FIELD_NUMBER I + public static final field NON_NULL_FIELD_NUMBER I + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getImplements ()Ljava/lang/String; + public fun getImplementsBytes ()Lcom/google/protobuf/ByteString; + public fun getNonNull ()Z + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$OneofOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun clearDeprecationMessage ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun clearImplements ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun clearNonNull ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions; + public fun getDeprecationMessage ()Ljava/lang/String; + public fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getImplements ()Ljava/lang/String; + public fun getImplementsBytes ()Lcom/google/protobuf/ByteString; + public fun getNonNull ()Z + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun setDeprecationMessage (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun setDeprecationMessageBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun setImplements (Ljava/lang/String;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun setImplementsBytes (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public fun setNonNull (Z)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$OneofOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$OneofOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { + public abstract fun getDeprecationMessage ()Ljava/lang/String; + public abstract fun getDeprecationMessageBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getImplements ()Ljava/lang/String; + public abstract fun getImplementsBytes ()Lcom/google/protobuf/ByteString; + public abstract fun getNonNull ()Z +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$ServiceOptions : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/ProtoktProtos$ServiceOptionsOrBuilder { + public fun equals (Ljava/lang/Object;)Z + public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getParserForType ()Lcom/google/protobuf/Parser; + public fun getSerializedSize ()I + public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; + public fun hashCode ()I + public final fun isInitialized ()Z + public static fun newBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public static fun newBuilder (Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; + public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; + public fun newBuilderForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static fun parser ()Lcom/google/protobuf/Parser; + public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; + public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; + public fun toBuilder ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V +} + +public final class com/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/ProtoktProtos$ServiceOptionsOrBuilder { + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun build ()Lcom/google/protobuf/Message; + public synthetic fun build ()Lcom/google/protobuf/MessageLite; + public fun build ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public synthetic fun buildPartial ()Lcom/google/protobuf/Message; + public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; + public fun buildPartial ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; + public fun clear ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; + public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; + public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; + public fun clone ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun clone ()Ljava/lang/Object; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; + public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; + public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions; + public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; + public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; + public final fun isInitialized ()Z + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; + public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; + public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public fun mergeFrom (Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; + public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; + public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; + public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/ProtoktProtos$ServiceOptions$Builder; +} + +public abstract interface class com/toasttab/protokt/v1/ProtoktProtos$ServiceOptionsOrBuilder : com/google/protobuf/MessageOrBuilder { +} + +public final class protokt/v1/EnumOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/EnumOptions$Deserializer; + public synthetic fun (Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/EnumOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/EnumOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/EnumOptions; + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setDeprecationMessage (Ljava/lang/String;)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/EnumOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/EnumOptions; + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumOptions; +} + +public final class protokt/v1/EnumValueOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/EnumValueOptions$Deserializer; + public synthetic fun (Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumValueOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/EnumValueOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumValueOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/EnumValueOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/EnumValueOptions; + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setDeprecationMessage (Ljava/lang/String;)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/EnumValueOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/EnumValueOptions; + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/EnumValueOptions; +} + +public final class protokt/v1/FieldOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/FieldOptions$Deserializer; + public synthetic fun (ZLjava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FieldOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/FieldOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getBytesSlice ()Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getKeyWrap ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getNonNull ()Z + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun getValueWrap ()Ljava/lang/String; + public final fun getWrap ()Ljava/lang/String; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FieldOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/FieldOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/FieldOptions; + public final fun getBytesSlice ()Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getKeyWrap ()Ljava/lang/String; + public final fun getNonNull ()Z + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun getValueWrap ()Ljava/lang/String; + public final fun getWrap ()Ljava/lang/String; + public final fun setBytesSlice (Z)V + public final fun setDeprecationMessage (Ljava/lang/String;)V + public final fun setKeyWrap (Ljava/lang/String;)V + public final fun setNonNull (Z)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V + public final fun setValueWrap (Ljava/lang/String;)V + public final fun setWrap (Ljava/lang/String;)V +} + +public final class protokt/v1/FieldOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/FieldOptions; + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FieldOptions; +} + +public final class protokt/v1/FileOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/FileOptions$Deserializer; + public synthetic fun (Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FileOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/FileOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getFileDescriptorObjectName ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FileOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/FileOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/FileOptions; + public final fun getFileDescriptorObjectName ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setFileDescriptorObjectName (Ljava/lang/String;)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/FileOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/FileOptions; + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FileOptions; +} + +public final class protokt/v1/InetSocketAddress : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/InetSocketAddress$Deserializer; + public synthetic fun (Lprotokt/v1/Bytes;ILprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/InetSocketAddress; + public fun equals (Ljava/lang/Object;)Z + public final fun getAddress ()Lprotokt/v1/Bytes; + public fun getMessageSize ()I + public final fun getPort ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/InetSocketAddress$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/InetSocketAddress; + public final fun getAddress ()Lprotokt/v1/Bytes; + public final fun getPort ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setAddress (Lprotokt/v1/Bytes;)V + public final fun setPort (I)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/InetSocketAddress$Deserializer : protokt/v1/AbstractKtDeserializer { + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/InetSocketAddress; + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; +} + +public final class protokt/v1/InetSocketAddressProto { + public static final field INSTANCE Lprotokt/v1/InetSocketAddressProto; + public final fun getDescriptor ()Lprotokt/v1/google/protobuf/FileDescriptor; +} + +public final class protokt/v1/Inet_socket_addressKt { + public static final fun getDescriptor (Lprotokt/v1/InetSocketAddress$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; +} + +public final class protokt/v1/MessageOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/MessageOptions$Deserializer; + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MessageOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/MessageOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getImplements ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MessageOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/MessageOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/MessageOptions; + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getImplements ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setDeprecationMessage (Ljava/lang/String;)V + public final fun setImplements (Ljava/lang/String;)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/MessageOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/MessageOptions; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MessageOptions; +} + +public final class protokt/v1/MethodOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/MethodOptions$Deserializer; + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MethodOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/MethodOptions; + public fun equals (Ljava/lang/Object;)Z + public fun getMessageSize ()I + public final fun getRequestMarshaller ()Ljava/lang/String; + public final fun getResponseMarshaller ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MethodOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/MethodOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/MethodOptions; + public final fun getRequestMarshaller ()Ljava/lang/String; + public final fun getResponseMarshaller ()Ljava/lang/String; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setRequestMarshaller (Ljava/lang/String;)V + public final fun setResponseMarshaller (Ljava/lang/String;)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/MethodOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/MethodOptions; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/MethodOptions; +} + +public final class protokt/v1/OneofOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/OneofOptions$Deserializer; + public synthetic fun (ZLjava/lang/String;Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/OneofOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/OneofOptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getImplements ()Ljava/lang/String; + public fun getMessageSize ()I + public final fun getNonNull ()Z + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/OneofOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/OneofOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/OneofOptions; + public final fun getDeprecationMessage ()Ljava/lang/String; + public final fun getImplements ()Ljava/lang/String; + public final fun getNonNull ()Z + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setDeprecationMessage (Ljava/lang/String;)V + public final fun setImplements (Ljava/lang/String;)V + public final fun setNonNull (Z)V + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/OneofOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/OneofOptions; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/OneofOptions; +} + +public final class protokt/v1/ProtoktKt { + public static final fun getDescriptor (Lprotokt/v1/EnumOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/EnumValueOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/FieldOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/FileOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/MessageOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/MethodOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/OneofOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; + public static final fun getDescriptor (Lprotokt/v1/ServiceOptions$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; +} + +public final class protokt/v1/ProtoktProtos { + public static final field INSTANCE Lprotokt/v1/ProtoktProtos; + public final fun getDescriptor ()Lprotokt/v1/google/protobuf/FileDescriptor; +} + +public final class protokt/v1/ServiceOptions : protokt/v1/AbstractKtMessage { + public static final field Deserializer Lprotokt/v1/ServiceOptions$Deserializer; + public synthetic fun (Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/ServiceOptions; + public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/ServiceOptions; + public fun equals (Ljava/lang/Object;)Z + public fun getMessageSize ()I + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public fun hashCode ()I + public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/ServiceOptions; + public fun serialize (Lprotokt/v1/KtMessageSerializer;)V + public fun toString ()Ljava/lang/String; +} + +public final class protokt/v1/ServiceOptions$Builder { + public fun ()V + public final fun build ()Lprotokt/v1/ServiceOptions; + public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; + public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V +} + +public final class protokt/v1/ServiceOptions$Deserializer : protokt/v1/AbstractKtDeserializer { + public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; + public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/ServiceOptions; + public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/ServiceOptions; +} + +public final class protokt/v1/google/protobuf/KtMessages { + public static final fun toDynamicMessage (Lprotokt/v1/KtMessage;Lprotokt/v1/google/protobuf/RuntimeContext;)Lcom/google/protobuf/DynamicMessage; +} + +public final class protokt/v1/google/protobuf/ProtoktReflectKt { + public static final fun getUnknownFields (Lprotokt/v1/KtMessage;)Ljava/util/Map; +} + +public final class protokt/v1/google/protobuf/RuntimeContext { + public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; + public fun (Ljava/util/Map;Ljava/lang/Iterable;)V + public final fun protobufJavaValue (Ljava/lang/Object;)Ljava/lang/Object; + public final fun unwrap (Ljava/lang/Object;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; +} + +public final class protokt/v1/google/protobuf/RuntimeContext$Companion { + public final fun getContextReflectively ()Lprotokt/v1/google/protobuf/RuntimeContext; +} + diff --git a/protokt-runtime/api/protokt-runtime.api b/protokt-runtime/api/protokt-runtime.api index 39144b2b0..072746778 100644 --- a/protokt-runtime/api/protokt-runtime.api +++ b/protokt-runtime/api/protokt-runtime.api @@ -595,7 +595,7 @@ public abstract interface class protokt/v1/KtMessageDeserializer { public abstract fun readSInt32 ()I public abstract fun readSInt64 ()J public abstract fun readString ()Ljava/lang/String; - public abstract fun readTag ()I + public abstract fun readTag-pVg5ArA ()I public fun readUInt32-pVg5ArA ()I public abstract fun readUInt64-s-VKNKU ()J public abstract fun readUnknown ()Lprotokt/v1/UnknownField; From 72fbb9f13f3376cad01efbc95eac3e9bb6834c2f Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 30 Dec 2023 17:24:50 -0500 Subject: [PATCH 03/38] fix --- protokt-reflect/api/protokt-reflect.api | 5 +++++ .../jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt | 2 +- .../kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index d58278970..2f4c5a677 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1394,6 +1394,11 @@ public final class protokt/v1/google/protobuf/KtMessages { public static final fun toDynamicMessage (Lprotokt/v1/KtMessage;Lprotokt/v1/google/protobuf/RuntimeContext;)Lcom/google/protobuf/DynamicMessage; } +public final class protokt/v1/google/protobuf/ProtoktReflect { + public static final field INSTANCE Lprotokt/v1/google/protobuf/ProtoktReflect; + public final fun getField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; +} + public final class protokt/v1/google/protobuf/ProtoktReflectKt { public static final fun getUnknownFields (Lprotokt/v1/KtMessage;)Ljava/util/Map; } diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 1b7419bcf..361c9c297 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -112,7 +112,7 @@ private fun getDescriptorsByTypeName() = .associateBy { it.fullName } private fun getConverters(): Iterable> { - val classLoader = Any::class.java.classLoader + val classLoader = Thread.currentThread().contextClassLoader return classLoader.getResources("META-INF/services/${Converter::class.qualifiedName}") .asSequence() diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt index ac2c976bb..13420b241 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt @@ -35,7 +35,7 @@ import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.isSubclassOf -internal object ProtoktReflect { +object ProtoktReflect { private val reflectedGettersByClass = CacheBuilder.newBuilder() .build( From da3ff2e035ebc75323d47ad83ebaf0fcb66147cc Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 30 Dec 2023 17:31:02 -0500 Subject: [PATCH 04/38] internal --- protokt-reflect/api/protokt-reflect.api | 1 - .../src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index 2f4c5a677..3133d42b1 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1407,7 +1407,6 @@ public final class protokt/v1/google/protobuf/RuntimeContext { public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; public fun (Ljava/util/Map;Ljava/lang/Iterable;)V public final fun protobufJavaValue (Ljava/lang/Object;)Ljava/lang/Object; - public final fun unwrap (Ljava/lang/Object;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; } public final class protokt/v1/google/protobuf/RuntimeContext$Companion { diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 361c9c297..fce851146 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -63,7 +63,7 @@ class RuntimeContext( } @Suppress("UNCHECKED_CAST") - fun unwrap( + internal fun unwrap( value: Any, field: FieldDescriptor, ) = ((DEFAULT_CONVERTERS[field.messageType.fullName] ?: convertersByWrappedType.getValue(value::class)) as Converter).unwrap( From 58b1d4c35edc5159bef9d66e0ba5a27ae695d745 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 20:43:08 -0500 Subject: [PATCH 05/38] reorganize shared but unpublished code --- buildSrc/build.gradle.kts | 9 ++ buildSrc/src/main/kotlin/LocalProtoktBuild.kt | 10 -- .../protokt/v1/gradle/ProtoktExtension.kt | 0 .../protobuf/gradle/GenerateProtoTaskExt.kt | 0 .../protokt/v1/gradle/DslExtensions.kt | 0 .../protokt/v1/gradle/ProtobufBuild.kt | 0 .../protokt/v1/gradle/ProtoktBuild.kt | 0 examples/grpc-java-lite/build.gradle.kts | 3 +- examples/grpc-kotlin-lite/build.gradle.kts | 2 +- .../jvm-lite/build.gradle.kts | 3 +- protokt-codegen/build.gradle.kts | 9 +- .../protokt/v1/codegen/generate/Implements.kt | 2 +- .../protokt/v1/codegen/generate/Wrapper.kt | 24 ++-- .../protokt/v1/codegen/util/PluginParams.kt | 1 + protokt-gradle-plugin/build.gradle.kts | 12 +- protokt-reflect/build.gradle.kts | 8 ++ .../protokt/v1/google/protobuf/KtMessages.kt | 109 ++++++++++----- .../v1/google/protobuf/DynamicMessageTest.kt | 122 +++++++++++++++- .../protokt/v1/google/protobuf/TestUtil.kt | 2 +- .../protokt/v1/testing/wrappers_dynamic.proto | 132 ++++++++++++++++++ protokt-util/build.gradle.kts | 27 ---- settings.gradle.kts | 1 - testing/options/build.gradle.kts | 8 ++ .../v1/testing}/ProtoktExtensionsTest.kt | 3 +- testing/plugin-options/lite/build.gradle.kts | 9 +- .../build.gradle.kts | 2 +- .../protokt/v1/util/ProtoktExtentions.kt | 0 .../protokt/v1/reflect}/ClassLookup.kt | 43 +++--- 28 files changed, 409 insertions(+), 132 deletions(-) rename buildSrc/src/{main/kotlin => shared/codegen}/protokt/v1/gradle/ProtoktExtension.kt (100%) rename buildSrc/src/{main/kotlin => shared/gradle-plugin}/com/google/protobuf/gradle/GenerateProtoTaskExt.kt (100%) rename buildSrc/src/{main/kotlin => shared/gradle-plugin}/protokt/v1/gradle/DslExtensions.kt (100%) rename buildSrc/src/{main/kotlin => shared/gradle-plugin}/protokt/v1/gradle/ProtobufBuild.kt (100%) rename buildSrc/src/{main/kotlin => shared/gradle-plugin}/protokt/v1/gradle/ProtoktBuild.kt (100%) create mode 100644 protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto delete mode 100644 protokt-util/build.gradle.kts rename {protokt-util/src/test/kotlin/protokt/v1/util => testing/options/src/test/kotlin/protokt/v1/testing}/ProtoktExtensionsTest.kt (91%) rename {protokt-util/src/main/kotlin => unpublished/src/lite-util}/protokt/v1/util/ProtoktExtentions.kt (100%) rename {protokt-codegen/src/main/kotlin/protokt/v1/codegen/util => unpublished/src/reflect/protokt/v1/reflect}/ClassLookup.kt (74%) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 2df41b5e4..324ed268d 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -42,3 +42,12 @@ dependencies { implementation(kotlin("gradle-plugin-api")) implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) } + +sourceSets { + main { + java { + srcDir("src/shared/codegen") + srcDir("src/shared/gradle-plugin") + } + } +} diff --git a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt index a6834037f..72061d199 100644 --- a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt +++ b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt @@ -15,10 +15,7 @@ import com.google.protobuf.gradle.GenerateProtoTask import org.gradle.api.Project -import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.compile.JavaCompile -import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.the import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl import protokt.v1.gradle.CODEGEN_NAME @@ -37,13 +34,6 @@ fun Project.localProtokt(disableJava: Boolean = true) { } } -fun Project.includeBuildSrc(vararg filePatterns: String) { - the()["main"].java { - srcDir(rootProject.file("buildSrc/src/main/kotlin")) - filePatterns.forEach { include(it) } - } -} - fun Project.pureKotlin() { tasks.withType { enabled = false diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktExtension.kt b/buildSrc/src/shared/codegen/protokt/v1/gradle/ProtoktExtension.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktExtension.kt rename to buildSrc/src/shared/codegen/protokt/v1/gradle/ProtoktExtension.kt diff --git a/buildSrc/src/main/kotlin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt b/buildSrc/src/shared/gradle-plugin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt similarity index 100% rename from buildSrc/src/main/kotlin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt rename to buildSrc/src/shared/gradle-plugin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/DslExtensions.kt b/buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/DslExtensions.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/DslExtensions.kt rename to buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/DslExtensions.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt b/buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/ProtobufBuild.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt rename to buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/ProtobufBuild.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt b/buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/ProtoktBuild.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt rename to buildSrc/src/shared/gradle-plugin/protokt/v1/gradle/ProtoktBuild.kt diff --git a/examples/grpc-java-lite/build.gradle.kts b/examples/grpc-java-lite/build.gradle.kts index 5f8edc3f1..d5a23772f 100644 --- a/examples/grpc-java-lite/build.gradle.kts +++ b/examples/grpc-java-lite/build.gradle.kts @@ -36,8 +36,6 @@ dependencies { implementation(libs.jackson) runtimeOnly(libs.protobuf.lite) - - testImplementation(project(":protokt-util")) } sourceSets { @@ -51,6 +49,7 @@ sourceSets { test { java { srcDir(liteOptionTestSourceDir()) + srcDir(rootProject.file("unpublished/src/lite-util")) } } } diff --git a/examples/grpc-kotlin-lite/build.gradle.kts b/examples/grpc-kotlin-lite/build.gradle.kts index a1b1c9082..804598fdb 100644 --- a/examples/grpc-kotlin-lite/build.gradle.kts +++ b/examples/grpc-kotlin-lite/build.gradle.kts @@ -43,7 +43,6 @@ dependencies { testImplementation(kotlin("test-junit")) testImplementation(libs.grpc.testing) - testImplementation(project(":protokt-util")) } sourceSets { @@ -59,6 +58,7 @@ sourceSets { test { java { srcDir("../grpc-kotlin/src/test/kotlin") + srcDir(rootProject.file("unpublished/src/lite-util")) srcDir(liteOptionTestSourceDir()) } } diff --git a/gradle-plugin-integration-test/jvm-lite/build.gradle.kts b/gradle-plugin-integration-test/jvm-lite/build.gradle.kts index 62468f4a9..5663f8af2 100644 --- a/gradle-plugin-integration-test/jvm-lite/build.gradle.kts +++ b/gradle-plugin-integration-test/jvm-lite/build.gradle.kts @@ -36,7 +36,6 @@ dependencies { testImplementation(kotlin("test-junit5")) testImplementation(libs.junit.jupiter) testImplementation(libs.protobuf.java) - testImplementation("com.toasttab.protokt:protokt-util:$version") } sourceSets { @@ -53,6 +52,8 @@ sourceSets { check(file(lite).exists()) srcDir(common) srcDir(lite) + + srcDir(rootProject.file("../unpublished/src/lite-util")) } } } diff --git a/protokt-codegen/build.gradle.kts b/protokt-codegen/build.gradle.kts index c0a05eaef..c354dfb87 100644 --- a/protokt-codegen/build.gradle.kts +++ b/protokt-codegen/build.gradle.kts @@ -81,6 +81,10 @@ tasks.withType { sourceSets { main { + java { + srcDir("../unpublished/src/reflect") + srcDir("../buildSrc/src/shared/codegen") + } proto { srcDir("../extensions/protokt-extensions-lite/src/main/proto") } @@ -93,8 +97,3 @@ buildConfig { buildConfigField("String", "DEFAULT_PROTOBUF_VERSION", "\"${libs.versions.protobuf.java.get()}\"") buildConfigField("String", "PROTOKT_VERSION", "\"$version\"") } - -includeBuildSrc( - "protokt/v1/gradle/ProtoktExtension.kt", - "**/*.java" // don't override the protobuf-gradle-plugin; todo: fix this function to not need this -) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt index 23fe0331b..8ed309e60 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt @@ -27,7 +27,7 @@ object Implements { msg: Message ) = msg.superInterface(ctx) - ?.let { fieldName in ctx.info.context.classLookup.properties(it) } + ?.let { fieldName in ctx.info.context.classLookup.properties(it.canonicalName) } ?: false fun TypeSpec.Builder.handleSuperInterface(implements: ClassName?, v: OneofGeneratorInfo? = null) = diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index edfafd536..27c331e9c 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -26,7 +26,7 @@ import protokt.v1.OptimizedSizeOfConverter import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.WellKnownTypes.wrapWithWellKnownInterception -import protokt.v1.codegen.util.ConverterDetails +import protokt.v1.reflect.ConverterDetails import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.GeneratorContext import protokt.v1.codegen.util.StandardField @@ -112,10 +112,10 @@ internal object Wrapper { converterDetails: ConverterDetails, access: CodeBlock, ) = - CodeBlock.of("%T.%L(%L)", converterDetails.converterClassName, method.name, access) + CodeBlock.of("%T.%L(%L)", converterDetails.converterClass.asClassName(), method.name, access) fun wrapper(f: StandardField, ctx: Context) = - f.withWrapper(ctx.info.context, ConverterDetails::converterClassName) + f.withWrapper(ctx.info.context, ::converterClassName) fun interceptRead(f: StandardField, readFunction: CodeBlock) = if (f.bytesSlice) { @@ -139,7 +139,7 @@ internal object Wrapper { if (f.bytesSlice) { BytesSlice::class.asTypeName() } else { - f.withWrapper(ctx.info.context, ConverterDetails::kotlinClassName) + f.withWrapper(ctx.info.context, ::kotlinClassName) } private val StandardField.bytesSlice @@ -156,16 +156,22 @@ internal object Wrapper { ) fun interceptMapKeyTypeName(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ConverterDetails::kotlinClassName) + f.withKeyWrap(ctx, ::kotlinClassName) fun mapKeyConverter(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ConverterDetails::converterClassName) + f.withKeyWrap(ctx, ::converterClassName) fun interceptMapValueTypeName(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ConverterDetails::kotlinClassName) + f.withValueWrap(ctx, ::kotlinClassName) fun mapValueConverter(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ConverterDetails::converterClassName) + f.withValueWrap(ctx, ::converterClassName) + + private fun kotlinClassName(converterDetails: ConverterDetails) = + ClassName.bestGuess(converterDetails.kotlinCanonicalClassName) + + private fun converterClassName(converterDetails: ConverterDetails) = + converterDetails.converterClass.asClassName() private fun StandardField.withValueWrap( ctx: Context, @@ -178,5 +184,5 @@ internal object Wrapper { ) private fun converter(protoClassName: ClassName, kotlinClassName: ClassName, ctx: GeneratorContext) = - ctx.classLookup.converter(protoClassName, kotlinClassName) + ctx.classLookup.converter(protoClassName.canonicalName, kotlinClassName.canonicalName) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt index e2ce16e45..c0b196e74 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt @@ -26,6 +26,7 @@ import protokt.v1.gradle.GENERATE_TYPES import protokt.v1.gradle.KOTLIN_EXTRA_CLASSPATH import protokt.v1.gradle.ProtoktExtension import protokt.v1.gradle.ProtoktExtension.Generate +import protokt.v1.reflect.ClassLookup import java.net.URLDecoder import kotlin.reflect.full.declaredMemberProperties diff --git a/protokt-gradle-plugin/build.gradle.kts b/protokt-gradle-plugin/build.gradle.kts index 84141b5a4..3746d9b60 100644 --- a/protokt-gradle-plugin/build.gradle.kts +++ b/protokt-gradle-plugin/build.gradle.kts @@ -61,10 +61,14 @@ dependencies { implementation(libs.protobuf.gradlePlugin) } -includeBuildSrc( - "protokt/v1/gradle/*", - "com/google/protobuf/gradle/*" -) +sourceSets { + main { + java { + srcDir("../buildSrc/src/shared/codegen") + srcDir("../buildSrc/src/shared/gradle-plugin") + } + } +} buildConfig { useKotlinOutput { topLevelConstants = true } diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 9ee0986fd..41f3e44ad 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -14,6 +14,7 @@ */ import com.google.protobuf.gradle.proto +import protokt.v1.gradle.testProtoktExtensions /* * Copyright (c) 2023 Toast, Inc. @@ -58,8 +59,15 @@ tasks.withType { enabled = true } sourceSets { main { + java { + srcDir("../unpublished/src/reflect") + } proto { srcDir("../extensions/protokt-extensions-lite/src/main/proto") } } } + +dependencies { + testProtoktExtensions(project(":extensions:protokt-extensions")) +} diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index fce851146..a42e28364 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -36,21 +36,28 @@ import protokt.v1.KtGeneratedFileDescriptor import protokt.v1.KtGeneratedMessage import protokt.v1.KtMessage import protokt.v1.google.protobuf.RuntimeContext.Companion.DEFAULT_CONVERTERS +import protokt.v1.reflect.ClassLookup import kotlin.Any import kotlin.reflect.KClass import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.findAnnotation fun KtMessage.toDynamicMessage(context: RuntimeContext): DynamicMessage = - context.protobufJavaValue(this) as DynamicMessage + context.convertValue(this) as DynamicMessage class RuntimeContext( - internal val descriptorsByFullTypeName: Map, + descriptors: Iterable, converters: Iterable>, ) { - private val convertersByWrappedType = converters.associateBy { it.wrapper } + internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } + private val convertersByWrappedType = converters.associateBy { it.wrapper to type(it.wrapped) } - fun protobufJavaValue(value: Any?) = + private fun type(klass: KClass<*>): KClass<*> = + when { + else -> error("unimplemented: $klass") + } + + fun convertValue(value: Any?) = when (value) { is KtEnum -> value.value is UInt -> value.toInt() @@ -62,13 +69,20 @@ class RuntimeContext( else -> value } - @Suppress("UNCHECKED_CAST") - internal fun unwrap( - value: Any, - field: FieldDescriptor, - ) = ((DEFAULT_CONVERTERS[field.messageType.fullName] ?: convertersByWrappedType.getValue(value::class)) as Converter).unwrap( - value, - ) + internal fun unwrap(value: Any, field: FieldDescriptor): Any { + val defaultConverter = + if (field.type == FieldDescriptor.Type.MESSAGE) { + DEFAULT_CONVERTERS[field.messageType.fullName] + } else { + null + } + + // todo! + val converter = defaultConverter ?: convertersByWrappedType.getValue(value::class to Any::class) + + @Suppress("UNCHECKED_CAST") + return (converter as Converter).unwrap(value) + } companion object { internal val DEFAULT_CONVERTERS: Map> = @@ -84,23 +98,28 @@ class RuntimeContext( "google.protobuf.BytesValue" to BytesValueConverter, ) - private val reflectiveContext by lazy { RuntimeContext(getDescriptorsByTypeName(), getConverters()) } + private val reflectiveContext by lazy { + ClassLookup(emptyList()) + RuntimeContext(getDescriptors(), getConverters()) + } fun getContextReflectively() = reflectiveContext } } -private fun getDescriptorsByTypeName() = +private fun getDescriptors() = ClassGraph() - .enableAllInfo() + .enableAnnotationInfo() .scan() - .getClassesWithAnnotation(KtGeneratedFileDescriptor::class.java) - .asSequence() - .map { - @Suppress("UNCHECKED_CAST") - it.loadClass().kotlin as KClass + .use { + it.getClassesWithAnnotation(KtGeneratedFileDescriptor::class.java) + .map { info -> + @Suppress("UNCHECKED_CAST") + info.loadClass().kotlin as KClass + } } + .asSequence() .map { klassWithDescriptor -> klassWithDescriptor .declaredMemberProperties @@ -109,7 +128,7 @@ private fun getDescriptorsByTypeName() = } .flatMap { it.toProtobufJavaDescriptor().messageTypes } .flatMap(::collectDescriptors) - .associateBy { it.fullName } + .asIterable() private fun getConverters(): Iterable> { val classLoader = Thread.currentThread().contextClassLoader @@ -143,7 +162,7 @@ private fun toDynamicMessage( context: RuntimeContext, ): Message { val descriptor = - context.descriptorsByFullTypeName + context.descriptorsByTypeName .getValue(message::class.findAnnotation()!!.fullTypeName) return DynamicMessage.newBuilder(descriptor) @@ -164,12 +183,12 @@ private fun toDynamicMessage( convertMap(value, field, context) field.isRepeated -> - (value as List<*>).map(context::protobufJavaValue) + (value as List<*>).map(context::convertValue) isWrapped(field) -> - context.protobufJavaValue(context.unwrap(value, field)) + context.convertValue(context.unwrap(value, field)) - else -> context.protobufJavaValue(value) + else -> context.convertValue(value) }, ) } @@ -180,11 +199,28 @@ private fun toDynamicMessage( } private fun isWrapped(field: FieldDescriptor): Boolean { - val options = field.toProto().options.getExtension(ProtoktProtos.property) - return options.wrap.isNotEmpty() || - options.keyWrap.isNotEmpty() || - options.valueWrap.isNotEmpty() || - (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in DEFAULT_CONVERTERS) + if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in DEFAULT_CONVERTERS) { + return true + } + + val options = field.toProto().options + + val propertyOptions = + if (options.hasField(ProtoktProtos.property.descriptor)) { + options.getField(ProtoktProtos.property.descriptor) as ProtoktProtos.FieldOptions + } else if (options.unknownFields.hasField(ProtoktProtos.property.number)) { + ProtoktProtos.FieldOptions.parseFrom( + options.unknownFields.getField(ProtoktProtos.property.number) + .lengthDelimitedList + .last() + ) + } else { + return false + } + + return propertyOptions.wrap.isNotEmpty() || + propertyOptions.keyWrap.isNotEmpty() || + propertyOptions.valueWrap.isNotEmpty() } private fun convertMap( @@ -194,6 +230,7 @@ private fun convertMap( ): List> { val keyDesc = field.messageType.findFieldByNumber(1) val valDesc = field.messageType.findFieldByNumber(2) + val keyDefault = if (keyDesc.type == Descriptors.FieldDescriptor.Type.MESSAGE) { null @@ -214,13 +251,13 @@ private fun convertMap( WireFormat.FieldType.valueOf(keyDesc.type.name), keyDefault, WireFormat.FieldType.valueOf(valDesc.type.name), - valDefault, + valDefault ) as MapEntry return (value as Map<*, *>).map { (k, v) -> defaultEntry.toBuilder() - .setKey(context.protobufJavaValue(k)) - .setValue(context.protobufJavaValue(v)) + .setKey(context.convertValue(k)) + .setValue(context.convertValue(v)) .build() } } @@ -236,13 +273,9 @@ private fun mapUnknownFields(message: KtMessage): UnknownFieldSet { field.varint.forEach { addVarint(it.value.toLong()) } field.fixed32.forEach { addFixed32(it.value.toInt()) } field.fixed64.forEach { addFixed64(it.value.toLong()) } - field.lengthDelimited.forEach { - addLengthDelimited( - UnsafeByteOperations.unsafeWrap(it.value.asReadOnlyBuffer()), - ) - } + field.lengthDelimited.forEach { addLengthDelimited(UnsafeByteOperations.unsafeWrap(it.value.asReadOnlyBuffer())) } } - .build(), + .build() ) } diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt index f280af7be..c3c2bdae8 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt @@ -16,24 +16,134 @@ package protokt.v1.google.protobuf import com.google.common.truth.Truth.assertThat +import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test +import protokt.v1.KtMessage +import protokt.v1.testing.MapWrappers +import protokt.v1.testing.OneofWrappers +import protokt.v1.testing.RepeatedWrappers +import protokt.v1.testing.Wrappers +import java.net.InetAddress +import java.net.InetSocketAddress +import java.time.Duration +import java.time.Instant +import java.time.LocalDate +import java.util.UUID class DynamicMessageTest { @Test - fun `dynamic message serialized size`() { - val message = getAllSet() + @Disabled + fun `dynamic message serialization`() { + val message = getAllTypesAllSet() - val dynamicMessage = message.toDynamicMessage(RuntimeContext.getContextReflectively()) + verifyMessage(message) + } - assertThat(dynamicMessage.serializedSize).isEqualTo(message.messageSize) + @Test + @Disabled + fun `dynamic message with wrapped fields`() { + val message = + Wrappers { + uuid = UUID.randomUUID() + /* + ipAddress = InetAddress.getByName("127.0.0.1") + socketAddress = InetSocketAddress.createUnresolved("127.0.0.1", 2319) + instant = Instant.now() + duration = Duration.ofSeconds(623, 2319) + localDate = LocalDate.now() + nullableUuid = UUID.randomUUID() + nullableLocalDate = LocalDate.now().minusDays(1) + optionalUuid = UUID.randomUUID() + optionalIpAddress = InetAddress.getByName("127.0.0.2") + optionalLocalDate = LocalDate.now().minusDays(2) + + */ + } + + verifyMessage(message) } @Test - fun `dynamic message serialization`() { - val message = getAllSet() + @Disabled + fun `dynamic message with oneof fields`() { + val message1 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.UuidOneof(UUID.randomUUID()) } + + verifyMessage(message1) + + val message2 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.IpAddressOneof(InetAddress.getByName("127.0.0.1")) } + + verifyMessage(message2) + + val message3 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.SocketAddressOneof(InetSocketAddress.createUnresolved("127.0.0.1", 2319)) } + + verifyMessage(message3) + + val message4 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.InstantOneof(Instant.now()) } + + verifyMessage(message4) + + val message5 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.DurationOneof(Duration.ofSeconds(623, 14853)) } + + verifyMessage(message5) + val message6 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.LocalDateOneof(LocalDate.now()) } + + verifyMessage(message6) + + val message7 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.NullableUuidOneof(UUID.randomUUID()) } + + verifyMessage(message7) + + val message8 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.NullableLocalDateOneof(LocalDate.now()) } + + verifyMessage(message8) + } + + @Test + @Disabled + fun `dynamic message with repeated fields`() { + val message = + RepeatedWrappers { + uuids = listOf(UUID.randomUUID(), UUID.randomUUID()) + uuidsWrapped = listOf(UUID.randomUUID(), UUID.randomUUID()) + } + + verifyMessage(message) + } + + @Test + @Disabled + fun `dynamic message with map fields`() { + val message = + MapWrappers { + mapStringUuid = + mapOf( + LocalDate.now() to UUID.randomUUID(), + LocalDate.now().minusDays(1) to UUID.randomUUID() + ) + + mapStringSocketAddress = + mapOf( + LocalDate.now() to InetSocketAddress.createUnresolved("127.0.0.1", 2319), + LocalDate.now().minusDays(1) to InetSocketAddress.createUnresolved("127.0.0.1", 2320) + ) + } + + verifyMessage(message) + } + + private fun verifyMessage(message: KtMessage) { val dynamicMessage = message.toDynamicMessage(RuntimeContext.getContextReflectively()) + assertThat(dynamicMessage.serializedSize).isEqualTo(message.messageSize) assertThat(dynamicMessage.toByteArray()).isEqualTo(message.serialize()) } } diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt index b6900d30e..dc47c6fb6 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt @@ -22,7 +22,7 @@ import protokt.v1.proto3_unittest.TestAllTypes import protokt.v1.protobuf_unittest_import.ImportMessage import protokt.v1.protobuf_unittest_import.PublicImportMessage -fun getAllSet() = +fun getAllTypesAllSet() = TestAllTypes { optionalInt32 = 101 optionalInt64 = 102 diff --git a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto new file mode 100644 index 000000000..63dc9647f --- /dev/null +++ b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2019 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto3"; + +package protokt.v1.testing; + +option java_package = "com.toasttab.protokt.v1.testing"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; +import "protokt/v1/inet_socket_address.proto"; +import "protokt/v1/protokt.proto"; + +message Wrappers { + bytes uuid = 2 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + bytes ip_address = 3 [ + (.protokt.v1.property).wrap = "java.net.InetAddress" + ]; + + .protokt.v1.InetSocketAddress socket_address = 5 [ + (.protokt.v1.property).wrap = "java.net.InetSocketAddress" + ]; + + google.protobuf.Timestamp instant = 6 [ + (.protokt.v1.property).wrap = "java.time.Instant" + ]; + + google.protobuf.Duration duration = 7 [ + (.protokt.v1.property).wrap = "java.time.Duration" + ]; + + string local_date = 8 [ + (.protokt.v1.property).wrap = "java.time.LocalDate" + ]; + + google.protobuf.BytesValue nullable_uuid = 9 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + google.protobuf.StringValue nullable_local_date = 10 [ + (.protokt.v1.property).wrap = "java.time.LocalDate" + ]; + + optional bytes optional_uuid = 12 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + optional bytes optional_ip_address = 13 [ + (.protokt.v1.property).wrap = "java.net.InetAddress" + ]; + + optional string optional_local_date = 14 [ + (.protokt.v1.property).wrap = "java.time.LocalDate" + ]; +} + +message OneofWrappers { + oneof wrapped_oneof { + option (.protokt.v1.oneof).non_null = true; + + bytes uuid_oneof = 2 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + bytes ip_address_oneof = 3 [ + (.protokt.v1.property).wrap = "java.net.InetAddress" + ]; + + .protokt.v1.InetSocketAddress socket_address_oneof = 5 [ + (.protokt.v1.property).wrap = "java.net.InetSocketAddress" + ]; + + google.protobuf.Timestamp instant_oneof = 6 [ + (.protokt.v1.property).wrap = "java.time.Instant" + ]; + + google.protobuf.Duration duration_oneof = 7 [ + (.protokt.v1.property).wrap = "java.time.Duration" + ]; + + string local_date_oneof = 8 [ + (.protokt.v1.property).wrap = "java.time.LocalDate" + ]; + + google.protobuf.BytesValue nullable_uuid_oneof = 9 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + google.protobuf.StringValue nullable_local_date_oneof = 10 [ + (.protokt.v1.property).wrap = "java.time.LocalDate" + ]; + } +} + +message RepeatedWrappers { + repeated bytes uuids = 1 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; + + repeated google.protobuf.BytesValue uuids_wrapped = 2 [ + (.protokt.v1.property).wrap = "java.util.UUID" + ]; +} + +message MapWrappers { + map map_string_uuid = 7 [ + (.protokt.v1.property).key_wrap = "java.time.LocalDate", + (.protokt.v1.property).value_wrap = "java.util.UUID" + ]; + + map map_string_socket_address = 8 [ + (.protokt.v1.property).key_wrap = "java.time.LocalDate", + (.protokt.v1.property).value_wrap = "java.net.InetSocketAddress" + ]; +} diff --git a/protokt-util/build.gradle.kts b/protokt-util/build.gradle.kts deleted file mode 100644 index 98f9db1fb..000000000 --- a/protokt-util/build.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2020 Toast, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -plugins { - id("protokt.jvm-conventions") -} - -// used by integration testing project -enablePublishing() - -includeBuildSrc("ProtoktExtension.kt") - -dependencies { - testImplementation(project(":extensions:protokt-extensions")) -} diff --git a/settings.gradle.kts b/settings.gradle.kts index bc1967b03..8a8bc1c6d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,7 +36,6 @@ include( "protokt-runtime-grpc", "protokt-runtime-grpc-lite", "protokt-gradle-plugin", - "protokt-util", "grpc-kotlin-shim", diff --git a/testing/options/build.gradle.kts b/testing/options/build.gradle.kts index bc7c1f1ea..995f74f99 100644 --- a/testing/options/build.gradle.kts +++ b/testing/options/build.gradle.kts @@ -41,3 +41,11 @@ dependencies { testRuntimeOnly(libs.protobuf.java) } + +sourceSets { + test { + java { + srcDir(rootProject.file("unpublished/src/lite-util")) + } + } +} diff --git a/protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt similarity index 91% rename from protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt rename to testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt index 9b26a142a..90f0c1941 100644 --- a/protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt +++ b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt @@ -13,10 +13,11 @@ * limitations under the License. */ -package protokt.v1.util +package protokt.v1.testing import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test +import protokt.v1.util.PROTOKT_EXTENSIONS_CLASS_NAME import protokt.v1.ProtoktProtos class ProtoktExtensionsTest { diff --git a/testing/plugin-options/lite/build.gradle.kts b/testing/plugin-options/lite/build.gradle.kts index 55070de8f..3091fd255 100644 --- a/testing/plugin-options/lite/build.gradle.kts +++ b/testing/plugin-options/lite/build.gradle.kts @@ -33,7 +33,14 @@ dependencies { protoktExtensions(project(":third-party:proto-google-common-protos-extensions-lite")) testImplementation(kotlin("reflect")) - testImplementation(project(":protokt-util")) testRuntimeOnly(libs.protobuf.lite) } + +sourceSets { + test { + java { + srcDir(rootProject.file("unpublished/src/lite-util")) + } + } +} diff --git a/third-party/proto-google-common-protos-lite/build.gradle.kts b/third-party/proto-google-common-protos-lite/build.gradle.kts index 9dfb70b93..76a5e9094 100644 --- a/third-party/proto-google-common-protos-lite/build.gradle.kts +++ b/third-party/proto-google-common-protos-lite/build.gradle.kts @@ -44,7 +44,7 @@ kotlin { val jvmTest by getting { dependencies { - implementation(project(":protokt-util")) + implementation(rootProject.fileTree("unpublished/src/lite-util")) } } diff --git a/protokt-util/src/main/kotlin/protokt/v1/util/ProtoktExtentions.kt b/unpublished/src/lite-util/protokt/v1/util/ProtoktExtentions.kt similarity index 100% rename from protokt-util/src/main/kotlin/protokt/v1/util/ProtoktExtentions.kt rename to unpublished/src/lite-util/protokt/v1/util/ProtoktExtentions.kt diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt similarity index 74% rename from protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt rename to unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt index 8ea599766..f9e72cdc4 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -13,14 +13,11 @@ * limitations under the License. */ -package protokt.v1.codegen.util +package protokt.v1.reflect import com.google.common.collect.HashBasedTable import com.google.common.collect.ImmutableTable import com.google.common.collect.Table -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.asClassName -import io.github.oshai.kotlinlogging.KotlinLogging import protokt.v1.Bytes import protokt.v1.Converter import protokt.v1.OptimizedSizeOfConverter @@ -31,11 +28,7 @@ import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.memberProperties class ClassLookup(classpath: List) { - private val logger = KotlinLogging.logger { } - private val classLoader by lazy { - logger.info { "Creating class loader with extra classpath: $classpath" } - val current = Thread.currentThread().contextClassLoader when { @@ -63,28 +56,32 @@ class ClassLookup(classpath: List) { .toList() } }.run { - val table = HashBasedTable.create>>() - forEach { table.getOrPut(it.wrapped.asClassName(), it.wrapper.asClassName()) { mutableListOf() }.add(it) } - ImmutableTable.builder>>().putAll(table).build() + val table = HashBasedTable.create>>() + forEach { table.getOrPut(it.wrapped.qualifiedName!!, it.wrapper.qualifiedName!!) { mutableListOf() }.add(it) } + ImmutableTable.builder>>().putAll(table).build() } } - private val classLookup = mutableMapOf>() + private val classLookup = mutableMapOf>() - fun properties(className: ClassName): Collection = + fun properties(canonicalClassName: String): Collection = try { - classLookup.getOrPut(className) { - classLoader.loadClass(className.canonicalName).kotlin + classLookup.getOrPut(canonicalClassName) { + classLoader.loadClass(canonicalClassName).kotlin }.memberProperties.map { it.name } } catch (t: Throwable) { - throw Exception("Class not found: ${className.canonicalName}") + throw Exception("Class not found: $canonicalClassName") } - fun converter(protoClassName: ClassName, kotlinClassName: ClassName): ConverterDetails { - val converters = convertersByProtoClassNameAndKotlinClassName.get(protoClassName, kotlinClassName) ?: emptyList() + fun converter(protoClassCanonicalName: String, kotlinClassCanonicalName: String): ConverterDetails { + val converters = + convertersByProtoClassNameAndKotlinClassName.get( + protoClassCanonicalName, + kotlinClassCanonicalName + ) ?: emptyList() require(converters.isNotEmpty()) { - "No converter found for wrapper type $kotlinClassName from type $protoClassName" + "No converter found for wrapper type $kotlinClassCanonicalName from type $protoClassCanonicalName" } val converter = @@ -107,8 +104,8 @@ class ClassLookup(classpath: List) { } return ConverterDetails( - converter::class.asClassName(), - kotlinClassName, + converter::class, + kotlinClassCanonicalName, converter is OptimizedSizeOfConverter<*, *>, !converter.acceptsDefaultValue ) @@ -142,8 +139,8 @@ private fun tryDeserializeDefaultValue(converter: Converter): Th } class ConverterDetails( - val converterClassName: ClassName, - val kotlinClassName: ClassName, + val converterClass: KClass<*>, + val kotlinCanonicalClassName: String, val optimizedSizeof: Boolean, val cannotDeserializeDefaultValue: Boolean ) From e28dd17cf57c30f79bfa556010341677327cb01a Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 20:44:16 -0500 Subject: [PATCH 06/38] lint --- .../src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt | 2 +- .../jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt | 4 ++-- .../test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index 27c331e9c..b4be54559 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -26,10 +26,10 @@ import protokt.v1.OptimizedSizeOfConverter import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.WellKnownTypes.wrapWithWellKnownInterception -import protokt.v1.reflect.ConverterDetails import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.GeneratorContext import protokt.v1.codegen.util.StandardField +import protokt.v1.reflect.ConverterDetails import kotlin.reflect.KFunction2 internal object Wrapper { diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index a42e28364..cab19297b 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -219,8 +219,8 @@ private fun isWrapped(field: FieldDescriptor): Boolean { } return propertyOptions.wrap.isNotEmpty() || - propertyOptions.keyWrap.isNotEmpty() || - propertyOptions.valueWrap.isNotEmpty() + propertyOptions.keyWrap.isNotEmpty() || + propertyOptions.valueWrap.isNotEmpty() } private fun convertMap( diff --git a/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt index 90f0c1941..2fbe045b8 100644 --- a/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt +++ b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt @@ -17,8 +17,8 @@ package protokt.v1.testing import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test -import protokt.v1.util.PROTOKT_EXTENSIONS_CLASS_NAME import protokt.v1.ProtoktProtos +import protokt.v1.util.PROTOKT_EXTENSIONS_CLASS_NAME class ProtoktExtensionsTest { @Test From 3659cb2944ae012b461351de2fca38f510125076 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 21:55:05 -0500 Subject: [PATCH 07/38] move over what is needed to infer protobuf type names --- .../v1/codegen/generate/BuilderGenerator.kt | 2 +- .../v1/codegen/generate/CodeGenerator.kt | 2 +- .../codegen/generate/DeserializerGenerator.kt | 20 ++--- .../codegen/generate/DeserializerSupport.kt | 6 +- .../v1/codegen/generate/EnumGenerator.kt | 2 +- .../generate/FileDescriptorResolver.kt | 2 +- .../v1/codegen/generate/FileGenerator.kt | 2 +- .../protokt/v1/codegen/generate/Implements.kt | 2 +- .../v1/codegen/generate/KotlinPoetUtil.kt | 2 +- .../v1/codegen/generate/MapEntryGenerator.kt | 18 ++-- .../generate/MessageDocumentationAnnotator.kt | 4 +- .../v1/codegen/generate/MessageGenerator.kt | 2 +- .../codegen/generate/MessageSizeGenerator.kt | 19 ++-- .../v1/codegen/generate/Nullability.kt | 4 +- .../v1/codegen/generate/OneofGenerator.kt | 2 +- .../v1/codegen/generate/PropertyAnnotator.kt | 7 +- .../PropertyDocumentationAnnotator.kt | 2 +- .../generate/SerializeAndSizeSupport.kt | 7 +- .../codegen/generate/SerializerGenerator.kt | 6 +- .../v1/codegen/generate/ServiceGenerator.kt | 2 +- .../v1/codegen/generate/WellKnownTypes.kt | 2 +- .../protokt/v1/codegen/generate/Wrapper.kt | 19 ++-- .../protokt/v1/codegen/util/ClassNames.kt | 2 +- .../protokt/v1/codegen/util/EnumParser.kt | 2 +- .../protokt/v1/codegen/util/FieldParser.kt | 47 ++-------- .../protokt/v1/codegen/util/FieldTypeExt.kt | 54 ++++++++++++ .../v1/codegen/util/FileContentParser.kt | 4 +- .../v1/codegen/util/GeneratedCodeCleanup.kt | 2 +- .../v1/codegen/util/GeneratorContext.kt | 2 +- .../util/GrpcKotlinGeneratorSupport.kt | 2 +- .../protokt/v1/codegen/util/MessageParser.kt | 2 +- .../v1/codegen/util/PackageResolution.kt | 14 +-- .../protokt/v1/codegen/util/PluginParams.kt | 2 +- .../protokt/v1/codegen/util/ServiceParser.kt | 6 +- .../kotlin/protokt/v1/codegen/util/Types.kt | 11 +-- .../protokt/v1/google/protobuf/KtMessages.kt | 88 ++++++++----------- .../v1/google/protobuf/DynamicMessageTest.kt | 17 +--- .../reflect/protokt/v1/reflect/ClassLookup.kt | 21 ++++- .../reflect/protokt/v1/reflect}/FieldType.kt | 62 ++++++------- .../protokt/v1/reflect/PackageNames.kt | 42 +++++++++ 40 files changed, 275 insertions(+), 239 deletions(-) create mode 100644 protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt rename {protokt-codegen/src/main/kotlin/protokt/v1/codegen/util => unpublished/src/reflect/protokt/v1/reflect}/FieldType.kt (68%) create mode 100644 unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt index 2b0785225..f493535be 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt @@ -27,8 +27,8 @@ import protokt.v1.KtBuilderDsl import protokt.v1.UnknownFieldSet import protokt.v1.codegen.generate.Deprecation.handleDeprecation import protokt.v1.codegen.util.BUILDER -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message +import protokt.v1.reflect.FieldType internal fun TypeSpec.Builder.handleBuilder(msg: Message, properties: List) = apply { BuilderGenerator(msg, properties).addBuilder(this) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt index 10a06a04f..94c363818 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt @@ -27,7 +27,7 @@ import protokt.v1.codegen.util.ProtoFileInfo import protokt.v1.codegen.util.Service import protokt.v1.codegen.util.TopLevelType -object CodeGenerator { +internal object CodeGenerator { data class Context( val enclosing: List, val info: ProtoFileInfo diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index 08c73b7db..4fc0478e3 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -34,21 +34,21 @@ import protokt.v1.codegen.generate.Wrapper.mapKeyConverter import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.generate.Wrapper.wrapField import protokt.v1.codegen.generate.Wrapper.wrapper -import protokt.v1.codegen.util.FieldType -import protokt.v1.codegen.util.FieldType.Enum -import protokt.v1.codegen.util.FieldType.SFixed32 -import protokt.v1.codegen.util.FieldType.SFixed64 -import protokt.v1.codegen.util.FieldType.SInt32 -import protokt.v1.codegen.util.FieldType.SInt64 -import protokt.v1.codegen.util.FieldType.UInt32 -import protokt.v1.codegen.util.FieldType.UInt64 import protokt.v1.codegen.util.KotlinPlugin import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField import protokt.v1.codegen.util.Tag +import protokt.v1.reflect.FieldType +import protokt.v1.reflect.FieldType.Enum +import protokt.v1.reflect.FieldType.SFixed32 +import protokt.v1.reflect.FieldType.SFixed64 +import protokt.v1.reflect.FieldType.SInt32 +import protokt.v1.reflect.FieldType.SInt64 +import protokt.v1.reflect.FieldType.UInt32 +import protokt.v1.reflect.FieldType.UInt64 -fun generateDeserializer(msg: Message, ctx: Context, properties: List) = +internal fun generateDeserializer(msg: Message, ctx: Context, properties: List) = DeserializerGenerator(msg, ctx, properties).generate() private class DeserializerGenerator( @@ -215,7 +215,7 @@ private class DeserializerGenerator( CodeBlock.of("%T(%L)", f.qualify(ff), deserialize(ff, ctx)) } -fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false): CodeBlock { +internal fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false): CodeBlock { val read = CodeBlock.of("deserializer.%L", interceptRead(f, f.readFn())) val wrappedRead = wrapper(f, ctx)?.let { wrapField(it, read) } ?: read diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt index 4ed4651aa..e7fc42312 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt @@ -18,9 +18,9 @@ package protokt.v1.codegen.generate import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.buildCodeBlock import com.squareup.kotlinpoet.withIndent -import protokt.v1.codegen.util.FieldType +import protokt.v1.reflect.FieldType -fun deserializeVarInitialState(p: PropertyInfo) = +internal fun deserializeVarInitialState(p: PropertyInfo) = if ( (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) && !p.mapEntry @@ -30,7 +30,7 @@ fun deserializeVarInitialState(p: PropertyInfo) = p.defaultValue } -fun wrapDeserializedValueForConstructor(p: PropertyInfo) = +internal fun wrapDeserializedValueForConstructor(p: PropertyInfo) = if (p.nonNullOption) { buildCodeBlock { beginControlFlow("requireNotNull(%N)", p.name) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/EnumGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/EnumGenerator.kt index 0ac00f599..dcc7cefdf 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/EnumGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/EnumGenerator.kt @@ -29,7 +29,7 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Deprecation.handleDeprecation import protokt.v1.codegen.util.Enum -fun generateEnum(e: Enum, ctx: Context) = +internal fun generateEnum(e: Enum, ctx: Context) = if (ctx.info.context.generateTypes) { EnumGenerator(e, ctx).generate() } else { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileDescriptorResolver.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileDescriptorResolver.kt index 33030738a..1dcf5424c 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileDescriptorResolver.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileDescriptorResolver.kt @@ -38,7 +38,7 @@ class FileDescriptorInfo( val properties: List ) -class FileDescriptorResolver +internal class FileDescriptorResolver private constructor( private val contents: ProtoFileContents ) { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileGenerator.kt index ffa744b4d..a63a690ea 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/FileGenerator.kt @@ -19,7 +19,7 @@ import com.squareup.kotlinpoet.FileSpec import protokt.v1.codegen.generate.Deprecation.addDeprecationSuppression import protokt.v1.codegen.util.ProtoFileContents -fun generateFile(contents: ProtoFileContents) = +internal fun generateFile(contents: ProtoFileContents) = FileGenerator(contents).generate() private class FileGenerator( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt index 8ed309e60..421d50dd4 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt @@ -21,7 +21,7 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.StandardField -object Implements { +internal object Implements { fun StandardField.overrides( ctx: Context, msg: Message diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt index f8419e90f..997bd2cfb 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt @@ -85,7 +85,7 @@ fun CodeBlock.Builder.endControlFlowWithoutNewline() { add("}") } -fun inferClassName(className: String, ctx: Context) = +internal fun inferClassName(className: String, ctx: Context) = inferClassName(className, ctx.info.kotlinPackage) fun inferClassName(className: String, pkg: String): ClassName { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index e8a2414cd..4db14143b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -30,13 +30,15 @@ import protokt.v1.KtMessageDeserializer import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.util.DESERIALIZER -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.MapEntry import protokt.v1.codegen.util.Message +import protokt.v1.codegen.util.SizeFn import protokt.v1.codegen.util.StandardField +import protokt.v1.codegen.util.sizeFn +import protokt.v1.reflect.FieldType import kotlin.reflect.KProperty0 -fun generateMapEntry(msg: Message, ctx: Context) = +internal fun generateMapEntry(msg: Message, ctx: Context) = MapEntryGenerator(msg, ctx).generate() private class MapEntryGenerator( @@ -114,10 +116,10 @@ private class MapEntryGenerator( .addFunction( buildFunSpec("entrySize") { returns(Int::class) - if (key.type.sizeFn is FieldType.Method) { + if (key.type.sizeFn is SizeFn.Method) { addParameter("key", key.className) } - if (value.type.sizeFn is FieldType.Method) { + if (value.type.sizeFn is SizeFn.Method) { addParameter("value", value.className) } addStatement("return %L + %L", sizeOf(key, ctx), sizeOf(value, ctx)) @@ -178,15 +180,15 @@ private class MapEntryGenerator( } } -fun sizeOfCall(mapEntry: MapEntry, keyStr: CodeBlock, valueStr: CodeBlock) = - if (mapEntry.key.type.sizeFn is FieldType.Method) { - if (mapEntry.value.type.sizeFn is FieldType.Method) { +internal fun sizeOfCall(mapEntry: MapEntry, keyStr: CodeBlock, valueStr: CodeBlock) = + if (mapEntry.key.type.sizeFn is SizeFn.Method) { + if (mapEntry.value.type.sizeFn is SizeFn.Method) { CodeBlock.of("entrySize(%L,·%L)", keyStr, valueStr) } else { CodeBlock.of("entrySize(%L)", keyStr) } } else { - if (mapEntry.value.type.sizeFn is FieldType.Method) { + if (mapEntry.value.type.sizeFn is SizeFn.Method) { CodeBlock.of("entrySize(%L)", valueStr) } else { CodeBlock.of("entrySize()") diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageDocumentationAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageDocumentationAnnotator.kt index a0038773e..7cad2342a 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageDocumentationAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageDocumentationAnnotator.kt @@ -20,10 +20,10 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorProto.MESSAGE_TYPE_FIE import com.google.protobuf.DescriptorProtos.SourceCodeInfo.Location import protokt.v1.codegen.generate.CodeGenerator.Context -fun annotateMessageDocumentation(ctx: Context) = +internal fun annotateMessageDocumentation(ctx: Context) = baseLocation(ctx)?.cleanDocumentation() -fun baseLocation(ctx: Context, extraPath: List = emptyList()) = +internal fun baseLocation(ctx: Context, extraPath: List = emptyList()) = ctx.info.sourceCodeInfo.locationList.firstOrNull { it.pathList == basePath(ctx) + extraPath } private fun basePath(ctx: Context): List { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt index a38fdf9c7..58ebd5021 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt @@ -34,7 +34,7 @@ import protokt.v1.codegen.generate.Deprecation.handleDeprecation import protokt.v1.codegen.generate.Implements.handleSuperInterface import protokt.v1.codegen.util.Message -fun generateMessage(msg: Message, ctx: Context) = +internal fun generateMessage(msg: Message, ctx: Context) = if (ctx.info.context.generateTypes) { MessageGenerator(msg, ctx).generate() } else { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt index 6cad639d6..d490062c1 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt @@ -27,12 +27,13 @@ import protokt.v1.codegen.generate.Wrapper.interceptSizeof import protokt.v1.codegen.generate.Wrapper.interceptValueAccess import protokt.v1.codegen.generate.Wrapper.mapKeyConverter import protokt.v1.codegen.generate.Wrapper.mapValueConverter -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof +import protokt.v1.codegen.util.SizeFn import protokt.v1.codegen.util.StandardField +import protokt.v1.codegen.util.sizeFn -fun generateMessageSize(msg: Message, properties: List, ctx: Context) = +internal fun generateMessageSize(msg: Message, properties: List, ctx: Context) = MessageSizeGenerator(msg, properties, ctx).generate() private class MessageSizeGenerator( @@ -100,7 +101,7 @@ private class MessageSizeGenerator( } } -fun sizeOf( +internal fun sizeOf( f: StandardField, ctx: Context, oneOfFieldAccess: CodeBlock? = null @@ -183,7 +184,7 @@ private fun sizeOfMap( } private fun StandardField.loopVar(name: String) = - if (type.sizeFn is FieldType.Method) { + if (type.sizeFn is SizeFn.Method) { name } else { "_" @@ -191,18 +192,18 @@ private fun StandardField.loopVar(name: String) = private fun StandardField.sizeOf(value: CodeBlock): CodeBlock = when (val fn = type.sizeFn) { - is FieldType.Const -> CodeBlock.of(fn.size.toString()) - is FieldType.Method -> CodeBlock.of("%M(%L)", fn.method, value) + is SizeFn.Const -> CodeBlock.of(fn.size.toString()) + is SizeFn.Method -> CodeBlock.of("%M(%L)", fn.method, value) } -fun StandardField.elementsSize( +internal fun StandardField.elementsSize( fieldAccess: CodeBlock = CodeBlock.of("it"), parenthesize: Boolean = true ) = when (val sizeFn = type.sizeFn) { - is FieldType.Const -> + is SizeFn.Const -> CodeBlock.of("(%N.size * %L)", fieldName, sizeFn.size) .let { if (parenthesize) CodeBlock.of("(%L)", it) else it } - is FieldType.Method -> + is SizeFn.Method -> CodeBlock.of("%N.sumOf·{·%L·}", fieldName, sizeOf(fieldAccess)) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Nullability.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Nullability.kt index 728e97f2f..48110e48c 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Nullability.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Nullability.kt @@ -18,11 +18,11 @@ package protokt.v1.codegen.generate import com.squareup.kotlinpoet.TypeName import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.util.Field -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField +import protokt.v1.reflect.FieldType -object Nullability { +internal object Nullability { val Field.hasNonNullOption get() = when (this) { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt index cd8ce5af4..aba5fd790 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt @@ -31,7 +31,7 @@ import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField -fun annotateOneofs(msg: Message, ctx: Context) = +internal fun annotateOneofs(msg: Message, ctx: Context) = OneofGenerator(msg, ctx).generate() private class OneofGenerator( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt index dec9f931b..a07196d9b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt @@ -35,12 +35,13 @@ import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNullability import protokt.v1.codegen.util.ErrorContext.withFieldName import protokt.v1.codegen.util.Field -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField +import protokt.v1.codegen.util.defaultValue +import protokt.v1.reflect.FieldType -fun annotateProperties(msg: Message, ctx: Context) = +internal fun annotateProperties(msg: Message, ctx: Context) = PropertyAnnotator(msg, ctx).annotate() private class PropertyAnnotator( @@ -149,7 +150,7 @@ private class PropertyAnnotator( } } -class PropertyInfo( +internal class PropertyInfo( val name: String, val number: Int? = null, val propertyType: TypeName, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyDocumentationAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyDocumentationAnnotator.kt index cccd167b4..68f35d9f8 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyDocumentationAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyDocumentationAnnotator.kt @@ -22,7 +22,7 @@ import protokt.v1.codegen.util.Field import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField -fun annotatePropertyDocumentation(field: Field, ctx: Context) = +internal fun annotatePropertyDocumentation(field: Field, ctx: Context) = PropertyDocumentationAnnotator(field, ctx).annotate() private class PropertyDocumentationAnnotator( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializeAndSizeSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializeAndSizeSupport.kt index d57c7549c..9f11295f2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializeAndSizeSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializeAndSizeSupport.kt @@ -23,12 +23,13 @@ import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.Nullability.nullable import protokt.v1.codegen.generate.Wrapper.interceptValueAccess import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNullability -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField +import protokt.v1.codegen.util.defaultValue +import protokt.v1.reflect.FieldType -fun Message.mapFields( +internal fun Message.mapFields( ctx: Context, properties: List, skipConditionalForUnpackedRepeatedFields: Boolean, @@ -122,5 +123,5 @@ private fun oneofInstanceConditionals(f: Oneof, stmt: (StandardField) -> CodeBlo } } -fun Oneof.qualify(f: StandardField) = +internal fun Oneof.qualify(f: StandardField) = className.nestedClass(fieldTypeNames.getValue(f.fieldName)) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt index c97a5d48f..e203e5bff 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt @@ -25,12 +25,12 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptValueAccess import protokt.v1.codegen.generate.Wrapper.mapKeyConverter import protokt.v1.codegen.generate.Wrapper.mapValueConverter -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField +import protokt.v1.reflect.FieldType -fun generateSerializer(msg: Message, properties: List, ctx: Context) = +internal fun generateSerializer(msg: Message, properties: List, ctx: Context) = SerializerGenerator(msg, properties, ctx).generate() private class SerializerGenerator( @@ -57,7 +57,7 @@ private class SerializerGenerator( } } -fun serialize( +internal fun serialize( f: StandardField, ctx: Context, p: PropertySpec, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/ServiceGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/ServiceGenerator.kt index a77da3924..9b7e83c0b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/ServiceGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/ServiceGenerator.kt @@ -57,7 +57,7 @@ import kotlin.reflect.KClass import kotlin.reflect.KFunction1 import kotlin.reflect.KFunction3 -fun generateService(s: Service, ctx: Context, kotlinPlugin: KotlinPlugin?) = +internal fun generateService(s: Service, ctx: Context, kotlinPlugin: KotlinPlugin?) = ServiceGenerator(s, ctx, kotlinPlugin).generate() private class ServiceGenerator( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt index d2b4625e7..11e8a922d 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt @@ -19,7 +19,7 @@ import protokt.v1.Bytes import protokt.v1.codegen.util.DOT_GOOGLE_PROTOBUF import protokt.v1.codegen.util.StandardField -object WellKnownTypes { +internal object WellKnownTypes { val StandardField.wrapWithWellKnownInterception get() = options.protokt.wrap.takeIf { it.isNotEmpty() } ?: if (protoTypeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index b4be54559..2b6892f1a 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -26,10 +26,11 @@ import protokt.v1.OptimizedSizeOfConverter import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.WellKnownTypes.wrapWithWellKnownInterception -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.GeneratorContext import protokt.v1.codegen.util.StandardField +import protokt.v1.reflect.ClassLookup import protokt.v1.reflect.ConverterDetails +import protokt.v1.reflect.FieldType import kotlin.reflect.KFunction2 internal object Wrapper { @@ -50,12 +51,12 @@ internal object Wrapper { wrapOption?.let { wrap -> ifWrapped( converter( - protoTypeName.takeIf { it.isNotEmpty() } - ?.let { className } - // Protobuf primitives have no typeName - ?: requireNotNull(type.kotlinRepresentation) { - "no kotlin representation for type of $fieldName: $type" - }.asClassName(), + ClassLookup.evaluateProtobufTypeCanonicalName( + protoTypeName, + className.canonicalName, + type, + fieldName + ).let(ClassName::bestGuess), inferClassName(wrap, ctx.kotlinPackage), ctx ) @@ -112,7 +113,7 @@ internal object Wrapper { converterDetails: ConverterDetails, access: CodeBlock, ) = - CodeBlock.of("%T.%L(%L)", converterDetails.converterClass.asClassName(), method.name, access) + CodeBlock.of("%T.%L(%L)", converterDetails.converter::class.asClassName(), method.name, access) fun wrapper(f: StandardField, ctx: Context) = f.withWrapper(ctx.info.context, ::converterClassName) @@ -171,7 +172,7 @@ internal object Wrapper { ClassName.bestGuess(converterDetails.kotlinCanonicalClassName) private fun converterClassName(converterDetails: ConverterDetails) = - converterDetails.converterClass.asClassName() + converterDetails.converter::class.asClassName() private fun StandardField.withValueWrap( ctx: Context, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt index 30be6089f..77d405a30 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt @@ -20,5 +20,5 @@ import com.squareup.kotlinpoet.ClassName const val DESERIALIZER = "Deserializer" const val BUILDER = "Builder" -fun GeneratorContext.className(simpleNames: List) = +internal fun GeneratorContext.className(simpleNames: List) = ClassName(kotlinPackage, simpleNames) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/EnumParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/EnumParser.kt index b1d8b04dd..900d29259 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/EnumParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/EnumParser.kt @@ -19,7 +19,7 @@ import com.google.common.base.CaseFormat import com.google.protobuf.DescriptorProtos.EnumDescriptorProto import com.toasttab.protokt.v1.ProtoktProtos -class EnumParser( +internal class EnumParser( private val ctx: GeneratorContext, private val idx: Int, private val desc: EnumDescriptorProto, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt index f1017995d..4253c297f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt @@ -26,12 +26,13 @@ import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type import com.google.protobuf.DescriptorProtos.FileDescriptorProto import com.google.protobuf.DescriptorProtos.OneofDescriptorProto import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.asTypeName import com.toasttab.protokt.v1.ProtoktProtos import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNonNullOptionForNonNullity import protokt.v1.codegen.util.ErrorContext.withFieldName +import protokt.v1.reflect.FieldType +import protokt.v1.reflect.typeName -class FieldParser( +internal class FieldParser( private val ctx: GeneratorContext, private val desc: DescriptorProto, private val enclosingMessages: List @@ -102,7 +103,7 @@ class FieldParser( fdp: FieldDescriptorProto, withinOneof: Boolean = false ): StandardField { - val fieldType = toFieldType(fdp.type) + val fieldType = FieldType.from(fdp.type) val protoktOptions = fdp.options.getExtension(ProtoktProtos.property) val repeated = fdp.label == LABEL_REPEATED val mapEntry = mapEntry(fdp) @@ -126,7 +127,7 @@ class FieldParser( fieldName = LOWER_UNDERSCORE.to(LOWER_CAMEL, fdp.name), options = FieldOptions(fdp.options, protoktOptions), protoTypeName = fdp.typeName, - className = typeName(fdp.typeName, fieldType), + className = ClassName.bestGuess(typeName(fdp.typeName, fieldType)), index = idx ) @@ -180,22 +181,6 @@ class FieldParser( } } - private fun typeName(protoTypeName: String, fieldType: FieldType): ClassName { - val fullyProtoQualified = protoTypeName.startsWith(".") - - return if (fullyProtoQualified) { - requalifyProtoType(protoTypeName) - } else { - protoTypeName.let { - if (it.isEmpty()) { - fieldType.protoktFieldType.asTypeName() - } else { - ClassName.bestGuess(it) - } - } - } - } - private fun optional(fdp: FieldDescriptorProto) = (fdp.label == LABEL_OPTIONAL && ctx.proto2) || fdp.proto3Optional @@ -258,25 +243,3 @@ class FieldParser( } } } - -private fun toFieldType(type: Type) = - when (type) { - Type.TYPE_BOOL -> FieldType.Bool - Type.TYPE_BYTES -> FieldType.Bytes - Type.TYPE_DOUBLE -> FieldType.Double - Type.TYPE_ENUM -> FieldType.Enum - Type.TYPE_FIXED32 -> FieldType.Fixed32 - Type.TYPE_FIXED64 -> FieldType.Fixed64 - Type.TYPE_FLOAT -> FieldType.Float - Type.TYPE_INT32 -> FieldType.Int32 - Type.TYPE_INT64 -> FieldType.Int64 - Type.TYPE_MESSAGE -> FieldType.Message - Type.TYPE_SFIXED32 -> FieldType.SFixed32 - Type.TYPE_SFIXED64 -> FieldType.SFixed64 - Type.TYPE_SINT32 -> FieldType.SInt32 - Type.TYPE_SINT64 -> FieldType.SInt64 - Type.TYPE_STRING -> FieldType.String - Type.TYPE_UINT32 -> FieldType.UInt32 - Type.TYPE_UINT64 -> FieldType.UInt64 - else -> error("Unknown type: $type") - } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt new file mode 100644 index 000000000..64ae6c9c2 --- /dev/null +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.codegen.util + +import com.squareup.kotlinpoet.CodeBlock +import com.squareup.kotlinpoet.MemberName +import com.squareup.kotlinpoet.MemberName.Companion.member +import com.squareup.kotlinpoet.asTypeName +import protokt.v1.SizeCodecs +import protokt.v1.codegen.generate.sizeOf +import protokt.v1.reflect.FieldType + +sealed interface SizeFn { + class Const(val size: Int) : SizeFn + class Method(val method: MemberName) : SizeFn +} + +internal val FieldType.sizeFn + get() = when (this) { + FieldType.Bool -> SizeFn.Const(1) + FieldType.Double, FieldType.Fixed64, FieldType.SFixed64 -> SizeFn.Const(8) + FieldType.Float, FieldType.Fixed32, FieldType.SFixed32 -> SizeFn.Const(4) + FieldType.SInt32 -> SizeFn.Method(SizeCodecs::class.asTypeName().member(SizeCodecs::sizeOfSInt32.name)) + FieldType.SInt64 -> SizeFn.Method(SizeCodecs::class.asTypeName().member(SizeCodecs::sizeOfSInt64.name)) + else -> SizeFn.Method(sizeOf) + } + +internal val FieldType.defaultValue: CodeBlock + get() = when (this) { + FieldType.Message -> CodeBlock.of("null") + FieldType.Enum -> error("enums do not have defaults; this is bug in the code generator") + FieldType.Bool -> CodeBlock.of("false") + FieldType.Fixed32, FieldType.UInt32 -> CodeBlock.of("0u") + FieldType.Int32, FieldType.SFixed32, FieldType.SInt32 -> CodeBlock.of("0") + FieldType.Fixed64, FieldType.UInt64 -> CodeBlock.of("0uL") + FieldType.Int64, FieldType.SFixed64, FieldType.SInt64 -> CodeBlock.of("0L") + FieldType.Float -> CodeBlock.of("0.0F") + FieldType.Double -> CodeBlock.of("0.0") + FieldType.Bytes -> CodeBlock.of("%T.empty()", protokt.v1.Bytes::class) + FieldType.String -> CodeBlock.of("\"\"") + } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt index 0fadb6cce..4d80c4693 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt @@ -22,13 +22,13 @@ import protokt.v1.codegen.util.ErrorContext.withEnumName import protokt.v1.codegen.util.ErrorContext.withMessageName import protokt.v1.codegen.util.ErrorContext.withServiceName -fun parseFileContents(ctx: GeneratorContext) = +internal fun parseFileContents(ctx: GeneratorContext) = ProtoFileContents( ProtoFileInfo(ctx), FileContentParser(ctx).parseContents() ) -class FileContentParser( +internal class FileContentParser( private val ctx: GeneratorContext, private val enums: List, private val messages: List, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratedCodeCleanup.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratedCodeCleanup.kt index 282e4a736..67b4dc359 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratedCodeCleanup.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratedCodeCleanup.kt @@ -28,7 +28,7 @@ import protokt.v1.codegen.generate.INDENT private val logger = KotlinLogging.logger { } -fun tidy(code: String, context: GeneratorContext) = +internal fun tidy(code: String, context: GeneratorContext) = if (context.formatOutput) { try { format(code) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratorContext.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratorContext.kt index 6fb228d58..8d82186fe 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratorContext.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GeneratorContext.kt @@ -19,7 +19,7 @@ import com.google.protobuf.DescriptorProtos.FileDescriptorProto import com.toasttab.protokt.v1.ProtoktProtos import protokt.v1.gradle.PROTOKT_VERSION -class GeneratorContext( +internal class GeneratorContext( val fdp: FileDescriptorProto, params: PluginParams, allFiles: List diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt index d2b7cd15a..453fcc91c 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt @@ -21,7 +21,7 @@ import io.grpc.kotlin.generator.GeneratorRunner import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream -fun generateGrpcKotlinStubs( +internal fun generateGrpcKotlinStubs( params: PluginParams, request: CodeGeneratorRequest ): List = diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt index bb08a1844..946cbe064 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt @@ -18,7 +18,7 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.DescriptorProto import com.toasttab.protokt.v1.ProtoktProtos -class MessageParser( +internal class MessageParser( private val ctx: GeneratorContext, private val idx: Int, private val desc: DescriptorProto, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt index 0cbc1c724..c36488634 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt @@ -16,10 +16,8 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.FileDescriptorProto -import com.squareup.kotlinpoet.ClassName -import protokt.v1.Bytes +import protokt.v1.reflect.PROTOKT_V1 -val PROTOKT_V1 = Bytes::class.java.`package`.name const val DOT_GOOGLE_PROTOBUF = ".google.protobuf" val PROTOKT_V1_GOOGLE_PROTO = PROTOKT_V1 + DOT_GOOGLE_PROTOBUF @@ -32,13 +30,3 @@ fun resolvePackage(fdp: FileDescriptorProto) = } else { "$PROTOKT_V1." + fdp.`package` } - -fun requalifyProtoType(typeName: String): ClassName = - // type name might have a `.` prefix - ClassName.bestGuess( - if (typeName.startsWith(".$PROTOKT_V1")) { - typeName.removePrefix(".") - } else { - "$PROTOKT_V1." + typeName.removePrefix(".") - } - ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt index c0b196e74..92e20728e 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PluginParams.kt @@ -30,7 +30,7 @@ import protokt.v1.reflect.ClassLookup import java.net.URLDecoder import kotlin.reflect.full.declaredMemberProperties -class PluginParams( +internal class PluginParams( params: Map ) { val classLookup = diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt index 75d3e9789..88b7ff5ab 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt @@ -17,7 +17,9 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.MethodDescriptorProto import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto +import com.squareup.kotlinpoet.ClassName import com.toasttab.protokt.v1.ProtoktProtos +import protokt.v1.reflect.requalifyProtoType class ServiceParser( private val idx: Int, @@ -38,8 +40,8 @@ class ServiceParser( private fun toMethod(desc: MethodDescriptorProto) = Method( name = desc.name, - inputType = requalifyProtoType(desc.inputType), - outputType = requalifyProtoType(desc.outputType), + inputType = ClassName.bestGuess(requalifyProtoType(desc.inputType)), + outputType = ClassName.bestGuess(requalifyProtoType(desc.outputType)), clientStreaming = desc.clientStreaming, serverStreaming = desc.serverStreaming, deprecated = desc.options.deprecated, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt index 1227248f2..5da7a9b0b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt @@ -19,6 +19,7 @@ import com.google.protobuf.DescriptorProtos import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.TypeSpec import com.toasttab.protokt.v1.ProtoktProtos +import protokt.v1.reflect.FieldType sealed class TopLevelType @@ -96,7 +97,7 @@ sealed class Field { abstract val fieldName: String } -class StandardField( +internal class StandardField( val number: Int, val tag: Tag, @@ -120,7 +121,7 @@ class StandardField( get() = mapEntry != null } -class Oneof( +internal class Oneof( val name: String, val className: ClassName, override val fieldName: String, @@ -130,7 +131,7 @@ class Oneof( val index: Int ) : Field() -class MapEntry( +internal class MapEntry( val key: StandardField, val value: StandardField ) @@ -145,7 +146,7 @@ class OneofOptions( val protokt: ProtoktProtos.OneofOptions ) -class ProtoFileInfo( +internal class ProtoFileInfo( val context: GeneratorContext ) { val name = context.fdp.name @@ -160,7 +161,7 @@ class FileOptions( val protokt: ProtoktProtos.FileOptions ) -class ProtoFileContents( +internal class ProtoFileContents( val info: ProtoFileInfo, val types: List ) diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index cab19297b..1f2fb25e1 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -35,8 +35,9 @@ import protokt.v1.KtEnum import protokt.v1.KtGeneratedFileDescriptor import protokt.v1.KtGeneratedMessage import protokt.v1.KtMessage -import protokt.v1.google.protobuf.RuntimeContext.Companion.DEFAULT_CONVERTERS import protokt.v1.reflect.ClassLookup +import protokt.v1.reflect.FieldType +import protokt.v1.reflect.typeName import kotlin.Any import kotlin.reflect.KClass import kotlin.reflect.full.declaredMemberProperties @@ -45,17 +46,11 @@ import kotlin.reflect.full.findAnnotation fun KtMessage.toDynamicMessage(context: RuntimeContext): DynamicMessage = context.convertValue(this) as DynamicMessage -class RuntimeContext( +class RuntimeContext internal constructor( descriptors: Iterable, - converters: Iterable>, + private val classLookup: ClassLookup ) { internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } - private val convertersByWrappedType = converters.associateBy { it.wrapper to type(it.wrapped) } - - private fun type(klass: KClass<*>): KClass<*> = - when { - else -> error("unimplemented: $klass") - } fun convertValue(value: Any?) = when (value) { @@ -70,37 +65,28 @@ class RuntimeContext( } internal fun unwrap(value: Any, field: FieldDescriptor): Any { - val defaultConverter = - if (field.type == FieldDescriptor.Type.MESSAGE) { - DEFAULT_CONVERTERS[field.messageType.fullName] - } else { - null - } - - // todo! - val converter = defaultConverter ?: convertersByWrappedType.getValue(value::class to Any::class) + val proto = field.toProto() + val type = FieldType.from(proto.type) + val converterDetails = + classLookup.converter( + ClassLookup.evaluateProtobufTypeCanonicalName( + proto.typeName, + typeName(proto.typeName, type), + type, + field.name + ), + // todo: ths is not right; have to infer kotlin name like we do in codegen + value::class.qualifiedName!! + ) @Suppress("UNCHECKED_CAST") - return (converter as Converter).unwrap(value) + val converter = converterDetails.converter as Converter + return converter.unwrap(value) } companion object { - internal val DEFAULT_CONVERTERS: Map> = - mapOf( - "google.protobuf.DoubleValue" to DoubleValueConverter, - "google.protobuf.FloatValue" to FloatValueConverter, - "google.protobuf.Int64Value" to Int64ValueConverter, - "google.protobuf.UInt64Value" to UInt64ValueConverter, - "google.protobuf.Int32Value" to Int32ValueConverter, - "google.protobuf.UInt32Value" to UInt32ValueConverter, - "google.protobuf.BoolValue" to BoolValueConverter, - "google.protobuf.StringValue" to StringValueConverter, - "google.protobuf.BytesValue" to BytesValueConverter, - ) - private val reflectiveContext by lazy { - ClassLookup(emptyList()) - RuntimeContext(getDescriptors(), getConverters()) + RuntimeContext(getDescriptors(), ClassLookup(emptyList())) } fun getContextReflectively() = @@ -130,23 +116,6 @@ private fun getDescriptors() = .flatMap(::collectDescriptors) .asIterable() -private fun getConverters(): Iterable> { - val classLoader = Thread.currentThread().contextClassLoader - - return classLoader.getResources("META-INF/services/${Converter::class.qualifiedName}") - .asSequence() - .flatMap { url -> - url.openStream() - .bufferedReader() - .useLines { lines -> - lines.map { it.substringBefore("#").trim() } - .filter { it.isNotEmpty() } - .map { classLoader.loadClass(it).kotlin.objectInstance as Converter<*, *> } - .toList() - } - }.asIterable() -} - private fun collectDescriptors(descriptor: Descriptors.Descriptor): Iterable = listOf(descriptor) + descriptor.nestedTypes.flatMap(::collectDescriptors) @@ -179,9 +148,11 @@ private fun toDynamicMessage( field.enumType.findValueByNumberCreatingIfUnknown(((value as KtEnum).value)) } + // todo: unwrap keys and values if wrapped field.isMapField -> convertMap(value, field, context) + // todo: unwrap elements if wrapped field.isRepeated -> (value as List<*>).map(context::convertValue) @@ -198,8 +169,21 @@ private fun toDynamicMessage( .build() } +private val WRAPPER_TYPE_NAMES = + setOf( + "google.protobuf.DoubleValue", + "google.protobuf.FloatValue", + "google.protobuf.Int64Value", + "google.protobuf.UInt64Value", + "google.protobuf.Int32Value", + "google.protobuf.UInt32Value", + "google.protobuf.BoolValue", + "google.protobuf.StringValue", + "google.protobuf.BytesValue" + ) + private fun isWrapped(field: FieldDescriptor): Boolean { - if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in DEFAULT_CONVERTERS) { + if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in WRAPPER_TYPE_NAMES) { return true } diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt index c3c2bdae8..197c2d9fe 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt @@ -16,7 +16,6 @@ package protokt.v1.google.protobuf import com.google.common.truth.Truth.assertThat -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import protokt.v1.KtMessage import protokt.v1.testing.MapWrappers @@ -32,39 +31,33 @@ import java.util.UUID class DynamicMessageTest { @Test - @Disabled fun `dynamic message serialization`() { val message = getAllTypesAllSet() - verifyMessage(message) + ; verifyMessage(message) } @Test - @Disabled fun `dynamic message with wrapped fields`() { val message = Wrappers { uuid = UUID.randomUUID() - /* - ipAddress = InetAddress.getByName("127.0.0.1") - socketAddress = InetSocketAddress.createUnresolved("127.0.0.1", 2319) + // ipAddress = InetAddress.getByName("127.0.0.1") + socketAddress = InetSocketAddress("127.0.0.1", 2319) instant = Instant.now() duration = Duration.ofSeconds(623, 2319) localDate = LocalDate.now() nullableUuid = UUID.randomUUID() nullableLocalDate = LocalDate.now().minusDays(1) optionalUuid = UUID.randomUUID() - optionalIpAddress = InetAddress.getByName("127.0.0.2") + // optionalIpAddress = InetAddress.getByName("127.0.0.2") optionalLocalDate = LocalDate.now().minusDays(2) - - */ } verifyMessage(message) } @Test - @Disabled fun `dynamic message with oneof fields`() { val message1 = OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.UuidOneof(UUID.randomUUID()) } @@ -108,7 +101,6 @@ class DynamicMessageTest { } @Test - @Disabled fun `dynamic message with repeated fields`() { val message = RepeatedWrappers { @@ -120,7 +112,6 @@ class DynamicMessageTest { } @Test - @Disabled fun `dynamic message with map fields`() { val message = MapWrappers { diff --git a/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt index f9e72cdc4..ac23ec443 100644 --- a/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -27,7 +27,7 @@ import kotlin.reflect.KClass import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.memberProperties -class ClassLookup(classpath: List) { +internal class ClassLookup(classpath: List) { private val classLoader by lazy { val current = Thread.currentThread().contextClassLoader @@ -104,12 +104,27 @@ class ClassLookup(classpath: List) { } return ConverterDetails( - converter::class, + converter, kotlinClassCanonicalName, converter is OptimizedSizeOfConverter<*, *>, !converter.acceptsDefaultValue ) } + + companion object { + fun evaluateProtobufTypeCanonicalName( + fieldDescriptorTypeName: String, + canonicalClassName: String, + type: FieldType, + fieldName: String + ): String = + fieldDescriptorTypeName.takeIf { it.isNotEmpty() } + ?.let { canonicalClassName } + // Protobuf primitives have no typeName + ?: requireNotNull(type.kotlinRepresentation) { + "no kotlin representation for type of $fieldName: $type" + }.qualifiedName!! + } } private fun tryDeserializeDefaultValue(converter: Converter): Throwable? { @@ -139,7 +154,7 @@ private fun tryDeserializeDefaultValue(converter: Converter): Th } class ConverterDetails( - val converterClass: KClass<*>, + val converter: Converter<*, *>, val kotlinCanonicalClassName: String, val optimizedSizeof: Boolean, val cannotDeserializeDefaultValue: Boolean diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt b/unpublished/src/reflect/protokt/v1/reflect/FieldType.kt similarity index 68% rename from protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt rename to unpublished/src/reflect/protokt/v1/reflect/FieldType.kt index 12fb04eb9..b8c45baaf 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/FieldType.kt @@ -13,20 +13,15 @@ * limitations under the License. */ -package protokt.v1.codegen.util +package protokt.v1.reflect -import com.squareup.kotlinpoet.CodeBlock -import com.squareup.kotlinpoet.MemberName -import com.squareup.kotlinpoet.MemberName.Companion.member -import com.squareup.kotlinpoet.asTypeName +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type import protokt.v1.KtEnum import protokt.v1.KtMessage import protokt.v1.KtMessageSerializer -import protokt.v1.SizeCodecs -import protokt.v1.codegen.generate.sizeOf import kotlin.reflect.KClass -sealed class FieldType { +internal sealed class FieldType { open val kotlinRepresentation: KClass<*>? = null open val inlineRepresentation: KClass<*>? = null open val ktRepresentation: KClass<*>? = null @@ -84,20 +79,6 @@ sealed class FieldType { else -> "write" } - sealed interface SizeFn - class Const(val size: Int) : SizeFn - class Method(val method: MemberName) : SizeFn - - val sizeFn: SizeFn - get() = when (this) { - Bool -> Const(1) - Double, Fixed64, SFixed64 -> Const(8) - Float, Fixed32, SFixed32 -> Const(4) - SInt32 -> Method(SizeCodecs::class.asTypeName().member(SizeCodecs::sizeOfSInt32.name)) - SInt64 -> Method(SizeCodecs::class.asTypeName().member(SizeCodecs::sizeOfSInt64.name)) - else -> Method(sizeOf) - } - val scalar get() = this is Scalar @@ -125,18 +106,27 @@ sealed class FieldType { SFixed32 -> 5 } - val defaultValue: CodeBlock - get() = when (this) { - Message -> CodeBlock.of("null") - Enum -> error("enums do not have defaults; this is bug in the code generator") - Bool -> CodeBlock.of("false") - Fixed32, UInt32 -> CodeBlock.of("0u") - Int32, SFixed32, SInt32 -> CodeBlock.of("0") - Fixed64, UInt64 -> CodeBlock.of("0uL") - Int64, SFixed64, SInt64 -> CodeBlock.of("0L") - Float -> CodeBlock.of("0.0F") - Double -> CodeBlock.of("0.0") - Bytes -> CodeBlock.of("%T.empty()", protokt.v1.Bytes::class) - String -> CodeBlock.of("\"\"") - } + companion object { + fun from(type: Type) = + when (type) { + Type.TYPE_BOOL -> Bool + Type.TYPE_BYTES -> Bytes + Type.TYPE_DOUBLE -> Double + Type.TYPE_ENUM -> Enum + Type.TYPE_FIXED32 -> Fixed32 + Type.TYPE_FIXED64 -> Fixed64 + Type.TYPE_FLOAT -> Float + Type.TYPE_INT32 -> Int32 + Type.TYPE_INT64 -> Int64 + Type.TYPE_MESSAGE -> Message + Type.TYPE_SFIXED32 -> SFixed32 + Type.TYPE_SFIXED64 -> SFixed64 + Type.TYPE_SINT32 -> SInt32 + Type.TYPE_SINT64 -> SInt64 + Type.TYPE_STRING -> String + Type.TYPE_UINT32 -> UInt32 + Type.TYPE_UINT64 -> UInt64 + else -> error("Unknown type: $type") + } + } } diff --git a/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt new file mode 100644 index 000000000..ade99f337 --- /dev/null +++ b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.reflect + +import protokt.v1.Bytes + +internal val PROTOKT_V1 = Bytes::class.java.`package`.name + +internal fun typeName(protoTypeName: String, fieldType: FieldType): String { + val fullyProtoQualified = protoTypeName.startsWith(".") + + return if (fullyProtoQualified) { + requalifyProtoType(protoTypeName) + } else { + protoTypeName.let { + it.ifEmpty { + fieldType.protoktFieldType.qualifiedName!! + } + } + } +} + +internal fun requalifyProtoType(typeName: String) = + // type name might have a `.` prefix + if (typeName.startsWith(".$PROTOKT_V1")) { + typeName.removePrefix(".") + } else { + "$PROTOKT_V1." + typeName.removePrefix(".") + } From cd757cabcb3b89ac05251944f224c4f278de0750 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 22:31:02 -0500 Subject: [PATCH 08/38] map value well known wrapper types do not work correctly --- .../v1/codegen/generate/KotlinPoetUtil.kt | 11 +---- .../v1/codegen/generate/OneofGenerator.kt | 2 +- .../protokt/v1/codegen/generate/Wrapper.kt | 10 +++-- .../v1/codegen/util/PackageResolution.kt | 7 +--- .../protokt/v1/google/protobuf/KtMessages.kt | 40 ++++++++++++++----- .../v1/google/protobuf/DynamicMessageTest.kt | 15 ++++++- .../protokt/v1/testing/wrappers_dynamic.proto | 8 ++++ .../reflect/protokt/v1/reflect/ClassLookup.kt | 2 +- .../reflect/protokt/v1/reflect/ClassNames.kt | 38 ++++++++++++++++++ .../protokt/v1/reflect/PackageNames.kt | 7 ++++ 10 files changed, 107 insertions(+), 33 deletions(-) create mode 100644 unpublished/src/reflect/protokt/v1/reflect/ClassNames.kt diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt index 997bd2cfb..066ebf46a 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt @@ -26,6 +26,7 @@ import com.squareup.kotlinpoet.asTypeName import protokt.v1.Collections import protokt.v1.SizeCodecs import protokt.v1.codegen.generate.CodeGenerator.Context +import protokt.v1.reflect.inferClassName import kotlin.reflect.KClass import kotlin.reflect.KFunction1 @@ -87,12 +88,4 @@ fun CodeBlock.Builder.endControlFlowWithoutNewline() { internal fun inferClassName(className: String, ctx: Context) = inferClassName(className, ctx.info.kotlinPackage) - -fun inferClassName(className: String, pkg: String): ClassName { - val inferred = ClassName.bestGuess(className) - return if (inferred.packageName == "") { - ClassName(pkg, className.split(".")) - } else { - inferred - } -} + .let { (pkg, names) -> ClassName(pkg, names) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt index aba5fd790..95cd262c5 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt @@ -44,7 +44,7 @@ private class OneofGenerator( val implements = oneof.options.protokt.implements .takeIf { it.isNotEmpty() } - ?.let { inferClassName(it, ctx.info.kotlinPackage) } + ?.let { inferClassName(it, ctx) } TypeSpec.classBuilder(oneof.name) .addModifiers(KModifier.SEALED) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index 2b6892f1a..b952f0f6e 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -31,6 +31,7 @@ import protokt.v1.codegen.util.StandardField import protokt.v1.reflect.ClassLookup import protokt.v1.reflect.ConverterDetails import protokt.v1.reflect.FieldType +import protokt.v1.reflect.inferClassName import kotlin.reflect.KFunction2 internal object Wrapper { @@ -56,8 +57,9 @@ internal object Wrapper { className.canonicalName, type, fieldName - ).let(ClassName::bestGuess), - inferClassName(wrap, ctx.kotlinPackage), + ), + inferClassName(wrap, ctx.kotlinPackage) + .let { (pkg, names) -> ClassName(pkg, names).canonicalName }, ctx ) ) @@ -184,6 +186,6 @@ internal object Wrapper { ifWrapped ) - private fun converter(protoClassName: ClassName, kotlinClassName: ClassName, ctx: GeneratorContext) = - ctx.classLookup.converter(protoClassName.canonicalName, kotlinClassName.canonicalName) + private fun converter(protoClassName: String, kotlinClassName: String, ctx: GeneratorContext) = + ctx.classLookup.converter(protoClassName, kotlinClassName) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt index c36488634..b87ddfe53 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt @@ -17,6 +17,7 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.FileDescriptorProto import protokt.v1.reflect.PROTOKT_V1 +import protokt.v1.reflect.resolvePackage const val DOT_GOOGLE_PROTOBUF = ".google.protobuf" val PROTOKT_V1_GOOGLE_PROTO = PROTOKT_V1 + DOT_GOOGLE_PROTOBUF @@ -25,8 +26,4 @@ fun packagesByFileName(protoFileList: List) = protoFileList.associate { it.name to resolvePackage(it) } fun resolvePackage(fdp: FileDescriptorProto) = - if (fdp.`package`.startsWith(PROTOKT_V1)) { - fdp.`package` - } else { - "$PROTOKT_V1." + fdp.`package` - } + resolvePackage(fdp.`package`) diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 1f2fb25e1..2cf3e7e8c 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -37,6 +37,8 @@ import protokt.v1.KtGeneratedMessage import protokt.v1.KtMessage import protokt.v1.reflect.ClassLookup import protokt.v1.reflect.FieldType +import protokt.v1.reflect.inferClassName +import protokt.v1.reflect.resolvePackage import protokt.v1.reflect.typeName import kotlin.Any import kotlin.reflect.KClass @@ -64,7 +66,7 @@ class RuntimeContext internal constructor( else -> value } - internal fun unwrap(value: Any, field: FieldDescriptor): Any { + internal fun unwrap(value: Any, field: FieldDescriptor, wrap: String): Any { val proto = field.toProto() val type = FieldType.from(proto.type) val converterDetails = @@ -75,8 +77,8 @@ class RuntimeContext internal constructor( type, field.name ), - // todo: ths is not right; have to infer kotlin name like we do in codegen - value::class.qualifiedName!! + inferClassName(wrap, resolvePackage(field.file.`package`)) + .let { (pkg, names) -> pkg + "." + names.joinToString(".") } ) @Suppress("UNCHECKED_CAST") @@ -138,6 +140,8 @@ private fun toDynamicMessage( .apply { descriptor.fields.forEach { field -> ProtoktReflect.getField(message, field)?.let { value -> + val wrap = wrap(field) + setField( field, when { @@ -154,10 +158,16 @@ private fun toDynamicMessage( // todo: unwrap elements if wrapped field.isRepeated -> - (value as List<*>).map(context::convertValue) + (value as List<*>).map { + if (isWrapped(field, wrap)) { + context.convertValue(context.unwrap(it!!, field, wrap!!)) + } else { + context.convertValue(it) + } + } - isWrapped(field) -> - context.convertValue(context.unwrap(value, field)) + isWrapped(field, wrap) -> + context.convertValue(context.unwrap(value, field, wrap!!)) else -> context.convertValue(value) }, @@ -182,11 +192,19 @@ private val WRAPPER_TYPE_NAMES = "google.protobuf.BytesValue" ) -private fun isWrapped(field: FieldDescriptor): Boolean { +private fun isWrapped(field: FieldDescriptor, wrap: String?): Boolean { if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in WRAPPER_TYPE_NAMES) { return true } + return wrap != null +} + +private fun wrap(field: FieldDescriptor): String? { + if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in WRAPPER_TYPE_NAMES) { + return field.messageType.fullName + } + val options = field.toProto().options val propertyOptions = @@ -199,12 +217,12 @@ private fun isWrapped(field: FieldDescriptor): Boolean { .last() ) } else { - return false + return null } - return propertyOptions.wrap.isNotEmpty() || - propertyOptions.keyWrap.isNotEmpty() || - propertyOptions.valueWrap.isNotEmpty() + return propertyOptions.wrap.takeIf { it.isNotEmpty() } + ?: propertyOptions.keyWrap.takeIf { it.isNotEmpty() } + ?: propertyOptions.valueWrap.takeIf { it.isNotEmpty() } } private fun convertMap( diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt index 197c2d9fe..1780417c0 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt @@ -34,7 +34,7 @@ class DynamicMessageTest { fun `dynamic message serialization`() { val message = getAllTypesAllSet() - ; verifyMessage(message) + verifyMessage(message) } @Test @@ -52,6 +52,7 @@ class DynamicMessageTest { optionalUuid = UUID.randomUUID() // optionalIpAddress = InetAddress.getByName("127.0.0.2") optionalLocalDate = LocalDate.now().minusDays(2) + optionalString = "foo" } verifyMessage(message) @@ -70,7 +71,7 @@ class DynamicMessageTest { verifyMessage(message2) val message3 = - OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.SocketAddressOneof(InetSocketAddress.createUnresolved("127.0.0.1", 2319)) } + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.SocketAddressOneof(InetSocketAddress("127.0.0.1", 2319)) } verifyMessage(message3) @@ -98,6 +99,11 @@ class DynamicMessageTest { OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.NullableLocalDateOneof(LocalDate.now()) } verifyMessage(message8) + + val message9 = + OneofWrappers { wrappedOneof = OneofWrappers.WrappedOneof.OptionalString("foo") } + + verifyMessage(message9) } @Test @@ -106,6 +112,7 @@ class DynamicMessageTest { RepeatedWrappers { uuids = listOf(UUID.randomUUID(), UUID.randomUUID()) uuidsWrapped = listOf(UUID.randomUUID(), UUID.randomUUID()) + strings = listOf("foo") } verifyMessage(message) @@ -126,6 +133,10 @@ class DynamicMessageTest { LocalDate.now() to InetSocketAddress.createUnresolved("127.0.0.1", 2319), LocalDate.now().minusDays(1) to InetSocketAddress.createUnresolved("127.0.0.1", 2320) ) + + // todo: this needs to wrap properly + mapStringStringValue = + mapOf("foo" to StringValue { value = "bar" }) } verifyMessage(message) diff --git a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto index 63dc9647f..278ea49f2 100644 --- a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto +++ b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto @@ -69,6 +69,8 @@ message Wrappers { optional string optional_local_date = 14 [ (.protokt.v1.property).wrap = "java.time.LocalDate" ]; + + google.protobuf.StringValue optional_string = 15; } message OneofWrappers { @@ -106,6 +108,8 @@ message OneofWrappers { google.protobuf.StringValue nullable_local_date_oneof = 10 [ (.protokt.v1.property).wrap = "java.time.LocalDate" ]; + + google.protobuf.StringValue optional_string = 11; } } @@ -117,6 +121,8 @@ message RepeatedWrappers { repeated google.protobuf.BytesValue uuids_wrapped = 2 [ (.protokt.v1.property).wrap = "java.util.UUID" ]; + + repeated google.protobuf.StringValue strings = 3; } message MapWrappers { @@ -129,4 +135,6 @@ message MapWrappers { (.protokt.v1.property).key_wrap = "java.time.LocalDate", (.protokt.v1.property).value_wrap = "java.net.InetSocketAddress" ]; + + map map_string_string_value = 9; } diff --git a/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt index ac23ec443..3df340a92 100644 --- a/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -153,7 +153,7 @@ private fun tryDeserializeDefaultValue(converter: Converter): Th return if (protoDefault == null) null else tryWrap(protoDefault as T) } -class ConverterDetails( +internal class ConverterDetails( val converter: Converter<*, *>, val kotlinCanonicalClassName: String, val optimizedSizeof: Boolean, diff --git a/unpublished/src/reflect/protokt/v1/reflect/ClassNames.kt b/unpublished/src/reflect/protokt/v1/reflect/ClassNames.kt new file mode 100644 index 000000000..9d0c5fcec --- /dev/null +++ b/unpublished/src/reflect/protokt/v1/reflect/ClassNames.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.reflect + +internal fun inferClassName(className: String, pkg: String): Pair> { + val inferred = bestGuessPackageName(className) + return if (inferred == null) { + pkg to className.split(".") + } else { + inferred to className.substringAfter("$inferred.").split(".") + } +} + +private fun bestGuessPackageName(classNameString: String): String? { + var p = 0 + while (p < classNameString.length && Character.isLowerCase(classNameString.codePointAt(p))) { + p = classNameString.indexOf('.', p) + 1 + require(p != 0) { "couldn't make a guess for $classNameString" } + } + return if (p != 0) { + classNameString.substring(0, p - 1) + } else { + null + } +} diff --git a/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt index ade99f337..a23832105 100644 --- a/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt @@ -40,3 +40,10 @@ internal fun requalifyProtoType(typeName: String) = } else { "$PROTOKT_V1." + typeName.removePrefix(".") } + +internal fun resolvePackage(pkg: String) = + if (pkg.startsWith(PROTOKT_V1)) { + pkg + } else { + "$PROTOKT_V1.$pkg" + } From 21d95342a3cdbd9932b97541047553403a089fbf Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 23:37:50 -0500 Subject: [PATCH 09/38] maps work --- .../protokt/v1/codegen/generate/Wrapper.kt | 6 +- .../v1/codegen/util/PackageResolution.kt | 2 +- .../protokt/v1/google/protobuf/KtMessages.kt | 119 +++++++++--------- .../v1/google/protobuf/DynamicMessageTest.kt | 8 +- .../protokt/v1/testing/wrappers_dynamic.proto | 2 +- .../protokt/v1/reflect/PackageNames.kt | 1 + .../protokt/v1/reflect}/WellKnownTypes.kt | 12 +- 7 files changed, 78 insertions(+), 72 deletions(-) rename {protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate => unpublished/src/reflect/protokt/v1/reflect}/WellKnownTypes.kt (74%) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index b952f0f6e..3479cb1a4 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -25,18 +25,18 @@ import protokt.v1.Converter import protokt.v1.OptimizedSizeOfConverter import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.hasNonNullOption -import protokt.v1.codegen.generate.WellKnownTypes.wrapWithWellKnownInterception import protokt.v1.codegen.util.GeneratorContext import protokt.v1.codegen.util.StandardField import protokt.v1.reflect.ClassLookup import protokt.v1.reflect.ConverterDetails import protokt.v1.reflect.FieldType +import protokt.v1.reflect.WellKnownTypes.wrapWithWellKnownInterception import protokt.v1.reflect.inferClassName import kotlin.reflect.KFunction2 internal object Wrapper { val StandardField.wrapped - get() = wrapWithWellKnownInterception != null + get() = wrapWithWellKnownInterception(options.protokt.wrap, protoTypeName) != null fun StandardField.wrapperRequiresNullability(ctx: Context) = wrapperRequiresNonNullOptionForNonNullity(ctx.info.context) && !hasNonNullOption @@ -69,7 +69,7 @@ internal object Wrapper { ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> R ) = - withWrapper(wrapWithWellKnownInterception, ctx, ifWrapped) + withWrapper(wrapWithWellKnownInterception(options.protokt.wrap, protoTypeName), ctx, ifWrapped) fun interceptSizeof( f: StandardField, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt index b87ddfe53..0045128d8 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt @@ -16,10 +16,10 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.FileDescriptorProto +import protokt.v1.reflect.DOT_GOOGLE_PROTOBUF import protokt.v1.reflect.PROTOKT_V1 import protokt.v1.reflect.resolvePackage -const val DOT_GOOGLE_PROTOBUF = ".google.protobuf" val PROTOKT_V1_GOOGLE_PROTO = PROTOKT_V1 + DOT_GOOGLE_PROTOBUF fun packagesByFileName(protoFileList: List) = diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 2cf3e7e8c..1129d5485 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -37,6 +37,7 @@ import protokt.v1.KtGeneratedMessage import protokt.v1.KtMessage import protokt.v1.reflect.ClassLookup import protokt.v1.reflect.FieldType +import protokt.v1.reflect.WellKnownTypes import protokt.v1.reflect.inferClassName import protokt.v1.reflect.resolvePackage import protokt.v1.reflect.typeName @@ -77,8 +78,7 @@ class RuntimeContext internal constructor( type, field.name ), - inferClassName(wrap, resolvePackage(field.file.`package`)) - .let { (pkg, names) -> pkg + "." + names.joinToString(".") } + wrap ) @Suppress("UNCHECKED_CAST") @@ -140,7 +140,7 @@ private fun toDynamicMessage( .apply { descriptor.fields.forEach { field -> ProtoktReflect.getField(message, field)?.let { value -> - val wrap = wrap(field) + val fieldOptions = fieldOptions(field) setField( field, @@ -152,24 +152,20 @@ private fun toDynamicMessage( field.enumType.findValueByNumberCreatingIfUnknown(((value as KtEnum).value)) } - // todo: unwrap keys and values if wrapped field.isMapField -> - convertMap(value, field, context) + convertMap(value, field, fieldOptions, context) - // todo: unwrap elements if wrapped field.isRepeated -> - (value as List<*>).map { - if (isWrapped(field, wrap)) { - context.convertValue(context.unwrap(it!!, field, wrap!!)) - } else { - context.convertValue(it) - } - } - - isWrapped(field, wrap) -> - context.convertValue(context.unwrap(value, field, wrap!!)) + convertList((value as List<*>), field, fieldOptions, context) - else -> context.convertValue(value) + else -> { + val wrap = wrap(field, fieldOptions) + if (wrap == null) { + context.convertValue(value) + } else { + context.convertValue(context.unwrap(value, field, wrap)) + } + } }, ) } @@ -179,56 +175,52 @@ private fun toDynamicMessage( .build() } -private val WRAPPER_TYPE_NAMES = - setOf( - "google.protobuf.DoubleValue", - "google.protobuf.FloatValue", - "google.protobuf.Int64Value", - "google.protobuf.UInt64Value", - "google.protobuf.Int32Value", - "google.protobuf.UInt32Value", - "google.protobuf.BoolValue", - "google.protobuf.StringValue", - "google.protobuf.BytesValue" - ) +private fun fieldOptions(field: FieldDescriptor): ProtoktProtos.FieldOptions { + val options = field.toProto().options -private fun isWrapped(field: FieldDescriptor, wrap: String?): Boolean { - if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in WRAPPER_TYPE_NAMES) { - return true + return if (options.hasField(ProtoktProtos.property.descriptor)) { + options.getField(ProtoktProtos.property.descriptor) as ProtoktProtos.FieldOptions + } else if (options.unknownFields.hasField(ProtoktProtos.property.number)) { + ProtoktProtos.FieldOptions.parseFrom( + options.unknownFields.getField(ProtoktProtos.property.number) + .lengthDelimitedList + .last() + ) + } else { + ProtoktProtos.FieldOptions.getDefaultInstance() } - - return wrap != null } -private fun wrap(field: FieldDescriptor): String? { - if (field.type == FieldDescriptor.Type.MESSAGE && field.messageType.fullName in WRAPPER_TYPE_NAMES) { - return field.messageType.fullName - } +private fun wrap(field: FieldDescriptor, fieldOptions: ProtoktProtos.FieldOptions) = + getClassName(fieldOptions.wrap, field) - val options = field.toProto().options +private fun getClassName(wrap: String, field: FieldDescriptor): String? = + wrap.takeIf { it.isNotEmpty() } + ?: WellKnownTypes.wrapWithWellKnownInterception(wrap, field.toProto().typeName) + ?.let { inferClassName(it, resolvePackage(field.file.`package`)) } + ?.let { (pkg, names) -> pkg + "." + names.joinToString(".") } - val propertyOptions = - if (options.hasField(ProtoktProtos.property.descriptor)) { - options.getField(ProtoktProtos.property.descriptor) as ProtoktProtos.FieldOptions - } else if (options.unknownFields.hasField(ProtoktProtos.property.number)) { - ProtoktProtos.FieldOptions.parseFrom( - options.unknownFields.getField(ProtoktProtos.property.number) - .lengthDelimitedList - .last() - ) +private fun convertList( + value: List<*>, + field: FieldDescriptor, + fieldOptions: ProtoktProtos.FieldOptions, + context: RuntimeContext +): List<*> { + val wrap = wrap(field, fieldOptions) + return value.map { + if (wrap == null) { + context.convertValue(it) } else { - return null + context.convertValue(context.unwrap(it!!, field, wrap)) } - - return propertyOptions.wrap.takeIf { it.isNotEmpty() } - ?: propertyOptions.keyWrap.takeIf { it.isNotEmpty() } - ?: propertyOptions.valueWrap.takeIf { it.isNotEmpty() } + } } private fun convertMap( value: Any, field: FieldDescriptor, - context: RuntimeContext, + fieldOptions: ProtoktProtos.FieldOptions, + context: RuntimeContext ): List> { val keyDesc = field.messageType.findFieldByNumber(1) val valDesc = field.messageType.findFieldByNumber(2) @@ -247,6 +239,9 @@ private fun convertMap( valDesc.defaultValue } + val keyWrap = getClassName(fieldOptions.keyWrap, keyDesc) + val valWrap = getClassName(fieldOptions.valueWrap, valDesc) + val defaultEntry = MapEntry.newDefaultInstance( field.messageType, @@ -258,8 +253,20 @@ private fun convertMap( return (value as Map<*, *>).map { (k, v) -> defaultEntry.toBuilder() - .setKey(context.convertValue(k)) - .setValue(context.convertValue(v)) + .setKey( + if (keyWrap == null) { + context.convertValue(k) + } else { + context.convertValue(context.unwrap(k!!, keyDesc, keyWrap)) + } + ) + .setValue( + if (valWrap == null) { + context.convertValue(v) + } else { + context.convertValue(context.unwrap(v!!, valDesc, valWrap)) + } + ) .build() } } diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt index 1780417c0..2334733ef 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt +++ b/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt @@ -130,13 +130,13 @@ class DynamicMessageTest { mapStringSocketAddress = mapOf( - LocalDate.now() to InetSocketAddress.createUnresolved("127.0.0.1", 2319), - LocalDate.now().minusDays(1) to InetSocketAddress.createUnresolved("127.0.0.1", 2320) + LocalDate.now() to InetSocketAddress("127.0.0.1", 2319), + LocalDate.now().minusDays(1) to InetSocketAddress("127.0.0.1", 2320) ) // todo: this needs to wrap properly - mapStringStringValue = - mapOf("foo" to StringValue { value = "bar" }) + // mapStringStringValue = + // mapOf("foo" to StringValue { value = "bar" }) } verifyMessage(message) diff --git a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto index 278ea49f2..7dfec893a 100644 --- a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto +++ b/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto @@ -136,5 +136,5 @@ message MapWrappers { (.protokt.v1.property).value_wrap = "java.net.InetSocketAddress" ]; - map map_string_string_value = 9; + // map map_string_string_value = 9; } diff --git a/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt index a23832105..391b7afe0 100644 --- a/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/PackageNames.kt @@ -18,6 +18,7 @@ package protokt.v1.reflect import protokt.v1.Bytes internal val PROTOKT_V1 = Bytes::class.java.`package`.name +internal const val DOT_GOOGLE_PROTOBUF = ".google.protobuf" internal fun typeName(protoTypeName: String, fieldType: FieldType): String { val fullyProtoQualified = protoTypeName.startsWith(".") diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt b/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt similarity index 74% rename from protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt rename to unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt index 11e8a922d..f53d974ea 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt @@ -13,17 +13,15 @@ * limitations under the License. */ -package protokt.v1.codegen.generate +package protokt.v1.reflect import protokt.v1.Bytes -import protokt.v1.codegen.util.DOT_GOOGLE_PROTOBUF -import protokt.v1.codegen.util.StandardField internal object WellKnownTypes { - val StandardField.wrapWithWellKnownInterception - get() = options.protokt.wrap.takeIf { it.isNotEmpty() } - ?: if (protoTypeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { - classNameForWellKnownType(protoTypeName.removePrefix("$DOT_GOOGLE_PROTOBUF.")) + fun wrapWithWellKnownInterception(wrap: String, typeName: String) = + wrap.takeIf { it.isNotEmpty() } + ?: if (typeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { + classNameForWellKnownType(typeName.removePrefix("$DOT_GOOGLE_PROTOBUF.")) } else { null } From 283d20d5456442c0e630e081352d96b82e710531 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 1 Jan 2024 23:43:41 -0500 Subject: [PATCH 10/38] compilation --- .../src/test/kotlin/protokt/v1/codegen/NonNullValidationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/NonNullValidationTest.kt b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/NonNullValidationTest.kt index 42b3745f8..5f2b694ea 100644 --- a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/NonNullValidationTest.kt +++ b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/NonNullValidationTest.kt @@ -19,7 +19,7 @@ import com.google.common.truth.Truth import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource -import protokt.v1.codegen.util.FieldType +import protokt.v1.reflect.FieldType class NonNullValidationTest : AbstractProtoktCodegenTest() { @ParameterizedTest From eca1983c4b9f5d9e05e60db62e3d5265f6102adb Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Tue, 2 Jan 2024 01:10:18 -0500 Subject: [PATCH 11/38] more tests --- .../codegen/generate/SerializerGenerator.kt | 4 --- .../protokt/v1/codegen/generate/Wrapper.kt | 13 ++++---- .../protokt/v1/codegen/ProtoktCodegenTest.kt | 33 +++++++++++++++++++ .../META-INF/services/protokt.v1.Converter | 1 + protokt-codegen/src/test/resources/test.proto | 6 +++- testing/interop/build.gradle.kts | 10 ++++-- .../google/protobuf/unittest_import.proto | 0 .../protobuf/unittest_import_public.proto | 0 .../google/protobuf/unittest_proto3.proto | 0 .../protokt/v1/testing/wrappers_dynamic.proto | 0 .../protokt/v1/testing}/DynamicMessageTest.kt | 8 ++--- .../kotlin/protokt/v1/testing}/TestUtil.kt | 2 +- testing/protobuf-java/build.gradle.kts | 1 + .../proto/protokt/v1/testing/wkt_test.proto | 5 +++ .../build.gradle.kts | 8 +++++ 15 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 protokt-codegen/src/test/resources/META-INF/services/protokt.v1.Converter rename {protokt-reflect/src/test => testing/interop/src/main}/proto/google/protobuf/unittest_import.proto (100%) rename {protokt-reflect/src/test => testing/interop/src/main}/proto/google/protobuf/unittest_import_public.proto (100%) rename {protokt-reflect/src/test => testing/interop/src/main}/proto/google/protobuf/unittest_proto3.proto (100%) rename {protokt-reflect/src/test => testing/interop/src/main}/proto/protokt/v1/testing/wrappers_dynamic.proto (100%) rename {protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf => testing/interop/src/test/kotlin/protokt/v1/testing}/DynamicMessageTest.kt (96%) rename {protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf => testing/interop/src/test/kotlin/protokt/v1/testing}/TestUtil.kt (98%) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt index e203e5bff..c04e82bb2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt @@ -28,7 +28,6 @@ import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField -import protokt.v1.reflect.FieldType internal fun generateSerializer(msg: Message, properties: List, ctx: Context) = SerializerGenerator(msg, properties, ctx).generate() @@ -115,9 +114,6 @@ internal fun serialize( } private fun StandardField.boxMap(ctx: Context): CodeBlock { - if (type != FieldType.Message) { - return CodeBlock.of("") - } val keyParam = mapKeyConverter(this, ctx) ?.let { CodeBlock.of("%T.unwrap(it.key)", it) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index 3479cb1a4..e36f67856 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -45,11 +45,11 @@ internal object Wrapper { withWrapper(ctx) { it.cannotDeserializeDefaultValue && !repeated } ?: false private fun StandardField.withWrapper( - wrapOption: String?, + wrap: String, ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> T ) = - wrapOption?.let { wrap -> + wrapWithWellKnownInterception(wrap, protoTypeName)?.let { ifWrapped( converter( ClassLookup.evaluateProtobufTypeCanonicalName( @@ -58,7 +58,7 @@ internal object Wrapper { type, fieldName ), - inferClassName(wrap, ctx.kotlinPackage) + inferClassName(it, ctx.kotlinPackage) .let { (pkg, names) -> ClassName(pkg, names).canonicalName }, ctx ) @@ -69,7 +69,7 @@ internal object Wrapper { ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> R ) = - withWrapper(wrapWithWellKnownInterception(options.protokt.wrap, protoTypeName), ctx, ifWrapped) + withWrapper(options.protokt.wrap, ctx, ifWrapped) fun interceptSizeof( f: StandardField, @@ -98,6 +98,7 @@ internal object Wrapper { } } ?: accessSize + // todo: this doesn't intercept map keys or values correctly fun interceptValueAccess( f: StandardField, ctx: Context, @@ -153,7 +154,7 @@ internal object Wrapper { ifWrapped: (ConverterDetails) -> R ) = mapEntry!!.key.withWrapper( - options.protokt.keyWrap.takeIf { it.isNotEmpty() }, + options.protokt.keyWrap, ctx.info.context, ifWrapped ) @@ -181,7 +182,7 @@ internal object Wrapper { ifWrapped: (ConverterDetails) -> R ) = mapEntry!!.value.withWrapper( - options.protokt.valueWrap.takeIf { it.isNotEmpty() }, + options.protokt.valueWrap, ctx.info.context, ifWrapped ) diff --git a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/ProtoktCodegenTest.kt b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/ProtoktCodegenTest.kt index 809c056e2..d61c3a8b9 100644 --- a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/ProtoktCodegenTest.kt +++ b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/ProtoktCodegenTest.kt @@ -16,6 +16,12 @@ package protokt.v1.codegen import org.junit.jupiter.api.Test +import protokt.v1.AbstractConverter +import protokt.v1.Bytes +import protokt.v1.OptimizedSizeOfConverter +import protokt.v1.SizeCodecs +import java.nio.ByteBuffer +import java.util.UUID class ProtoktCodegenTest : AbstractProtoktCodegenTest() { @Test @@ -30,3 +36,30 @@ class ProtoktCodegenTest : AbstractProtoktCodegenTest() { } } } + +object UuidBytesConverter : AbstractConverter(), OptimizedSizeOfConverter { + override val acceptsDefaultValue = false + + private val sizeOfProxy = ByteArray(16) + + override fun sizeOf(wrapped: UUID) = + SizeCodecs.sizeOf(sizeOfProxy) + + override fun wrap(unwrapped: Bytes): UUID { + val buf = unwrapped.asReadOnlyBuffer() + + require(buf.remaining() == 16) { + "UUID source must have size 16; had ${buf.remaining()}" + } + + return buf.run { UUID(long, long) } + } + + override fun unwrap(wrapped: UUID): Bytes = + Bytes.from( + ByteBuffer.allocate(16) + .putLong(wrapped.mostSignificantBits) + .putLong(wrapped.leastSignificantBits) + .array() + ) +} diff --git a/protokt-codegen/src/test/resources/META-INF/services/protokt.v1.Converter b/protokt-codegen/src/test/resources/META-INF/services/protokt.v1.Converter new file mode 100644 index 000000000..a7d962639 --- /dev/null +++ b/protokt-codegen/src/test/resources/META-INF/services/protokt.v1.Converter @@ -0,0 +1 @@ +protokt.v1.codegen.UuidBytesConverter diff --git a/protokt-codegen/src/test/resources/test.proto b/protokt-codegen/src/test/resources/test.proto index 44b8aa5ea..ffa79118e 100644 --- a/protokt-codegen/src/test/resources/test.proto +++ b/protokt-codegen/src/test/resources/test.proto @@ -17,8 +17,12 @@ syntax = "proto3"; package toasttab.protokt.v1.codegen.testing; +import "protokt/v1/protokt.proto"; + message TestMessage { - string value = 1; + map map_int_value_wrapped = 4 [ + (.protokt.v1.property).value_wrap = "java.util.UUID" + ]; } message Empty {} diff --git a/testing/interop/build.gradle.kts b/testing/interop/build.gradle.kts index cb81e0464..ec02d0cee 100644 --- a/testing/interop/build.gradle.kts +++ b/testing/interop/build.gradle.kts @@ -14,6 +14,7 @@ */ import protokt.v1.gradle.protokt +import protokt.v1.gradle.protoktExtensions plugins { id("protokt.jvm-conventions") @@ -30,11 +31,14 @@ protokt { } dependencies { - implementation(kotlin("reflect")) - implementation(project(":protokt-runtime-grpc")) - implementation(project(":testing:protobuf-java")) + protoktExtensions(project(":extensions:protokt-extensions")) + implementation(libs.grpc.stub) + implementation(project(":protokt-runtime-grpc")) + testImplementation(project(":protokt-reflect")) + testImplementation(project(":testing:protobuf-java")) + testImplementation(kotlin("reflect")) testImplementation(libs.jackson) testImplementation(libs.protobuf.java) } diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto b/testing/interop/src/main/proto/google/protobuf/unittest_import.proto similarity index 100% rename from protokt-reflect/src/test/proto/google/protobuf/unittest_import.proto rename to testing/interop/src/main/proto/google/protobuf/unittest_import.proto diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto b/testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto similarity index 100% rename from protokt-reflect/src/test/proto/google/protobuf/unittest_import_public.proto rename to testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto diff --git a/protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto b/testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto similarity index 100% rename from protokt-reflect/src/test/proto/google/protobuf/unittest_proto3.proto rename to testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto diff --git a/protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto b/testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto similarity index 100% rename from protokt-reflect/src/test/proto/protokt/v1/testing/wrappers_dynamic.proto rename to testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt similarity index 96% rename from protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt rename to testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt index 2334733ef..39d8afe5c 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/DynamicMessageTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt @@ -13,15 +13,13 @@ * limitations under the License. */ -package protokt.v1.google.protobuf +package protokt.v1.testing import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test import protokt.v1.KtMessage -import protokt.v1.testing.MapWrappers -import protokt.v1.testing.OneofWrappers -import protokt.v1.testing.RepeatedWrappers -import protokt.v1.testing.Wrappers +import protokt.v1.google.protobuf.RuntimeContext +import protokt.v1.google.protobuf.toDynamicMessage import java.net.InetAddress import java.net.InetSocketAddress import java.time.Duration diff --git a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt similarity index 98% rename from protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt rename to testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt index dc47c6fb6..92eb9f836 100644 --- a/protokt-reflect/src/jvmTest/kotlin/protokt/v1/google/protobuf/TestUtil.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt @@ -13,7 +13,7 @@ * limitations under the License. */ -package protokt.v1.google.protobuf +package protokt.v1.testing import protokt.v1.Bytes import protokt.v1.proto3_unittest.ForeignEnum diff --git a/testing/protobuf-java/build.gradle.kts b/testing/protobuf-java/build.gradle.kts index 86eefd1bb..80f624743 100644 --- a/testing/protobuf-java/build.gradle.kts +++ b/testing/protobuf-java/build.gradle.kts @@ -24,6 +24,7 @@ defaultProtoc() dependencies { compileOnly(libs.protobuf.java) + protobuf(project(":extensions:protokt-extensions")) } sourceSets { diff --git a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto index 5e3297f29..ed9b8191a 100644 --- a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto +++ b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto @@ -29,4 +29,9 @@ message WellKnownTypes { google.protobuf.BoolValue bool = 7; google.protobuf.StringValue string = 8; google.protobuf.BytesValue bytes = 9; + + repeated google.protobuf.DoubleValue doubles = 10; + + // todo! + // map string_values = 11; } diff --git a/third-party/proto-google-common-protos-lite/build.gradle.kts b/third-party/proto-google-common-protos-lite/build.gradle.kts index 76a5e9094..e3f722e00 100644 --- a/third-party/proto-google-common-protos-lite/build.gradle.kts +++ b/third-party/proto-google-common-protos-lite/build.gradle.kts @@ -51,3 +51,11 @@ kotlin { jvmTest.kotlin.srcDir(liteOptionTestSourceDir()) } } + +sourceSets { + test { + java { + srcDir(rootProject.file("unpublished/src/lite-util")) + } + } +} From 8e96790c9a6c6740434636af69b3660cb879667d Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Tue, 2 Jan 2024 01:30:00 -0500 Subject: [PATCH 12/38] api dump --- protokt-reflect/api/protokt-reflect.api | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index 3133d42b1..e4dcafaba 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1405,8 +1405,7 @@ public final class protokt/v1/google/protobuf/ProtoktReflectKt { public final class protokt/v1/google/protobuf/RuntimeContext { public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; - public fun (Ljava/util/Map;Ljava/lang/Iterable;)V - public final fun protobufJavaValue (Ljava/lang/Object;)Ljava/lang/Object; + public final fun convertValue (Ljava/lang/Object;)Ljava/lang/Object; } public final class protokt/v1/google/protobuf/RuntimeContext$Companion { From f980afa46a35b45e425c24c5f2b4358c3051609e Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Tue, 2 Jan 2024 20:41:22 -0500 Subject: [PATCH 13/38] fix field presence lookup --- .../protokt/v1/codegen/util/FieldTypeExt.kt | 4 +- .../protokt/v1/google/protobuf/KtMessages.kt | 6 +- .../v1/google/protobuf/ProtoktReflect.kt | 33 +++++++--- .../protokt/v1/testing/DynamicMessageTest.kt | 4 +- .../protokt/v1/testing/ProtoktReflectTest.kt | 66 +++++++++++++++++++ .../kotlin/protokt/v1/testing/TestUtil.kt | 1 + 6 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt index 64ae6c9c2..9a4f6b6fe 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt @@ -41,13 +41,13 @@ internal val FieldType.sizeFn internal val FieldType.defaultValue: CodeBlock get() = when (this) { FieldType.Message -> CodeBlock.of("null") - FieldType.Enum -> error("enums do not have defaults; this is bug in the code generator") + FieldType.Enum -> error("enums defaults are discovered external to this property; this is bug in the code generator") FieldType.Bool -> CodeBlock.of("false") FieldType.Fixed32, FieldType.UInt32 -> CodeBlock.of("0u") FieldType.Int32, FieldType.SFixed32, FieldType.SInt32 -> CodeBlock.of("0") FieldType.Fixed64, FieldType.UInt64 -> CodeBlock.of("0uL") FieldType.Int64, FieldType.SFixed64, FieldType.SInt64 -> CodeBlock.of("0L") - FieldType.Float -> CodeBlock.of("0.0F") + FieldType.Float -> CodeBlock.of("0.0f") FieldType.Double -> CodeBlock.of("0.0") FieldType.Bytes -> CodeBlock.of("%T.empty()", protokt.v1.Bytes::class) FieldType.String -> CodeBlock.of("\"\"") diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 1129d5485..fc3cee29c 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -53,6 +53,8 @@ class RuntimeContext internal constructor( descriptors: Iterable, private val classLookup: ClassLookup ) { + constructor(descriptors: Iterable) : this(descriptors, DEFAULT_CLASS_LOOKUP) + internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } fun convertValue(value: Any?) = @@ -87,8 +89,10 @@ class RuntimeContext internal constructor( } companion object { + private val DEFAULT_CLASS_LOOKUP by lazy { ClassLookup(emptyList()) } + private val reflectiveContext by lazy { - RuntimeContext(getDescriptors(), ClassLookup(emptyList())) + RuntimeContext(getDescriptors(), DEFAULT_CLASS_LOOKUP) } fun getContextReflectively() = diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt index 13420b241..53d190f7c 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt @@ -17,8 +17,9 @@ package protokt.v1.google.protobuf import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader -import com.google.protobuf.Descriptors import com.google.protobuf.Descriptors.FieldDescriptor +import com.google.protobuf.Descriptors.FieldDescriptor.Type +import protokt.v1.Bytes import protokt.v1.Fixed32Val import protokt.v1.Fixed64Val import protokt.v1.KtEnum @@ -106,7 +107,7 @@ object ProtoktReflect { value.varint .map(VarintVal::value) .map { - if (field.type == FieldDescriptor.Type.UINT64) { + if (field.type == Type.UINT64) { it } else { it.toLong() @@ -123,7 +124,7 @@ object ProtoktReflect { value.lengthDelimited .map(LengthDelimitedVal::value) .map { - if (field.type == Descriptors.FieldDescriptor.Type.STRING) { + if (field.type == Type.STRING) { StandardCharsets.UTF_8.decode(it.asReadOnlyBuffer()).toString() } else { it @@ -145,13 +146,29 @@ object ProtoktReflect { } } - fun getField( - message: KtMessage, - field: FieldDescriptor, - ): Any? = reflectedGettersByClass[message::class](field, message) + fun hasField(message: KtMessage, field: FieldDescriptor): Boolean { + val value = getField(message, field) + + return if (field.hasPresence()) { + value != null + } else { + value != defaultValue(field) + } + } + + fun getField(message: KtMessage, field: FieldDescriptor): Any? = + reflectedGettersByClass[message::class](field, message) } -fun getUnknownFields(message: KtMessage) = +private fun defaultValue(field: FieldDescriptor) = + when (field.type) { + Type.UINT64, Type.FIXED64 -> 0uL + Type.UINT32, Type.FIXED32 -> 0u + Type.BYTES -> Bytes.empty() + else -> field.defaultValue + } + +internal fun getUnknownFields(message: KtMessage) = message::class .declaredMemberProperties .firstOrNull { it.returnType.classifier == UnknownFieldSet::class } diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt index 39d8afe5c..54c86955c 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt @@ -40,7 +40,7 @@ class DynamicMessageTest { val message = Wrappers { uuid = UUID.randomUUID() - // ipAddress = InetAddress.getByName("127.0.0.1") + ipAddress = InetAddress.getByName("127.0.0.1") socketAddress = InetSocketAddress("127.0.0.1", 2319) instant = Instant.now() duration = Duration.ofSeconds(623, 2319) @@ -48,7 +48,7 @@ class DynamicMessageTest { nullableUuid = UUID.randomUUID() nullableLocalDate = LocalDate.now().minusDays(1) optionalUuid = UUID.randomUUID() - // optionalIpAddress = InetAddress.getByName("127.0.0.2") + optionalIpAddress = InetAddress.getByName("127.0.0.2") optionalLocalDate = LocalDate.now().minusDays(2) optionalString = "foo" } diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt new file mode 100644 index 000000000..870251999 --- /dev/null +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.testing + +import com.google.common.truth.Truth.assertThat +import com.google.protobuf.Descriptors.FieldDescriptor +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import proto3_unittest.UnittestProto3 +import protokt.v1.google.protobuf.ProtoktReflect +import protokt.v1.google.protobuf.RuntimeContext +import protokt.v1.proto3_unittest.TestAllTypes + +class ProtoktReflectTest { + private val context = RuntimeContext.getContextReflectively() + + @ParameterizedTest + @MethodSource("optionalDescriptors") + fun `hasField behavior matches for non-optional proto3 scalar fields`(field: FieldDescriptor) { + val protoDefault = TestAllTypes {} + val javaDefault = UnittestProto3.TestAllTypes.getDefaultInstance() + + assertThat(javaDefault.hasField(field)).isFalse() + assertThat(ProtoktReflect.hasField(protoDefault, field)).isFalse() + + assertThat(context.convertValue(ProtoktReflect.getField(protoDefault, field))) + .isEqualTo(javaDefault.getField(field)) + } + + companion object { + private val descriptor = UnittestProto3.TestAllTypes.getDescriptor() + + @JvmStatic + fun optionalDescriptors() = + listOf( + descriptor.findFieldByName("optional_int32"), + descriptor.findFieldByName("optional_int64"), + descriptor.findFieldByName("optional_uint32"), + descriptor.findFieldByName("optional_uint64"), + descriptor.findFieldByName("optional_sint32"), + descriptor.findFieldByName("optional_sint64"), + descriptor.findFieldByName("optional_fixed32"), + descriptor.findFieldByName("optional_fixed64"), + descriptor.findFieldByName("optional_sfixed32"), + descriptor.findFieldByName("optional_sfixed64"), + descriptor.findFieldByName("optional_float"), + descriptor.findFieldByName("optional_double"), + descriptor.findFieldByName("optional_bool"), + descriptor.findFieldByName("optional_string"), + descriptor.findFieldByName("optional_bytes") + ) + } +} diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt index 92eb9f836..50e48b1aa 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/TestUtil.kt @@ -38,6 +38,7 @@ fun getAllTypesAllSet() = optionalDouble = 112.0 optionalBool = true optionalString = "114" + optionalBytes = Bytes.from("115".toByteArray()) optionalNestedMessage = TestAllTypes.NestedMessage { bb = 115 } optionalForeignMessage = ForeignMessage { c = 116 } optionalNestedEnum = TestAllTypes.NestedEnum.FOO From 1036d0eb34705b8ecbb7c132b65fe7ab21ed89a7 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Tue, 2 Jan 2024 20:50:19 -0500 Subject: [PATCH 14/38] api dump --- protokt-reflect/api/protokt-reflect.api | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index e4dcafaba..3b8060ef4 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1397,14 +1397,12 @@ public final class protokt/v1/google/protobuf/KtMessages { public final class protokt/v1/google/protobuf/ProtoktReflect { public static final field INSTANCE Lprotokt/v1/google/protobuf/ProtoktReflect; public final fun getField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; -} - -public final class protokt/v1/google/protobuf/ProtoktReflectKt { - public static final fun getUnknownFields (Lprotokt/v1/KtMessage;)Ljava/util/Map; + public final fun hasField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Z } public final class protokt/v1/google/protobuf/RuntimeContext { public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; + public fun (Ljava/lang/Iterable;)V public final fun convertValue (Ljava/lang/Object;)Ljava/lang/Object; } From b2b0e1aa6daee20a8d3a3f6a9246a6a792f82f9c Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Tue, 2 Jan 2024 20:55:47 -0500 Subject: [PATCH 15/38] more api cleanup --- protokt-reflect/api/protokt-reflect.api | 8 ++--- .../protokt/v1/google/protobuf/KtMessages.kt | 30 ++++++++++++++++--- .../v1/google/protobuf/ProtoktReflect.kt | 21 +------------ .../protokt/v1/testing/ProtoktReflectTest.kt | 9 +++--- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index 3b8060ef4..a0301b303 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1391,15 +1391,11 @@ public final class protokt/v1/ServiceOptions$Deserializer : protokt/v1/AbstractK } public final class protokt/v1/google/protobuf/KtMessages { + public static final fun getField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; + public static final fun hasField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Z public static final fun toDynamicMessage (Lprotokt/v1/KtMessage;Lprotokt/v1/google/protobuf/RuntimeContext;)Lcom/google/protobuf/DynamicMessage; } -public final class protokt/v1/google/protobuf/ProtoktReflect { - public static final field INSTANCE Lprotokt/v1/google/protobuf/ProtoktReflect; - public final fun getField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Ljava/lang/Object; - public final fun hasField (Lprotokt/v1/KtMessage;Lcom/google/protobuf/Descriptors$FieldDescriptor;)Z -} - public final class protokt/v1/google/protobuf/RuntimeContext { public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; public fun (Ljava/lang/Iterable;)V diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index fc3cee29c..6bc91152a 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -20,6 +20,7 @@ package protokt.v1.google.protobuf import com.google.protobuf.DescriptorProtos import com.google.protobuf.Descriptors import com.google.protobuf.Descriptors.FieldDescriptor +import com.google.protobuf.Descriptors.FieldDescriptor.Type import com.google.protobuf.DynamicMessage import com.google.protobuf.MapEntry import com.google.protobuf.Message @@ -49,6 +50,27 @@ import kotlin.reflect.full.findAnnotation fun KtMessage.toDynamicMessage(context: RuntimeContext): DynamicMessage = context.convertValue(this) as DynamicMessage +fun KtMessage.hasField(field: FieldDescriptor): Boolean { + val value = getField(field) + + return if (field.hasPresence()) { + value != null + } else { + value != defaultValue(field) + } +} + +private fun defaultValue(field: FieldDescriptor) = + when (field.type) { + Type.UINT64, Type.FIXED64 -> 0uL + Type.UINT32, Type.FIXED32 -> 0u + Type.BYTES -> Bytes.empty() + else -> field.defaultValue + } + +fun KtMessage.getField(field: FieldDescriptor) = + ProtoktReflect.getField(this, field) + class RuntimeContext internal constructor( descriptors: Iterable, private val classLookup: ClassLookup @@ -143,13 +165,13 @@ private fun toDynamicMessage( return DynamicMessage.newBuilder(descriptor) .apply { descriptor.fields.forEach { field -> - ProtoktReflect.getField(message, field)?.let { value -> + message.getField(field)?.let { value -> val fieldOptions = fieldOptions(field) setField( field, when { - field.type == Descriptors.FieldDescriptor.Type.ENUM -> + field.type == Type.ENUM -> if (field.isRepeated) { (value as List<*>).map { field.enumType.findValueByNumberCreatingIfUnknown(((it as KtEnum).value)) } } else { @@ -230,14 +252,14 @@ private fun convertMap( val valDesc = field.messageType.findFieldByNumber(2) val keyDefault = - if (keyDesc.type == Descriptors.FieldDescriptor.Type.MESSAGE) { + if (keyDesc.type == Type.MESSAGE) { null } else { keyDesc.defaultValue } val valDefault = - if (valDesc.type == Descriptors.FieldDescriptor.Type.MESSAGE) { + if (valDesc.type == Type.MESSAGE) { null } else { valDesc.defaultValue diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt index 53d190f7c..d016c4ee5 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt @@ -19,7 +19,6 @@ import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheLoader import com.google.protobuf.Descriptors.FieldDescriptor import com.google.protobuf.Descriptors.FieldDescriptor.Type -import protokt.v1.Bytes import protokt.v1.Fixed32Val import protokt.v1.Fixed64Val import protokt.v1.KtEnum @@ -36,7 +35,7 @@ import kotlin.reflect.full.declaredMemberProperties import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.isSubclassOf -object ProtoktReflect { +internal object ProtoktReflect { private val reflectedGettersByClass = CacheBuilder.newBuilder() .build( @@ -146,28 +145,10 @@ object ProtoktReflect { } } - fun hasField(message: KtMessage, field: FieldDescriptor): Boolean { - val value = getField(message, field) - - return if (field.hasPresence()) { - value != null - } else { - value != defaultValue(field) - } - } - fun getField(message: KtMessage, field: FieldDescriptor): Any? = reflectedGettersByClass[message::class](field, message) } -private fun defaultValue(field: FieldDescriptor) = - when (field.type) { - Type.UINT64, Type.FIXED64 -> 0uL - Type.UINT32, Type.FIXED32 -> 0u - Type.BYTES -> Bytes.empty() - else -> field.defaultValue - } - internal fun getUnknownFields(message: KtMessage) = message::class .declaredMemberProperties diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt index 870251999..8a19fec1a 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt @@ -20,8 +20,9 @@ import com.google.protobuf.Descriptors.FieldDescriptor import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import proto3_unittest.UnittestProto3 -import protokt.v1.google.protobuf.ProtoktReflect import protokt.v1.google.protobuf.RuntimeContext +import protokt.v1.google.protobuf.getField +import protokt.v1.google.protobuf.hasField import protokt.v1.proto3_unittest.TestAllTypes class ProtoktReflectTest { @@ -30,13 +31,13 @@ class ProtoktReflectTest { @ParameterizedTest @MethodSource("optionalDescriptors") fun `hasField behavior matches for non-optional proto3 scalar fields`(field: FieldDescriptor) { - val protoDefault = TestAllTypes {} + val protoktDefault = TestAllTypes {} val javaDefault = UnittestProto3.TestAllTypes.getDefaultInstance() assertThat(javaDefault.hasField(field)).isFalse() - assertThat(ProtoktReflect.hasField(protoDefault, field)).isFalse() + assertThat(protoktDefault.hasField(field)).isFalse() - assertThat(context.convertValue(ProtoktReflect.getField(protoDefault, field))) + assertThat(context.convertValue(protoktDefault.getField(field))) .isEqualTo(javaDefault.getField(field)) } From 786ee1d9cc22d92dbaf5727c5e3882e7da05fb3c Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 00:04:26 -0500 Subject: [PATCH 16/38] fix map wrapper types --- .../v1/codegen/generate/BuilderGenerator.kt | 4 +- .../codegen/generate/DeserializerGenerator.kt | 20 ++------ .../codegen/generate/DeserializerSupport.kt | 4 +- .../v1/codegen/generate/MapEntryGenerator.kt | 33 +++++++------ .../v1/codegen/generate/MessageGenerator.kt | 44 ++++++++--------- .../codegen/generate/MessageSizeGenerator.kt | 24 ++------- .../v1/codegen/generate/PropertyAnnotator.kt | 32 ++++++------ .../codegen/generate/SerializerGenerator.kt | 26 ++++------ .../protokt/v1/codegen/generate/Wrapper.kt | 39 +++------------ .../protokt/v1/codegen/util/FieldParser.kt | 49 ++++++++++++++----- .../v1/codegen/util/FileContentParser.kt | 2 +- .../protokt/v1/codegen/util/MessageParser.kt | 8 +-- .../kotlin/protokt/v1/codegen/util/Types.kt | 17 ++++--- protokt-codegen/src/test/resources/test.proto | 8 +++ .../protokt/v1/google/protobuf/KtMessages.kt | 7 ++- .../protokt/v1/testing/wrappers_dynamic.proto | 2 +- .../protokt/v1/testing/DynamicMessageTest.kt | 5 +- .../proto/protokt/v1/testing/wkt_test.proto | 3 +- .../protokt/v1/reflect/WellKnownTypes.kt | 4 +- 19 files changed, 155 insertions(+), 176 deletions(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt index f493535be..ebe6aad69 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt @@ -70,7 +70,7 @@ private class BuilderGenerator( .mutable(true) .handleDeprecation(it.deprecation) .apply { - if (it.map) { + if (it.isMap) { setter( FunSpec.setterBuilder() .addParameter("newValue", Map::class) @@ -88,7 +88,7 @@ private class BuilderGenerator( } .initializer( when { - it.map -> CodeBlock.of("emptyMap()") + it.isMap -> CodeBlock.of("emptyMap()") it.repeated -> CodeBlock.of("emptyList()") it.fieldType == FieldType.Message || it.wrapped || it.nullable -> CodeBlock.of("null") else -> it.defaultValue diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index 4fc0478e3..9513eb196 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -30,8 +30,6 @@ import protokt.v1.KtMessageDeserializer import protokt.v1.UnknownFieldSet import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptRead -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.generate.Wrapper.wrapField import protokt.v1.codegen.generate.Wrapper.wrapper import protokt.v1.codegen.util.KotlinPlugin @@ -142,7 +140,7 @@ private class DeserializerGenerator( } private fun deserializeType(p: PropertyInfo) = - if (p.repeated || p.map) { + if (p.repeated || p.isMap) { p.deserializeType as ParameterizedTypeName ClassName(p.deserializeType.rawType.packageName, "Mutable" + p.deserializeType.rawType.simpleName) .parameterizedBy(p.deserializeType.typeArguments) @@ -220,7 +218,7 @@ internal fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false val wrappedRead = wrapper(f, ctx)?.let { wrapField(it, read) } ?: read return when { - f.map -> deserializeMap(f, ctx, read) + f.isMap -> deserializeMap(f, read) f.repeated -> buildCodeBlock { add("\n(%N ?: mutableListOf())", f.fieldName) @@ -234,24 +232,14 @@ internal fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false } } -private fun deserializeMap(f: StandardField, ctx: Context, read: CodeBlock): CodeBlock { - val key = - mapKeyConverter(f, ctx) - ?.let { wrapField(it, CodeBlock.of("it.key")) } - ?: CodeBlock.of("it.key") - - val value = - mapValueConverter(f, ctx) - ?.let { wrapField(it, CodeBlock.of("it.value")) } - ?: CodeBlock.of("it.value") - +private fun deserializeMap(f: StandardField, read: CodeBlock): CodeBlock { return buildCodeBlock { add("\n(%N ?: mutableMapOf())", f.fieldName) beginControlFlow(".apply") beginControlFlow("deserializer.readRepeated(false)") add(read) beginControlFlow(".let") - add("put(%L, %L)\n", key, value) + add("put(%L, %L)\n", CodeBlock.of("it.key"), CodeBlock.of("it.value")) endControlFlow() endControlFlow() endControlFlowWithoutNewline() diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt index e7fc42312..89706036b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt @@ -23,7 +23,7 @@ import protokt.v1.reflect.FieldType internal fun deserializeVarInitialState(p: PropertyInfo) = if ( (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) && - !p.mapEntry + !p.isMapEntry ) { CodeBlock.of("null") } else { @@ -48,7 +48,7 @@ internal fun wrapDeserializedValueForConstructor(p: PropertyInfo) = endControlFlowWithoutNewline() } } else { - if (p.map) { + if (p.isMap) { CodeBlock.of("%M(%N)", unmodifiableMap, p.name) } else if (p.repeated) { CodeBlock.of("%M(%N)", unmodifiableList, p.name) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index 4db14143b..c355f28a2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -30,7 +30,6 @@ import protokt.v1.KtMessageDeserializer import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.util.DESERIALIZER -import protokt.v1.codegen.util.MapEntry import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.SizeFn import protokt.v1.codegen.util.StandardField @@ -45,11 +44,16 @@ private class MapEntryGenerator( private val msg: Message, private val ctx: Context ) { - private val key = msg.fields[0] as StandardField + private val key = (msg.fields[0] as StandardField) private val value = msg.fields[1] as StandardField - private val keyProp = constructorProperty("key", key.className, false) - private val valProp = constructorProperty("value", value.className, false) + // todo: intercept keyWrap and valueWrap here + // todo: remove all `f.wrapped` checks from Wrapper.kt + private val keyTypeName = key.interceptTypeName(ctx) + private val valueTypeName = value.interceptTypeName(ctx) + + private val keyProp = constructorProperty("key", keyTypeName, false) + private val valProp = constructorProperty("value", valueTypeName, false) fun generate() = TypeSpec.classBuilder(msg.className).apply { @@ -66,8 +70,8 @@ private class MapEntryGenerator( private fun TypeSpec.Builder.addConstructor() { primaryConstructor( FunSpec.constructorBuilder() - .addParameter("key", key.className) - .addParameter("value", value.className) + .addParameter("key", keyTypeName) + .addParameter("value", valueTypeName) .build() ) } @@ -81,7 +85,8 @@ private class MapEntryGenerator( .addCode( "return·%L", sizeOfCall( - MapEntry(key, value), + key, + value, CodeBlock.of("key"), CodeBlock.of("value") ) @@ -117,10 +122,10 @@ private class MapEntryGenerator( buildFunSpec("entrySize") { returns(Int::class) if (key.type.sizeFn is SizeFn.Method) { - addParameter("key", key.className) + addParameter("key", keyTypeName) } if (value.type.sizeFn is SizeFn.Method) { - addParameter("value", value.className) + addParameter("value", valueTypeName) } addStatement("return %L + %L", sizeOf(key, ctx), sizeOf(value, ctx)) } @@ -174,21 +179,21 @@ private class MapEntryGenerator( buildCodeBlock { add("0u -> return %T(key, value", msg.className) if (f.type == FieldType.Message) { - add(" ?: %T{}", value.className) + add("!!") } add(")") } } -internal fun sizeOfCall(mapEntry: MapEntry, keyStr: CodeBlock, valueStr: CodeBlock) = - if (mapEntry.key.type.sizeFn is SizeFn.Method) { - if (mapEntry.value.type.sizeFn is SizeFn.Method) { +internal fun sizeOfCall(key: StandardField, value: StandardField, keyStr: CodeBlock, valueStr: CodeBlock) = + if (key.type.sizeFn is SizeFn.Method) { + if (value.type.sizeFn is SizeFn.Method) { CodeBlock.of("entrySize(%L,·%L)", keyStr, valueStr) } else { CodeBlock.of("entrySize(%L)", keyStr) } } else { - if (mapEntry.value.type.sizeFn is SizeFn.Method) { + if (value.type.sizeFn is SizeFn.Method) { CodeBlock.of("entrySize(%L)", valueStr) } else { CodeBlock.of("entrySize()") diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt index 58ebd5021..76c18c6d9 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt @@ -45,29 +45,27 @@ private class MessageGenerator( private val msg: Message, private val ctx: Context ) { - fun generate() = - if (msg.mapEntry) { - generateMapEntry(msg, ctx) - } else { - val properties = annotateProperties(msg, ctx) - val propertySpecs = properties(properties) - - TypeSpec.classBuilder(msg.className).apply { - annotateMessageDocumentation(ctx)?.let { addKdoc(formatDoc(it)) } - handleAnnotations() - handleConstructor(propertySpecs) - addTypes(annotateOneofs(msg, ctx)) - handleMessageSize() - addFunction(generateMessageSize(msg, propertySpecs, ctx)) - addFunction(generateSerializer(msg, propertySpecs, ctx)) - handleEquals(properties) - handleHashCode(properties) - handleToString(properties) - handleBuilder(msg, properties) - addType(generateDeserializer(msg, ctx, properties)) - addTypes(msg.nestedTypes.flatMap { generate(it, ctx) }) - }.build() - } + fun generate(): TypeSpec { + val properties = annotateProperties(msg, ctx) + val propertySpecs = properties(properties) + + return TypeSpec.classBuilder(msg.className).apply { + annotateMessageDocumentation(ctx)?.let { addKdoc(formatDoc(it)) } + handleAnnotations() + handleConstructor(propertySpecs) + addTypes(annotateOneofs(msg, ctx)) + handleMessageSize() + addFunction(generateMessageSize(msg, propertySpecs, ctx)) + addFunction(generateSerializer(msg, propertySpecs, ctx)) + handleEquals(properties) + handleHashCode(properties) + handleToString(properties) + handleBuilder(msg, properties) + addType(generateDeserializer(msg, ctx, properties)) + addTypes(properties.mapNotNull { it.mapEntry }.map { generateMapEntry(it, ctx) }) + addTypes(msg.nestedTypes.filterNot { it is Message && it.mapEntry }.flatMap { generate(it, ctx) }) + }.build() + } private fun TypeSpec.Builder.handleAnnotations() = apply { addAnnotation( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt index d490062c1..5c2417e2f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt @@ -25,8 +25,6 @@ import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.Wrapper.interceptFieldSizeof import protokt.v1.codegen.generate.Wrapper.interceptSizeof import protokt.v1.codegen.generate.Wrapper.interceptValueAccess -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.SizeFn @@ -115,7 +113,7 @@ internal fun sizeOf( } return when { - f.map -> sizeOfMap(f, fieldAccess, ctx) + f.isMap -> sizeOfMap(f, fieldAccess) f.repeated && f.packed -> { namedCodeBlock( "sizeOf(${f.tag}u) + " + @@ -154,28 +152,16 @@ internal fun sizeOf( private fun sizeOfMap( f: StandardField, - name: CodeBlock, - ctx: Context + name: CodeBlock ): CodeBlock { - val key = - mapKeyConverter(f, ctx) - ?.let { CodeBlock.of("%T.unwrap(k)", it) } - ?: CodeBlock.of("k") - - val value = - mapValueConverter(f, ctx) - ?.let { CodeBlock.of("%T.unwrap(v)", it) } - ?: CodeBlock.of("v") - - val mapEntry = f.mapEntry!! - val sizeOfCall = sizeOfCall(mapEntry, key, value) + val sizeOfCall = sizeOfCall(f.mapKey, f.mapValue, CodeBlock.of("k"), CodeBlock.of("v")) return buildCodeBlock { add( "%M($name, ${f.tag}u)·{·%L,·%L·->\n", sizeOf, - mapEntry.key.loopVar("k"), - mapEntry.value.loopVar("v") + f.mapKey.loopVar("k"), + f.mapValue.loopVar("v") ) indent() add("%T.%L\n", f.className, sizeOfCall) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt index a07196d9b..b1893cf86 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt @@ -67,8 +67,8 @@ private class PropertyAnnotator( defaultValue = field.defaultValue(ctx, msg.mapEntry), fieldType = field.type, repeated = field.repeated, - map = field.map, - mapEntry = msg.mapEntry, + mapEntry = field.mapEntry, + isMapEntry = msg.mapEntry, nullable = field.nullable || field.optional || wrapperRequiresNullability, nonNullOption = field.hasNonNullOption, overrides = field.overrides(ctx, msg), @@ -103,13 +103,13 @@ private class PropertyAnnotator( } private fun annotateStandard(f: StandardField): TypeName = - if (f.map) { + if (f.isMap) { val mapTypes = resolveMapEntryTypes(f, ctx) Map::class .asTypeName() .parameterizedBy(mapTypes.kType, mapTypes.vType) } else { - val parameter = interceptTypeName(f, ctx) ?: f.className + val parameter = f.interceptTypeName(ctx) if (f.repeated) { List::class.asTypeName().parameterizedBy(parameter) @@ -119,12 +119,10 @@ private class PropertyAnnotator( } private fun resolveMapEntryTypes(f: StandardField, ctx: Context) = - f.mapEntry!!.let { - MapTypeParams( - interceptMapKeyTypeName(f, ctx) ?: it.key.className, - interceptMapValueTypeName(f, ctx) ?: it.value.className - ) - } + MapTypeParams( + interceptMapKeyTypeName(f, ctx) ?: f.mapKey.className, + interceptMapValueTypeName(f, ctx) ?: f.mapValue.className + ) private class MapTypeParams( val kType: TypeName, @@ -137,7 +135,7 @@ private class PropertyAnnotator( interceptDefaultValue( this, when { - map -> CodeBlock.of("emptyMap()") + isMap -> CodeBlock.of("emptyMap()") repeated -> CodeBlock.of("emptyList()") type == FieldType.Message -> CodeBlock.of("null") type == FieldType.Enum -> CodeBlock.of("%T.from(0)", className) @@ -150,6 +148,9 @@ private class PropertyAnnotator( } } +internal fun StandardField.interceptTypeName(ctx: Context) = + interceptTypeName(this, ctx) ?: className + internal class PropertyInfo( val name: String, val number: Int? = null, @@ -159,13 +160,16 @@ internal class PropertyInfo( val defaultValue: CodeBlock, val nullable: Boolean, val nonNullOption: Boolean, - val mapEntry: Boolean = false, + val isMapEntry: Boolean = false, val fieldType: FieldType? = null, val repeated: Boolean = false, - val map: Boolean = false, + val mapEntry: Message? = null, val oneof: Boolean = false, val wrapped: Boolean = false, val overrides: Boolean = false, val documentation: List?, val deprecation: Deprecation.RenderOptions? = null -) +) { + val isMap + get() = mapEntry != null +} diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt index c04e82bb2..6dcf5c82f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt @@ -23,8 +23,6 @@ import com.squareup.kotlinpoet.buildCodeBlock import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptValueAccess -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField @@ -85,11 +83,11 @@ internal fun serialize( ) add("%N.forEach·{·serializer.%L·}", p, f.write(CodeBlock.of("it"))) } - f.map -> buildCodeBlock { + f.isMap -> buildCodeBlock { beginControlFlow("%N.entries.forEach", p) add( "serializer.writeTag(${f.tag.value}u).write(%L)\n", - f.boxMap(ctx) + f.boxMap() ) endControlFlowWithoutNewline() } @@ -113,19 +111,13 @@ internal fun serialize( } } -private fun StandardField.boxMap(ctx: Context): CodeBlock { - val keyParam = - mapKeyConverter(this, ctx) - ?.let { CodeBlock.of("%T.unwrap(it.key)", it) } - ?: CodeBlock.of("it.key") - - val valParam = - mapValueConverter(this, ctx) - ?.let { CodeBlock.of("%T.unwrap(it.value)", it) } - ?: CodeBlock.of("it.value") - - return CodeBlock.of("%T(%L, %L)", className, keyParam, valParam) -} +private fun StandardField.boxMap() = + CodeBlock.of( + "%T(%L, %L)", + className, + CodeBlock.of("it.key"), + CodeBlock.of("it.value") + ) private fun StandardField.write(value: CodeBlock) = CodeBlock.of("%L(%L)", type.writeFn, value) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index e36f67856..d220433da 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -36,16 +36,16 @@ import kotlin.reflect.KFunction2 internal object Wrapper { val StandardField.wrapped - get() = wrapWithWellKnownInterception(options.protokt.wrap, protoTypeName) != null + get() = wrapWithWellKnownInterception(options.wrap, protoTypeName) != null fun StandardField.wrapperRequiresNullability(ctx: Context) = wrapperRequiresNonNullOptionForNonNullity(ctx.info.context) && !hasNonNullOption fun StandardField.wrapperRequiresNonNullOptionForNonNullity(ctx: GeneratorContext) = - withWrapper(ctx) { it.cannotDeserializeDefaultValue && !repeated } ?: false + wrapped && withWrapper(ctx) { it.cannotDeserializeDefaultValue && !repeated } ?: false private fun StandardField.withWrapper( - wrap: String, + wrap: String?, ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> T ) = @@ -69,7 +69,7 @@ internal object Wrapper { ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> R ) = - withWrapper(options.protokt.wrap, ctx, ifWrapped) + withWrapper(options.wrap, ctx, ifWrapped) fun interceptSizeof( f: StandardField, @@ -98,7 +98,6 @@ internal object Wrapper { } } ?: accessSize - // todo: this doesn't intercept map keys or values correctly fun interceptValueAccess( f: StandardField, ctx: Context, @@ -149,27 +148,11 @@ internal object Wrapper { private val StandardField.bytesSlice get() = options.protokt.bytesSlice - private fun StandardField.withKeyWrap( - ctx: Context, - ifWrapped: (ConverterDetails) -> R - ) = - mapEntry!!.key.withWrapper( - options.protokt.keyWrap, - ctx.info.context, - ifWrapped - ) - fun interceptMapKeyTypeName(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ::kotlinClassName) - - fun mapKeyConverter(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ::converterClassName) + f.mapKey.withWrapper(ctx.info.context, ::kotlinClassName) fun interceptMapValueTypeName(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ::kotlinClassName) - - fun mapValueConverter(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ::converterClassName) + f.mapValue.withWrapper(ctx.info.context, ::kotlinClassName) private fun kotlinClassName(converterDetails: ConverterDetails) = ClassName.bestGuess(converterDetails.kotlinCanonicalClassName) @@ -177,16 +160,6 @@ internal object Wrapper { private fun converterClassName(converterDetails: ConverterDetails) = converterDetails.converter::class.asClassName() - private fun StandardField.withValueWrap( - ctx: Context, - ifWrapped: (ConverterDetails) -> R - ) = - mapEntry!!.value.withWrapper( - options.protokt.valueWrap, - ctx.info.context, - ifWrapped - ) - private fun converter(protoClassName: String, kotlinClassName: String, ctx: GeneratorContext) = ctx.classLookup.converter(protoClassName, kotlinClassName) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt index 4253c297f..b27f40680 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt @@ -35,7 +35,9 @@ import protokt.v1.reflect.typeName internal class FieldParser( private val ctx: GeneratorContext, private val desc: DescriptorProto, - private val enclosingMessages: List + private val enclosingMessages: List, + private val keyWrap: String?, + private val valueWrap: String? ) { fun toFields(): List { val generatedOneofIndices = mutableSetOf() @@ -106,7 +108,19 @@ internal class FieldParser( val fieldType = FieldType.from(fdp.type) val protoktOptions = fdp.options.getExtension(ProtoktProtos.property) val repeated = fdp.label == LABEL_REPEATED - val mapEntry = mapEntry(fdp) + val mapEntry = mapEntry(fdp, protoktOptions) + if (mapEntry == null) { + require(protoktOptions.keyWrap.isEmpty()) { + "key wrap is not applicable to non-map-entry" + } + require(protoktOptions.valueWrap.isEmpty()) { + "value wrap is not applicable to non-map-entry" + } + } else { + require(protoktOptions.wrap.isEmpty()) { + "wrap is not applicable to map entry" + } + } val optional = optional(fdp) val packed = packed(fieldType, fdp) val tag = @@ -125,7 +139,15 @@ internal class FieldParser( packed = packed, mapEntry = mapEntry, fieldName = LOWER_UNDERSCORE.to(LOWER_CAMEL, fdp.name), - options = FieldOptions(fdp.options, protoktOptions), + options = FieldOptions( + fdp.options, + protoktOptions, + when { + keyWrap != null && idx == 0 -> keyWrap + valueWrap != null && idx == 1 -> valueWrap + else -> protoktOptions.wrap.takeIf { it.isNotEmpty() } + } + ), protoTypeName = fdp.typeName, className = ClassName.bestGuess(typeName(fdp.typeName, fieldType)), index = idx @@ -138,21 +160,24 @@ internal class FieldParser( return result } - private fun mapEntry(fdp: FieldDescriptorProto) = + private fun mapEntry(fdp: FieldDescriptorProto, options: ProtoktProtos.FieldOptions) = if (fdp.label == LABEL_REPEATED && fdp.type == Type.TYPE_MESSAGE) { findMapEntry(ctx.fdp, fdp.typeName) ?.takeIf { it.options.mapEntry } - ?.let { resolveMapEntry(MessageParser(ctx, -1, it, enclosingMessages).toMessage()) } + ?.let { entry -> + MessageParser( + ctx, + -1, + entry, + enclosingMessages + desc.name, + options.keyWrap.takeIf { it.isNotEmpty() }, + options.valueWrap.takeIf { it.isNotEmpty() } + ).toMessage() + } } else { null } - private fun resolveMapEntry(m: Message) = - MapEntry( - (m.fields[0] as StandardField), - (m.fields[1] as StandardField) - ) - private fun findMapEntry( fdp: FileDescriptorProto, name: String, @@ -232,7 +257,7 @@ internal class FieldParser( "and is inapplicable to non-message " + when { field.mapEntry != null -> - "map<${name(field.mapEntry.key)}, ${name(field.mapEntry.value)}>" + "map<${name(field.mapKey)}, ${name(field.mapValue)}>" field.repeated -> "repeated $typeName" diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt index 4d80c4693..b712dbe33 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt @@ -51,7 +51,7 @@ internal class FileContentParser( } + messages.mapIndexed { idx, desc -> withMessageName((enclosingMessages + desc.name).joinToString(".")) { - MessageParser(ctx, idx, desc, enclosingMessages).toMessage() + MessageParser(ctx, idx, desc, enclosingMessages, null, null).toMessage() } } + services.mapIndexed { idx, desc -> diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt index 946cbe064..51a2a63bc 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt @@ -22,10 +22,12 @@ internal class MessageParser( private val ctx: GeneratorContext, private val idx: Int, private val desc: DescriptorProto, - private val enclosingMessages: List + private val enclosingMessages: List, + private val keyWrap: String?, + private val valueWrap: String? ) { fun toMessage(): Message { - val fieldList = FieldParser(ctx, desc, enclosingMessages).toFields() + val fieldList = FieldParser(ctx, desc, enclosingMessages, keyWrap, valueWrap).toFields() val simpleNames = enclosingMessages + desc.name return Message( fields = fieldList.sortedBy { @@ -41,7 +43,7 @@ internal class MessageParser( emptyList(), simpleNames ).parseContents(), - mapEntry = desc.options?.mapEntry == true, + mapEntry = desc.options.mapEntry, options = MessageOptions( desc.options, desc.options.getExtension(ProtoktProtos.class_) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt index 5da7a9b0b..0dae04069 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt @@ -112,13 +112,18 @@ internal class StandardField( val repeated: Boolean, val optional: Boolean, val packed: Boolean, - val mapEntry: MapEntry?, + val mapEntry: Message?, val protoTypeName: String, val options: FieldOptions, val index: Int ) : Field() { - val map + val isMap get() = mapEntry != null + + val mapKey + get() = mapEntry!!.fields[0] as StandardField + val mapValue + get() = mapEntry!!.fields[1] as StandardField } internal class Oneof( @@ -131,14 +136,10 @@ internal class Oneof( val index: Int ) : Field() -internal class MapEntry( - val key: StandardField, - val value: StandardField -) - class FieldOptions( val default: DescriptorProtos.FieldOptions, - val protokt: ProtoktProtos.FieldOptions + val protokt: ProtoktProtos.FieldOptions, + val wrap: String? ) class OneofOptions( diff --git a/protokt-codegen/src/test/resources/test.proto b/protokt-codegen/src/test/resources/test.proto index ffa79118e..bf28c58f1 100644 --- a/protokt-codegen/src/test/resources/test.proto +++ b/protokt-codegen/src/test/resources/test.proto @@ -17,12 +17,20 @@ syntax = "proto3"; package toasttab.protokt.v1.codegen.testing; +import "google/protobuf/wrappers.proto"; import "protokt/v1/protokt.proto"; message TestMessage { + // google.protobuf.DoubleValue double = 1; + map map = 1; + + /* map map_int_value_wrapped = 4 [ (.protokt.v1.property).value_wrap = "java.util.UUID" ]; + */ } +/* message Empty {} + */ diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 6bc91152a..3eb3e7941 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -221,10 +221,9 @@ private fun wrap(field: FieldDescriptor, fieldOptions: ProtoktProtos.FieldOption getClassName(fieldOptions.wrap, field) private fun getClassName(wrap: String, field: FieldDescriptor): String? = - wrap.takeIf { it.isNotEmpty() } - ?: WellKnownTypes.wrapWithWellKnownInterception(wrap, field.toProto().typeName) - ?.let { inferClassName(it, resolvePackage(field.file.`package`)) } - ?.let { (pkg, names) -> pkg + "." + names.joinToString(".") } + WellKnownTypes.wrapWithWellKnownInterception(wrap.takeIf { it.isNotEmpty() }, field.toProto().typeName) + ?.let { inferClassName(it, resolvePackage(field.file.`package`)) } + ?.let { (pkg, names) -> pkg + "." + names.joinToString(".") } private fun convertList( value: List<*>, diff --git a/testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto b/testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto index 7dfec893a..278ea49f2 100644 --- a/testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto +++ b/testing/interop/src/main/proto/protokt/v1/testing/wrappers_dynamic.proto @@ -136,5 +136,5 @@ message MapWrappers { (.protokt.v1.property).value_wrap = "java.net.InetSocketAddress" ]; - // map map_string_string_value = 9; + map map_string_string_value = 9; } diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt index 54c86955c..b206276ed 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt @@ -132,9 +132,8 @@ class DynamicMessageTest { LocalDate.now().minusDays(1) to InetSocketAddress("127.0.0.1", 2320) ) - // todo: this needs to wrap properly - // mapStringStringValue = - // mapOf("foo" to StringValue { value = "bar" }) + mapStringStringValue = + mapOf("foo" to "bar") } verifyMessage(message) diff --git a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto index ed9b8191a..b5e9c49ca 100644 --- a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto +++ b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto @@ -32,6 +32,5 @@ message WellKnownTypes { repeated google.protobuf.DoubleValue doubles = 10; - // todo! - // map string_values = 11; + map string_values = 11; } diff --git a/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt b/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt index f53d974ea..7473326d9 100644 --- a/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt +++ b/unpublished/src/reflect/protokt/v1/reflect/WellKnownTypes.kt @@ -18,8 +18,8 @@ package protokt.v1.reflect import protokt.v1.Bytes internal object WellKnownTypes { - fun wrapWithWellKnownInterception(wrap: String, typeName: String) = - wrap.takeIf { it.isNotEmpty() } + fun wrapWithWellKnownInterception(wrap: String?, typeName: String) = + wrap ?: if (typeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { classNameForWellKnownType(typeName.removePrefix("$DOT_GOOGLE_PROTOBUF.")) } else { From 9d426aa466b0adae2cbdcb508333ea4a2f89cdaa Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 00:13:29 -0500 Subject: [PATCH 17/38] some cleanup --- .../protokt/v1/codegen/generate/MapEntryGenerator.kt | 5 ++--- .../kotlin/protokt/v1/codegen/generate/OneofGenerator.kt | 8 +------- .../protokt/v1/codegen/generate/PropertyAnnotator.kt | 3 --- .../main/kotlin/protokt/v1/codegen/generate/Wrapper.kt | 8 ++++---- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index c355f28a2..e02ed632b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -29,6 +29,7 @@ import protokt.v1.KtMessage import protokt.v1.KtMessageDeserializer import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context +import protokt.v1.codegen.generate.Wrapper.interceptTypeName import protokt.v1.codegen.util.DESERIALIZER import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.SizeFn @@ -44,11 +45,9 @@ private class MapEntryGenerator( private val msg: Message, private val ctx: Context ) { - private val key = (msg.fields[0] as StandardField) + private val key = msg.fields[0] as StandardField private val value = msg.fields[1] as StandardField - // todo: intercept keyWrap and valueWrap here - // todo: remove all `f.wrapped` checks from Wrapper.kt private val keyTypeName = key.interceptTypeName(ctx) private val valueTypeName = value.interceptTypeName(ctx) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt index 95cd262c5..f1074d637 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt @@ -26,7 +26,6 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Deprecation.renderOptions import protokt.v1.codegen.generate.Implements.handleSuperInterface import protokt.v1.codegen.generate.Wrapper.interceptTypeName -import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField @@ -103,12 +102,7 @@ private class OneofGenerator( OneofGeneratorInfo( fieldName = f.fieldName, number = f.number, - type = - if (f.wrapped) { - interceptTypeName(f, ctx) ?: f.className - } else { - f.className - }, + type = f.interceptTypeName(ctx), documentation = annotatePropertyDocumentation(f, ctx), deprecation = deprecation(f) ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt index b1893cf86..6fb31d213 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt @@ -148,9 +148,6 @@ private class PropertyAnnotator( } } -internal fun StandardField.interceptTypeName(ctx: Context) = - interceptTypeName(this, ctx) ?: className - internal class PropertyInfo( val name: String, val number: Int? = null, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index d220433da..a933e8d98 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -138,12 +138,12 @@ internal object Wrapper { } } - fun interceptTypeName(f: StandardField, ctx: Context) = - if (f.bytesSlice) { + fun StandardField.interceptTypeName(ctx: Context) = + if (bytesSlice) { BytesSlice::class.asTypeName() } else { - f.withWrapper(ctx.info.context, ::kotlinClassName) - } + withWrapper(ctx.info.context, ::kotlinClassName) + } ?: className private val StandardField.bytesSlice get() = options.protokt.bytesSlice From 5f6a2805e439648ac93f43ca2bbbbbbbe994e87d Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 01:05:34 -0500 Subject: [PATCH 18/38] mostly clean up map wrapper types --- .../codegen/generate/DeserializerSupport.kt | 5 +-- .../v1/codegen/generate/MapEntryGenerator.kt | 34 ++++++++++++------- .../v1/codegen/generate/PropertyAnnotator.kt | 18 +--------- .../protokt/v1/codegen/generate/Wrapper.kt | 6 ---- protokt-codegen/src/test/resources/test.proto | 3 +- 5 files changed, 26 insertions(+), 40 deletions(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt index 89706036b..f2b19ffb6 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt @@ -21,10 +21,7 @@ import com.squareup.kotlinpoet.withIndent import protokt.v1.reflect.FieldType internal fun deserializeVarInitialState(p: PropertyInfo) = - if ( - (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) && - !p.isMapEntry - ) { + if (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) { CodeBlock.of("null") } else { p.defaultValue diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index e02ed632b..f245d0fd5 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -29,6 +29,8 @@ import protokt.v1.KtMessage import protokt.v1.KtMessageDeserializer import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context +import protokt.v1.codegen.generate.Nullability.nullable +import protokt.v1.codegen.generate.Wrapper.interceptDefaultValue import protokt.v1.codegen.generate.Wrapper.interceptTypeName import protokt.v1.codegen.util.DESERIALIZER import protokt.v1.codegen.util.Message @@ -54,6 +56,10 @@ private class MapEntryGenerator( private val keyProp = constructorProperty("key", keyTypeName, false) private val valProp = constructorProperty("value", valueTypeName, false) + private val propInfo = annotateProperties(msg, ctx) + private val keyPropInfo = propInfo[0] + private val valPropInfo = propInfo[1] + fun generate() = TypeSpec.classBuilder(msg.className).apply { addModifiers(KModifier.PRIVATE) @@ -108,8 +114,6 @@ private class MapEntryGenerator( } private fun TypeSpec.Builder.addDeserializer() { - val propInfo = annotateProperties(msg, ctx) - addType( TypeSpec.companionObjectBuilder(DESERIALIZER) .superclass( @@ -134,12 +138,12 @@ private class MapEntryGenerator( addModifiers(KModifier.OVERRIDE) addParameter("deserializer", KtMessageDeserializer::class) returns(msg.className) - addStatement("%L", deserializeVar(propInfo, ::key)) - addStatement("%L", deserializeVar(propInfo, ::value)) + addStatement("%L", deserializeVar(keyPropInfo, ::key)) + addStatement("%L", deserializeVar(valPropInfo, ::value)) addCode("\n") beginControlFlow("while (true)") beginControlFlow("when (deserializer.readTag())") - addStatement("%L", constructOnZero(value)) + addStatement("%L", constructOnZero()) addStatement( "${key.tag.value}u -> key = %L", deserialize(key, ctx) @@ -156,13 +160,12 @@ private class MapEntryGenerator( ) } - private fun deserializeVar(propInfo: List, accessor: KProperty0): CodeBlock { + private fun deserializeVar(prop: PropertyInfo, accessor: KProperty0): CodeBlock { val field = accessor.get() - val prop = propInfo.single { it.name == field.fieldName } return namedCodeBlock( "var ${accessor.name}" + - if (field.type == FieldType.Message) { + if (field.type == FieldType.Message || prop.wrapped || prop.nullable) { ": %type:T" } else { "" @@ -174,11 +177,18 @@ private class MapEntryGenerator( ) } - private fun constructOnZero(f: StandardField) = + private fun constructOnZero() = buildCodeBlock { - add("0u -> return %T(key, value", msg.className) - if (f.type == FieldType.Message) { - add("!!") + add("0u -> return %T(key", msg.className) + if (keyPropInfo.nullable || keyPropInfo.wrapped) { + add("?: %L", keyPropInfo.defaultValue) + } + add(", value") + if (value.type == FieldType.Message && !valPropInfo.wrapped) { + add("?: %T {}", value.className) + } else if (valPropInfo.nullable || valPropInfo.wrapped) { + // todo: add a test verifying absent message wrapped value type uses the default + add("?: %L", interceptDefaultValue(value, CodeBlock.of("%T {}", value.className), ctx)) } add(")") } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt index 6fb31d213..3f4aca019 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt @@ -28,8 +28,6 @@ import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.Nullability.nullable import protokt.v1.codegen.generate.Nullability.propertyType import protokt.v1.codegen.generate.Wrapper.interceptDefaultValue -import protokt.v1.codegen.generate.Wrapper.interceptMapKeyTypeName -import protokt.v1.codegen.generate.Wrapper.interceptMapValueTypeName import protokt.v1.codegen.generate.Wrapper.interceptTypeName import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNullability @@ -68,7 +66,6 @@ private class PropertyAnnotator( fieldType = field.type, repeated = field.repeated, mapEntry = field.mapEntry, - isMapEntry = msg.mapEntry, nullable = field.nullable || field.optional || wrapperRequiresNullability, nonNullOption = field.hasNonNullOption, overrides = field.overrides(ctx, msg), @@ -104,10 +101,9 @@ private class PropertyAnnotator( private fun annotateStandard(f: StandardField): TypeName = if (f.isMap) { - val mapTypes = resolveMapEntryTypes(f, ctx) Map::class .asTypeName() - .parameterizedBy(mapTypes.kType, mapTypes.vType) + .parameterizedBy(f.mapKey.interceptTypeName(ctx), f.mapValue.interceptTypeName(ctx)) } else { val parameter = f.interceptTypeName(ctx) @@ -118,17 +114,6 @@ private class PropertyAnnotator( } } - private fun resolveMapEntryTypes(f: StandardField, ctx: Context) = - MapTypeParams( - interceptMapKeyTypeName(f, ctx) ?: f.mapKey.className, - interceptMapValueTypeName(f, ctx) ?: f.mapValue.className - ) - - private class MapTypeParams( - val kType: TypeName, - val vType: TypeName - ) - private fun Field.defaultValue(ctx: Context, mapEntry: Boolean) = when (this) { is StandardField -> @@ -157,7 +142,6 @@ internal class PropertyInfo( val defaultValue: CodeBlock, val nullable: Boolean, val nonNullOption: Boolean, - val isMapEntry: Boolean = false, val fieldType: FieldType? = null, val repeated: Boolean = false, val mapEntry: Message? = null, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index a933e8d98..d022c007b 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -148,12 +148,6 @@ internal object Wrapper { private val StandardField.bytesSlice get() = options.protokt.bytesSlice - fun interceptMapKeyTypeName(f: StandardField, ctx: Context) = - f.mapKey.withWrapper(ctx.info.context, ::kotlinClassName) - - fun interceptMapValueTypeName(f: StandardField, ctx: Context) = - f.mapValue.withWrapper(ctx.info.context, ::kotlinClassName) - private fun kotlinClassName(converterDetails: ConverterDetails) = ClassName.bestGuess(converterDetails.kotlinCanonicalClassName) diff --git a/protokt-codegen/src/test/resources/test.proto b/protokt-codegen/src/test/resources/test.proto index bf28c58f1..eaf1c4d61 100644 --- a/protokt-codegen/src/test/resources/test.proto +++ b/protokt-codegen/src/test/resources/test.proto @@ -17,12 +17,13 @@ syntax = "proto3"; package toasttab.protokt.v1.codegen.testing; +import "google/protobuf/empty.proto"; import "google/protobuf/wrappers.proto"; import "protokt/v1/protokt.proto"; message TestMessage { // google.protobuf.DoubleValue double = 1; - map map = 1; + map map = 1; /* map map_int_value_wrapped = 4 [ From 3689bc8d0a7725541e142cd38c175ef55f749b5a Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 17:23:04 -0500 Subject: [PATCH 19/38] isolate more and get tests passing --- .../protokt-extensions-lite/build.gradle.kts | 9 + .../protokt/v1/protokt.proto | 0 .../protokt-extensions/build.gradle.kts | 1 + protokt-codegen/build.gradle.kts | 2 +- .../codegen/generate/DeserializerGenerator.kt | 3 +- .../v1/codegen/generate/MapEntryGenerator.kt | 24 ++- .../protokt/v1/codegen/generate/Wrapper.kt | 11 +- protokt-reflect/api/protokt-reflect.api | 158 ------------------ protokt-reflect/build.gradle.kts | 4 +- 9 files changed, 41 insertions(+), 171 deletions(-) rename extensions/protokt-extensions-lite/src/{main/proto => extensions-proto}/protokt/v1/protokt.proto (100%) diff --git a/extensions/protokt-extensions-lite/build.gradle.kts b/extensions/protokt-extensions-lite/build.gradle.kts index c50a5fae1..cd2c1f05e 100644 --- a/extensions/protokt-extensions-lite/build.gradle.kts +++ b/extensions/protokt-extensions-lite/build.gradle.kts @@ -13,6 +13,7 @@ * limitations under the License. */ +import com.google.protobuf.gradle.proto import protokt.v1.gradle.protokt import protokt.v1.gradle.protoktExtensions @@ -57,6 +58,14 @@ kotlin { } } +sourceSets { + main { + proto { + srcDir("src/extensions-proto") + } + } +} + dependencies { protoktExtensions(project(":extensions:protokt-extensions-simple")) } diff --git a/extensions/protokt-extensions-lite/src/main/proto/protokt/v1/protokt.proto b/extensions/protokt-extensions-lite/src/extensions-proto/protokt/v1/protokt.proto similarity index 100% rename from extensions/protokt-extensions-lite/src/main/proto/protokt/v1/protokt.proto rename to extensions/protokt-extensions-lite/src/extensions-proto/protokt/v1/protokt.proto diff --git a/extensions/protokt-extensions/build.gradle.kts b/extensions/protokt-extensions/build.gradle.kts index a00a3ea3e..597a08397 100644 --- a/extensions/protokt-extensions/build.gradle.kts +++ b/extensions/protokt-extensions/build.gradle.kts @@ -54,6 +54,7 @@ sourceSets { main { proto { srcDir("../protokt-extensions-lite/src/main/proto") + srcDir("../protokt-extensions-lite/src/extensions-proto") } } } diff --git a/protokt-codegen/build.gradle.kts b/protokt-codegen/build.gradle.kts index c354dfb87..157428f04 100644 --- a/protokt-codegen/build.gradle.kts +++ b/protokt-codegen/build.gradle.kts @@ -86,7 +86,7 @@ sourceSets { srcDir("../buildSrc/src/shared/codegen") } proto { - srcDir("../extensions/protokt-extensions-lite/src/main/proto") + srcDir("../extensions/protokt-extensions-lite/src/extensions-proto") } } } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index 9513eb196..f7fc09ad2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -31,7 +31,6 @@ import protokt.v1.UnknownFieldSet import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptRead import protokt.v1.codegen.generate.Wrapper.wrapField -import protokt.v1.codegen.generate.Wrapper.wrapper import protokt.v1.codegen.util.KotlinPlugin import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof @@ -215,7 +214,7 @@ private class DeserializerGenerator( internal fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false): CodeBlock { val read = CodeBlock.of("deserializer.%L", interceptRead(f, f.readFn())) - val wrappedRead = wrapper(f, ctx)?.let { wrapField(it, read) } ?: read + val wrappedRead = wrapField(f, ctx, read) ?: read return when { f.isMap -> deserializeMap(f, read) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index f245d0fd5..4981fab35 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -32,6 +32,7 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.nullable import protokt.v1.codegen.generate.Wrapper.interceptDefaultValue import protokt.v1.codegen.generate.Wrapper.interceptTypeName +import protokt.v1.codegen.generate.Wrapper.wrapField import protokt.v1.codegen.util.DESERIALIZER import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.SizeFn @@ -184,11 +185,24 @@ private class MapEntryGenerator( add("?: %L", keyPropInfo.defaultValue) } add(", value") - if (value.type == FieldType.Message && !valPropInfo.wrapped) { - add("?: %T {}", value.className) - } else if (valPropInfo.nullable || valPropInfo.wrapped) { - // todo: add a test verifying absent message wrapped value type uses the default - add("?: %L", interceptDefaultValue(value, CodeBlock.of("%T {}", value.className), ctx)) + if (valPropInfo.nullable) { + if (valPropInfo.wrapped) { + if (value.type == FieldType.Message) { + add("?: %L", wrapField(value, ctx, CodeBlock.of("%T {}", value.className))) + } else { + add("?: %L", valPropInfo.defaultValue) + } + } else { + if (value.type == FieldType.Message) { + add("?: %T {}", value.className) + } else { + add("?: %L", interceptDefaultValue(value, valPropInfo.defaultValue, ctx)) + } + } + } else { + if (valPropInfo.wrapped) { + add("?: %L", valPropInfo.defaultValue) + } } add(")") } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index d022c007b..528e4b322 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -107,9 +107,6 @@ internal object Wrapper { callConverterMethod(Converter::unwrap, it, accessValue) } ?: accessValue - fun wrapField(wrapName: TypeName, arg: CodeBlock) = - CodeBlock.of("%T.%L(%L)", wrapName, Converter::wrap.name, arg) - private fun callConverterMethod( method: KFunction2<*, *, *>, converterDetails: ConverterDetails, @@ -134,10 +131,16 @@ internal object Wrapper { if (f.type == FieldType.Message && !f.repeated) { defaultValue } else { - wrapper(f, ctx)?.let { wrapField(it, defaultValue) } ?: defaultValue + wrapField(f, ctx, defaultValue) ?: defaultValue } } + fun wrapField(f: StandardField, ctx: Context, argToConverter: CodeBlock) = + wrapper(f, ctx)?.let { wrapField(it, argToConverter) } + + private fun wrapField(wrapName: TypeName, arg: CodeBlock) = + CodeBlock.of("%T.%L(%L)", wrapName, Converter::wrap.name, arg) + fun StandardField.interceptTypeName(ctx: Context) = if (bytesSlice) { BytesSlice::class.asTypeName() diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index a0301b303..05f82f959 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1,119 +1,3 @@ -public final class com/toasttab/protokt/v1/InetSocketAddressProto { - public static fun getDescriptor ()Lcom/google/protobuf/Descriptors$FileDescriptor; - public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistry;)V - public static fun registerAllExtensions (Lcom/google/protobuf/ExtensionRegistryLite;)V -} - -public final class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress : com/google/protobuf/GeneratedMessageV3, com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder { - public static final field ADDRESS_FIELD_NUMBER I - public static final field PORT_FIELD_NUMBER I - public fun equals (Ljava/lang/Object;)Z - public fun getAddress ()Lcom/google/protobuf/ByteString; - public static fun getDefaultInstance ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; - public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; - public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; - public fun getParserForType ()Lcom/google/protobuf/Parser; - public fun getPort ()I - public fun getSerializedSize ()I - public final fun getUnknownFields ()Lcom/google/protobuf/UnknownFieldSet; - public fun hashCode ()I - public final fun isInitialized ()Z - public static fun newBuilder ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public static fun newBuilder (Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun newBuilderForType ()Lcom/google/protobuf/Message$Builder; - public synthetic fun newBuilderForType ()Lcom/google/protobuf/MessageLite$Builder; - public fun newBuilderForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public static fun parseDelimitedFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseDelimitedFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Lcom/google/protobuf/ByteString;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Ljava/io/InputStream;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Ljava/io/InputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Ljava/nio/ByteBuffer;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom (Ljava/nio/ByteBuffer;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom ([B)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parseFrom ([BLcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static fun parser ()Lcom/google/protobuf/Parser; - public synthetic fun toBuilder ()Lcom/google/protobuf/Message$Builder; - public synthetic fun toBuilder ()Lcom/google/protobuf/MessageLite$Builder; - public fun toBuilder ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun writeTo (Lcom/google/protobuf/CodedOutputStream;)V -} - -public final class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder : com/google/protobuf/GeneratedMessageV3$Builder, com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder { - public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; - public fun addRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun build ()Lcom/google/protobuf/Message; - public synthetic fun build ()Lcom/google/protobuf/MessageLite; - public fun build ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public synthetic fun buildPartial ()Lcom/google/protobuf/Message; - public synthetic fun buildPartial ()Lcom/google/protobuf/MessageLite; - public fun buildPartial ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public synthetic fun clear ()Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun clear ()Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun clear ()Lcom/google/protobuf/Message$Builder; - public synthetic fun clear ()Lcom/google/protobuf/MessageLite$Builder; - public fun clear ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun clearAddress ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/google/protobuf/Message$Builder; - public fun clearField (Lcom/google/protobuf/Descriptors$FieldDescriptor;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/google/protobuf/Message$Builder; - public fun clearOneof (Lcom/google/protobuf/Descriptors$OneofDescriptor;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun clearPort ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun clone ()Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun clone ()Lcom/google/protobuf/AbstractMessageLite$Builder; - public synthetic fun clone ()Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun clone ()Lcom/google/protobuf/Message$Builder; - public synthetic fun clone ()Lcom/google/protobuf/MessageLite$Builder; - public fun clone ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun clone ()Ljava/lang/Object; - public fun getAddress ()Lcom/google/protobuf/ByteString; - public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/Message; - public synthetic fun getDefaultInstanceForType ()Lcom/google/protobuf/MessageLite; - public fun getDefaultInstanceForType ()Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress; - public static final fun getDescriptor ()Lcom/google/protobuf/Descriptors$Descriptor; - public fun getDescriptorForType ()Lcom/google/protobuf/Descriptors$Descriptor; - public fun getPort ()I - public final fun isInitialized ()Z - public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/AbstractMessageLite$Builder; - public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/Message$Builder; - public synthetic fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/google/protobuf/MessageLite$Builder; - public fun mergeFrom (Lcom/google/protobuf/CodedInputStream;Lcom/google/protobuf/ExtensionRegistryLite;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/google/protobuf/Message$Builder; - public fun mergeFrom (Lcom/google/protobuf/Message;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun mergeFrom (Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/AbstractMessage$Builder; - public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; - public final fun mergeUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun setAddress (Lcom/google/protobuf/ByteString;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/google/protobuf/Message$Builder; - public fun setField (Lcom/google/protobuf/Descriptors$FieldDescriptor;Ljava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public fun setPort (I)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/google/protobuf/Message$Builder; - public fun setRepeatedField (Lcom/google/protobuf/Descriptors$FieldDescriptor;ILjava/lang/Object;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; - public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/GeneratedMessageV3$Builder; - public synthetic fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/google/protobuf/Message$Builder; - public final fun setUnknownFields (Lcom/google/protobuf/UnknownFieldSet;)Lcom/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddress$Builder; -} - -public abstract interface class com/toasttab/protokt/v1/InetSocketAddressProto$InetSocketAddressOrBuilder : com/google/protobuf/MessageOrBuilder { - public abstract fun getAddress ()Lcom/google/protobuf/ByteString; - public abstract fun getPort ()I -} - public final class com/toasttab/protokt/v1/ProtoktProtos { public static final field CLASS_FIELD_NUMBER I public static final field ENUM_FIELD_NUMBER I @@ -1203,48 +1087,6 @@ public final class protokt/v1/FileOptions$Deserializer : protokt/v1/AbstractKtDe public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/FileOptions; } -public final class protokt/v1/InetSocketAddress : protokt/v1/AbstractKtMessage { - public static final field Deserializer Lprotokt/v1/InetSocketAddress$Deserializer; - public synthetic fun (Lprotokt/v1/Bytes;ILprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun copy (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; - public static fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/InetSocketAddress; - public fun equals (Ljava/lang/Object;)Z - public final fun getAddress ()Lprotokt/v1/Bytes; - public fun getMessageSize ()I - public final fun getPort ()I - public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; - public fun hashCode ()I - public static final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; - public fun serialize (Lprotokt/v1/KtMessageSerializer;)V - public fun toString ()Ljava/lang/String; -} - -public final class protokt/v1/InetSocketAddress$Builder { - public fun ()V - public final fun build ()Lprotokt/v1/InetSocketAddress; - public final fun getAddress ()Lprotokt/v1/Bytes; - public final fun getPort ()I - public final fun getUnknownFields ()Lprotokt/v1/UnknownFieldSet; - public final fun setAddress (Lprotokt/v1/Bytes;)V - public final fun setPort (I)V - public final fun setUnknownFields (Lprotokt/v1/UnknownFieldSet;)V -} - -public final class protokt/v1/InetSocketAddress$Deserializer : protokt/v1/AbstractKtDeserializer { - public fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/InetSocketAddress; - public synthetic fun deserialize (Lprotokt/v1/KtMessageDeserializer;)Lprotokt/v1/KtMessage; - public final fun invoke (Lkotlin/jvm/functions/Function1;)Lprotokt/v1/InetSocketAddress; -} - -public final class protokt/v1/InetSocketAddressProto { - public static final field INSTANCE Lprotokt/v1/InetSocketAddressProto; - public final fun getDescriptor ()Lprotokt/v1/google/protobuf/FileDescriptor; -} - -public final class protokt/v1/Inet_socket_addressKt { - public static final fun getDescriptor (Lprotokt/v1/InetSocketAddress$Deserializer;)Lprotokt/v1/google/protobuf/Descriptor; -} - public final class protokt/v1/MessageOptions : protokt/v1/AbstractKtMessage { public static final field Deserializer Lprotokt/v1/MessageOptions$Deserializer; public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lprotokt/v1/UnknownFieldSet;Lkotlin/jvm/internal/DefaultConstructorMarker;)V diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 41f3e44ad..dcaf46e3e 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -63,7 +63,9 @@ sourceSets { srcDir("../unpublished/src/reflect") } proto { - srcDir("../extensions/protokt-extensions-lite/src/main/proto") + srcDirs( + "../extensions/protokt-extensions-lite/src/extensions-proto" + ) } } } From c78311532273359c17cf4df93b473628eda6197f Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 17:30:09 -0500 Subject: [PATCH 20/38] fix --- .../v1/codegen/AbstractProtoktCodegenTest.kt | 2 +- protokt-reflect/build.gradle.kts | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/AbstractProtoktCodegenTest.kt b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/AbstractProtoktCodegenTest.kt index ab239ffc3..fd5b655be 100644 --- a/protokt-codegen/src/test/kotlin/protokt/v1/codegen/AbstractProtoktCodegenTest.kt +++ b/protokt-codegen/src/test/kotlin/protokt/v1/codegen/AbstractProtoktCodegenTest.kt @@ -121,7 +121,7 @@ private val binGenerator = File(codegenTestingResources.toFile(), "bin-generator") private val extensionsProto = - Path.of("extensions", "protokt-extensions-lite", "src", "main", "proto") + Path.of("extensions", "protokt-extensions-lite", "src", "extensions-proto") private val includeProtos = File(projectRoot, "build/extracted-include-protos/main") diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index dcaf46e3e..21230121b 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -16,21 +16,6 @@ import com.google.protobuf.gradle.proto import protokt.v1.gradle.testProtoktExtensions -/* - * Copyright (c) 2023 Toast, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - plugins { id("protokt.multiplatform-conventions") } From 437909aabb3d485171a563e76e7911c99531c459 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 22:33:38 -0500 Subject: [PATCH 21/38] fix tags in codegen for large field numbers --- .../protokt.spotless-conventions.gradle.kts | 5 +- .../v1/codegen/generate/CodeGenerator.kt | 6 +- .../codegen/generate/DeserializerGenerator.kt | 6 +- .../v1/codegen/generate/MapEntryGenerator.kt | 6 +- .../kotlin/protokt/v1/codegen/util/Types.kt | 5 +- .../protokt/v1/KtMessageDeserializer.kt | 2 +- .../protokt/v1/JsKtMessageDeserializer.kt | 14 +- .../toasttab/protokt/rt/KtGeneratedMessage.kt | 1 + .../protokt/v1/JvmKtMessageDeserializer.kt | 2 +- .../google/protobuf/unittest_import.proto | 49 +++++ .../protobuf/unittest_import_public.proto | 18 ++ .../google/protobuf/unittest_proto3.proto | 206 ++++++++++++++++++ 12 files changed, 296 insertions(+), 24 deletions(-) create mode 100644 testing/interop/src/main/proto/google/protobuf/unittest_import.proto create mode 100644 testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto create mode 100644 testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto diff --git a/buildSrc/src/main/kotlin/protokt.spotless-conventions.gradle.kts b/buildSrc/src/main/kotlin/protokt.spotless-conventions.gradle.kts index 6d9b63102..ee859bda3 100644 --- a/buildSrc/src/main/kotlin/protokt.spotless-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/protokt.spotless-conventions.gradle.kts @@ -78,7 +78,10 @@ allprojects { "examples/protos/src/main/proto/io/grpc/examples/route_guide.proto", "testing/conformance/driver/src/main/proto/conformance/conformance.proto", "testing/conformance/driver/src/main/proto/proto3/test_messages_proto3.proto", - "testing/interop/src/main/proto/tutorial/addressbook.proto" + "testing/interop/src/main/proto/tutorial/addressbook.proto", + "testing/interop/src/main/proto/google/protobuf/unittest_import.proto", + "testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto", + "testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto", ).map(rootProject::file) + "node_modules/**" + "**/build/extracted-include-protos/**" + diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt index a775d7cf2..10a06a04f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/CodeGenerator.kt @@ -35,11 +35,7 @@ object CodeGenerator { fun generate(contents: ProtoFileContents) = contents.types.flatMap { - generate( - it, - Context(emptyList(), contents.info) - ) - .map { type -> GeneratedType(it, type) } + generate(it, Context(emptyList(), contents.info)).map(::GeneratedType) } fun generate(type: TopLevelType, ctx: Context): Iterable = diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index e5d425ffc..08c73b7db 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -83,7 +83,7 @@ private class DeserializerGenerator( beginControlFlow("when (deserializer.readTag())") val constructor = buildCodeBlock { - add("0·->·return·%T(\n", msg.className) + add("0u·->·return·%T(\n", msg.className) withIndent { constructorLines(properties).forEach(::add) } @@ -92,7 +92,7 @@ private class DeserializerGenerator( addStatement("%L", constructor) deserializerInfo.forEach { addStatement( - "%L -> %N = %L", + "%Lu -> %N = %L", it.tag, it.fieldName, it.value @@ -156,7 +156,7 @@ private class DeserializerGenerator( CodeBlock.of("%T.from(unknownFields)", UnknownFieldSet::class) private class DeserializerInfo( - val tag: Int, + val tag: UInt, val fieldName: String, val value: CodeBlock ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index 02fc58d84..e8a2414cd 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -135,11 +135,11 @@ private class MapEntryGenerator( beginControlFlow("when (deserializer.readTag())") addStatement("%L", constructOnZero(value)) addStatement( - "${key.tag.value} -> key = %L", + "${key.tag.value}u -> key = %L", deserialize(key, ctx) ) addStatement( - "${value.tag.value} -> value = %L", + "${value.tag.value}u -> value = %L", deserialize(value, ctx) ) endControlFlow() @@ -170,7 +170,7 @@ private class MapEntryGenerator( private fun constructOnZero(f: StandardField) = buildCodeBlock { - add("0 -> return %T(key, value", msg.className) + add("0u -> return %T(key, value", msg.className) if (f.type == FieldType.Message) { add(" ?: %T{}", value.className) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt index 8a5f1b325..1227248f2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt @@ -166,11 +166,10 @@ class ProtoFileContents( ) class GeneratedType( - val rawType: TopLevelType, val typeSpec: TypeSpec ) -sealed class Tag(val value: Int) : Comparable { +sealed class Tag(val value: UInt) : Comparable { class Packed( number: Int ) : Tag(computeTag(number, 2)) @@ -188,4 +187,4 @@ sealed class Tag(val value: Int) : Comparable { } private fun computeTag(fieldNumber: Int, wireType: Int) = - (fieldNumber shl 3) or wireType + (fieldNumber shl 3).toUInt() or wireType.toUInt() diff --git a/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt b/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt index bde4ab698..47f7357aa 100644 --- a/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt +++ b/protokt-runtime/src/commonMain/kotlin/protokt/v1/KtMessageDeserializer.kt @@ -29,7 +29,7 @@ interface KtMessageDeserializer { fun readSInt64(): Long fun readString(): String fun readUInt64(): ULong - fun readTag(): Int + fun readTag(): UInt fun readUnknown(): UnknownField fun readRepeated(packed: Boolean, acc: KtMessageDeserializer.() -> Unit) fun readMessage(m: KtDeserializer): T diff --git a/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt b/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt index 519f0dc1f..91ff7b642 100644 --- a/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt +++ b/protokt-runtime/src/jsMain/kotlin/protokt/v1/JsKtMessageDeserializer.kt @@ -17,7 +17,7 @@ package protokt.v1 internal fun deserializer(reader: Reader): KtMessageDeserializer { return object : KtMessageDeserializer { - var lastTag = 0 + var lastTag = 0u var endPosition = reader.len override fun readDouble() = @@ -53,14 +53,14 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { override fun readUInt64() = Long.fromProtobufJsLong(reader.uint64()).toULong() - override fun readTag(): Int { + override fun readTag(): UInt { lastTag = if (reader.pos == endPosition) { - 0 + 0u } else { val tag = readInt32() check(tag ushr 3 != 0) { "Invalid tag" } - tag + tag.toUInt() } return lastTag } @@ -73,7 +73,7 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { readBytes().toBytesSlice() override fun readUnknown(): UnknownField { - val fieldNumber = (lastTag ushr 3).toUInt() + val fieldNumber = (lastTag.toInt() ushr 3).toUInt() return when (tagWireType(lastTag)) { 0 -> UnknownField.varint(fieldNumber, readInt64()) @@ -115,5 +115,5 @@ internal fun deserializer(reader: Reader): KtMessageDeserializer { } } -private fun tagWireType(tag: Int) = - tag and ((1 shl 3) - 1) +private fun tagWireType(tag: UInt) = + tag.toInt() and ((1 shl 3) - 1) diff --git a/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt b/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt index 2a6c27b72..35edb64bc 100644 --- a/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt +++ b/protokt-runtime/src/jvmMain/kotlin/com/toasttab/protokt/rt/KtGeneratedMessage.kt @@ -15,6 +15,7 @@ package com.toasttab.protokt.rt +@Deprecated("use v1") @Target(AnnotationTarget.CLASS) annotation class KtGeneratedMessage( /** diff --git a/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt b/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt index 98bf6931f..a42e0632a 100644 --- a/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt +++ b/protokt-runtime/src/jvmMain/kotlin/protokt/v1/JvmKtMessageDeserializer.kt @@ -58,7 +58,7 @@ internal fun deserializer( stream.readUInt64().toULong() override fun readTag() = - stream.readTag() + stream.readTag().toUInt() override fun readBytes() = Bytes(stream.readByteArray()) diff --git a/testing/interop/src/main/proto/google/protobuf/unittest_import.proto b/testing/interop/src/main/proto/google/protobuf/unittest_import.proto new file mode 100644 index 000000000..23fa9a8f3 --- /dev/null +++ b/testing/interop/src/main/proto/google/protobuf/unittest_import.proto @@ -0,0 +1,49 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// A proto file which is imported by unittest.proto to test importing. + +syntax = "proto2"; + +// We don't put this in a package within proto2 because we need to make sure +// that the generated code doesn't depend on being in the proto2 namespace. +// In test_util.h we do +// "using namespace unittest_import = protobuf_unittest_import". +package protobuf_unittest_import; + +option optimize_for = SPEED; +option cc_enable_arenas = true; + +// Exercise the java_package option. +option java_package = "com.google.protobuf.test"; + +// Do not set a java_outer_classname here to verify that Proto2 works without +// one. + +// Test public import +import public "google/protobuf/unittest_import_public.proto"; + +message ImportMessage { + optional int32 d = 1; +} + +enum ImportEnum { + IMPORT_FOO = 7; + IMPORT_BAR = 8; + IMPORT_BAZ = 9; +} + +// To use an enum in a map, it must has the first value as 0. +enum ImportEnumForMap { + UNKNOWN = 0; + FOO = 1; + BAR = 2; +} diff --git a/testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto b/testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto new file mode 100644 index 000000000..ff428143f --- /dev/null +++ b/testing/interop/src/main/proto/google/protobuf/unittest_import_public.proto @@ -0,0 +1,18 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +// Author: liujisi@google.com (Pherl Liu) + +syntax = "proto2"; + +package protobuf_unittest_import; + +option java_package = "com.google.protobuf.test"; + +message PublicImportMessage { + optional int32 e = 1; +} diff --git a/testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto b/testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto new file mode 100644 index 000000000..46bc10221 --- /dev/null +++ b/testing/interop/src/main/proto/google/protobuf/unittest_proto3.proto @@ -0,0 +1,206 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto3"; + +package proto3_unittest; + +import "google/protobuf/unittest_import.proto"; + +option optimize_for = SPEED; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + optional NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype = STRING_PIECE]; + string optional_cord = 25 [ctype = CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage optional_public_import_message = + 26; + + NestedMessage optional_lazy_message = 27 [lazy = true]; + NestedMessage optional_unverified_lazy_message = 28 [unverified_lazy = true]; + protobuf_unittest_import.ImportMessage optional_lazy_import_message = 115 + [lazy = true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; + repeated string repeated_cord = 55 [ctype = CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy = true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recursively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage {} + +// TestMessageWithDummy is also used to test behavior of unknown fields. +message TestMessageWithDummy { + // This field is only here for triggering copy-on-write; it's not intended to + // be serialized. + bool dummy = 536870911; +} + +// Same layout as TestOneof2 in unittest.proto to test unknown enum value +// parsing behavior in oneof. +message TestOneof2 { + oneof foo { + NestedEnum foo_enum = 6; + } + + enum NestedEnum { + UNKNOWN = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + } +} From d1a4417415b5ff3ef62567eb32087d47f734e44b Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 22:37:50 -0500 Subject: [PATCH 22/38] api dump --- protokt-runtime/api/protokt-runtime.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protokt-runtime/api/protokt-runtime.api b/protokt-runtime/api/protokt-runtime.api index 39144b2b0..072746778 100644 --- a/protokt-runtime/api/protokt-runtime.api +++ b/protokt-runtime/api/protokt-runtime.api @@ -595,7 +595,7 @@ public abstract interface class protokt/v1/KtMessageDeserializer { public abstract fun readSInt32 ()I public abstract fun readSInt64 ()J public abstract fun readString ()Ljava/lang/String; - public abstract fun readTag ()I + public abstract fun readTag-pVg5ArA ()I public fun readUInt32-pVg5ArA ()I public abstract fun readUInt64-s-VKNKU ()J public abstract fun readUnknown ()Lprotokt/v1/UnknownField; From d357e38ee94975d32055caba954a3e8513fd92e8 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 23:46:47 -0500 Subject: [PATCH 23/38] change strategy for sharing potentially unpublished code --- buildSrc/build.gradle.kts | 9 +++++++ buildSrc/src/main/kotlin/LocalProtoktBuild.kt | 7 ----- examples/grpc-java-lite/build.gradle.kts | 3 +-- examples/grpc-kotlin-lite/build.gradle.kts | 2 +- .../jvm-lite/build.gradle.kts | 3 ++- protokt-codegen/build.gradle.kts | 8 +++--- protokt-gradle-plugin/build.gradle.kts | 12 ++++++--- protokt-util/build.gradle.kts | 27 ------------------- settings.gradle.kts | 1 - .../protokt/v1/gradle/ProtoktExtension.kt | 0 .../protobuf/gradle/GenerateProtoTaskExt.kt | 0 .../protokt/v1/gradle/DslExtensions.kt | 0 .../protokt/v1/gradle/ProtobufBuild.kt | 0 .../protokt/v1/gradle/ProtoktBuild.kt | 2 +- .../protokt/v1/util/ProtoktExtentions.kt | 0 testing/options/build.gradle.kts | 8 ++++++ .../v1/testing}/ProtoktExtensionsTest.kt | 3 ++- testing/plugin-options/lite/build.gradle.kts | 9 ++++++- .../build.gradle.kts | 13 ++++----- 19 files changed, 50 insertions(+), 57 deletions(-) delete mode 100644 protokt-util/build.gradle.kts rename {buildSrc/src/main/kotlin => shared-src/codegen}/protokt/v1/gradle/ProtoktExtension.kt (100%) rename {buildSrc/src/main/kotlin => shared-src/gradle-plugin}/com/google/protobuf/gradle/GenerateProtoTaskExt.kt (100%) rename {buildSrc/src/main/kotlin => shared-src/gradle-plugin}/protokt/v1/gradle/DslExtensions.kt (100%) rename {buildSrc/src/main/kotlin => shared-src/gradle-plugin}/protokt/v1/gradle/ProtobufBuild.kt (100%) rename {buildSrc/src/main/kotlin => shared-src/gradle-plugin}/protokt/v1/gradle/ProtoktBuild.kt (98%) rename {protokt-util/src/main/kotlin => shared-src/lite-util}/protokt/v1/util/ProtoktExtentions.kt (100%) rename {protokt-util/src/test/kotlin/protokt/v1/util => testing/options/src/test/kotlin/protokt/v1/testing}/ProtoktExtensionsTest.kt (91%) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 2df41b5e4..ebbe78e35 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -42,3 +42,12 @@ dependencies { implementation(kotlin("gradle-plugin-api")) implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) } + +sourceSets { + main { + java { + srcDir("../shared-src/codegen") + srcDir("../shared-src/gradle-plugin") + } + } +} diff --git a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt index e77dcc141..00606bb31 100644 --- a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt +++ b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt @@ -37,13 +37,6 @@ fun Project.localProtokt() { } } -fun Project.includeBuildSrc(vararg filePatterns: String) { - the()["main"].java { - srcDir(rootProject.file("buildSrc/src/main/kotlin")) - filePatterns.forEach { include(it) } - } -} - fun Project.pureKotlin() { tasks.withType { enabled = false diff --git a/examples/grpc-java-lite/build.gradle.kts b/examples/grpc-java-lite/build.gradle.kts index 5f8edc3f1..9fe2ace8f 100644 --- a/examples/grpc-java-lite/build.gradle.kts +++ b/examples/grpc-java-lite/build.gradle.kts @@ -36,8 +36,6 @@ dependencies { implementation(libs.jackson) runtimeOnly(libs.protobuf.lite) - - testImplementation(project(":protokt-util")) } sourceSets { @@ -51,6 +49,7 @@ sourceSets { test { java { srcDir(liteOptionTestSourceDir()) + srcDir(rootProject.file("shared-src/lite-util")) } } } diff --git a/examples/grpc-kotlin-lite/build.gradle.kts b/examples/grpc-kotlin-lite/build.gradle.kts index a1b1c9082..6ecff9edc 100644 --- a/examples/grpc-kotlin-lite/build.gradle.kts +++ b/examples/grpc-kotlin-lite/build.gradle.kts @@ -43,7 +43,6 @@ dependencies { testImplementation(kotlin("test-junit")) testImplementation(libs.grpc.testing) - testImplementation(project(":protokt-util")) } sourceSets { @@ -60,6 +59,7 @@ sourceSets { java { srcDir("../grpc-kotlin/src/test/kotlin") srcDir(liteOptionTestSourceDir()) + srcDir(rootProject.file("shared-src/lite-util")) } } } diff --git a/gradle-plugin-integration-test/jvm-lite/build.gradle.kts b/gradle-plugin-integration-test/jvm-lite/build.gradle.kts index 62468f4a9..fe44ee602 100644 --- a/gradle-plugin-integration-test/jvm-lite/build.gradle.kts +++ b/gradle-plugin-integration-test/jvm-lite/build.gradle.kts @@ -36,7 +36,6 @@ dependencies { testImplementation(kotlin("test-junit5")) testImplementation(libs.junit.jupiter) testImplementation(libs.protobuf.java) - testImplementation("com.toasttab.protokt:protokt-util:$version") } sourceSets { @@ -53,6 +52,8 @@ sourceSets { check(file(lite).exists()) srcDir(common) srcDir(lite) + + srcDir(rootProject.file("../shared-src/lite-util")) } } } diff --git a/protokt-codegen/build.gradle.kts b/protokt-codegen/build.gradle.kts index c0a05eaef..bc03fa576 100644 --- a/protokt-codegen/build.gradle.kts +++ b/protokt-codegen/build.gradle.kts @@ -81,6 +81,9 @@ tasks.withType { sourceSets { main { + java { + srcDir("../shared-src/codegen") + } proto { srcDir("../extensions/protokt-extensions-lite/src/main/proto") } @@ -93,8 +96,3 @@ buildConfig { buildConfigField("String", "DEFAULT_PROTOBUF_VERSION", "\"${libs.versions.protobuf.java.get()}\"") buildConfigField("String", "PROTOKT_VERSION", "\"$version\"") } - -includeBuildSrc( - "protokt/v1/gradle/ProtoktExtension.kt", - "**/*.java" // don't override the protobuf-gradle-plugin; todo: fix this function to not need this -) diff --git a/protokt-gradle-plugin/build.gradle.kts b/protokt-gradle-plugin/build.gradle.kts index 84141b5a4..b536bf39e 100644 --- a/protokt-gradle-plugin/build.gradle.kts +++ b/protokt-gradle-plugin/build.gradle.kts @@ -61,10 +61,14 @@ dependencies { implementation(libs.protobuf.gradlePlugin) } -includeBuildSrc( - "protokt/v1/gradle/*", - "com/google/protobuf/gradle/*" -) +sourceSets { + main { + java { + srcDir(rootProject.file("shared-src/codegen")) + srcDir(rootProject.file("shared-src/gradle-plugin")) + } + } +} buildConfig { useKotlinOutput { topLevelConstants = true } diff --git a/protokt-util/build.gradle.kts b/protokt-util/build.gradle.kts deleted file mode 100644 index 98f9db1fb..000000000 --- a/protokt-util/build.gradle.kts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2020 Toast, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -plugins { - id("protokt.jvm-conventions") -} - -// used by integration testing project -enablePublishing() - -includeBuildSrc("ProtoktExtension.kt") - -dependencies { - testImplementation(project(":extensions:protokt-extensions")) -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 220efaff0..6383ecd6a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,7 +35,6 @@ include( "protokt-runtime-grpc", "protokt-runtime-grpc-lite", "protokt-gradle-plugin", - "protokt-util", "grpc-kotlin-shim", diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktExtension.kt b/shared-src/codegen/protokt/v1/gradle/ProtoktExtension.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktExtension.kt rename to shared-src/codegen/protokt/v1/gradle/ProtoktExtension.kt diff --git a/buildSrc/src/main/kotlin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt b/shared-src/gradle-plugin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt similarity index 100% rename from buildSrc/src/main/kotlin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt rename to shared-src/gradle-plugin/com/google/protobuf/gradle/GenerateProtoTaskExt.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/DslExtensions.kt b/shared-src/gradle-plugin/protokt/v1/gradle/DslExtensions.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/DslExtensions.kt rename to shared-src/gradle-plugin/protokt/v1/gradle/DslExtensions.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt b/shared-src/gradle-plugin/protokt/v1/gradle/ProtobufBuild.kt similarity index 100% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtobufBuild.kt rename to shared-src/gradle-plugin/protokt/v1/gradle/ProtobufBuild.kt diff --git a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt b/shared-src/gradle-plugin/protokt/v1/gradle/ProtoktBuild.kt similarity index 98% rename from buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt rename to shared-src/gradle-plugin/protokt/v1/gradle/ProtoktBuild.kt index 1d27c00c0..c80abf41b 100644 --- a/buildSrc/src/main/kotlin/protokt/v1/gradle/ProtoktBuild.kt +++ b/shared-src/gradle-plugin/protokt/v1/gradle/ProtoktBuild.kt @@ -48,7 +48,7 @@ const val EXTENSIONS = "protoktExtensions" const val TEST_EXTENSIONS = "testProtoktExtensions" -fun configureProtokt(project: Project, protoktVersion: Any?, resolveBinary: () -> String) { +internal fun configureProtokt(project: Project, protoktVersion: Any?, resolveBinary: () -> String) { injectKotlinPluginsIntoProtobufGradle() val ext = project.extensions.create("protokt") configureProtobufPlugin(project, ext, resolveBinary()) diff --git a/protokt-util/src/main/kotlin/protokt/v1/util/ProtoktExtentions.kt b/shared-src/lite-util/protokt/v1/util/ProtoktExtentions.kt similarity index 100% rename from protokt-util/src/main/kotlin/protokt/v1/util/ProtoktExtentions.kt rename to shared-src/lite-util/protokt/v1/util/ProtoktExtentions.kt diff --git a/testing/options/build.gradle.kts b/testing/options/build.gradle.kts index bc7c1f1ea..2b265b5d8 100644 --- a/testing/options/build.gradle.kts +++ b/testing/options/build.gradle.kts @@ -41,3 +41,11 @@ dependencies { testRuntimeOnly(libs.protobuf.java) } + +sourceSets { + test { + java { + srcDir(rootProject.file("shared-src/lite-util")) + } + } +} diff --git a/protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt similarity index 91% rename from protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt rename to testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt index 9b26a142a..2fbe045b8 100644 --- a/protokt-util/src/test/kotlin/protokt/v1/util/ProtoktExtensionsTest.kt +++ b/testing/options/src/test/kotlin/protokt/v1/testing/ProtoktExtensionsTest.kt @@ -13,11 +13,12 @@ * limitations under the License. */ -package protokt.v1.util +package protokt.v1.testing import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test import protokt.v1.ProtoktProtos +import protokt.v1.util.PROTOKT_EXTENSIONS_CLASS_NAME class ProtoktExtensionsTest { @Test diff --git a/testing/plugin-options/lite/build.gradle.kts b/testing/plugin-options/lite/build.gradle.kts index 55070de8f..31091c896 100644 --- a/testing/plugin-options/lite/build.gradle.kts +++ b/testing/plugin-options/lite/build.gradle.kts @@ -33,7 +33,14 @@ dependencies { protoktExtensions(project(":third-party:proto-google-common-protos-extensions-lite")) testImplementation(kotlin("reflect")) - testImplementation(project(":protokt-util")) testRuntimeOnly(libs.protobuf.lite) } + +sourceSets { + test { + java { + srcDir(rootProject.file("shared-src/lite-util")) + } + } +} diff --git a/third-party/proto-google-common-protos-lite/build.gradle.kts b/third-party/proto-google-common-protos-lite/build.gradle.kts index 9dfb70b93..2ff51344b 100644 --- a/third-party/proto-google-common-protos-lite/build.gradle.kts +++ b/third-party/proto-google-common-protos-lite/build.gradle.kts @@ -41,13 +41,14 @@ kotlin { implementation(kotlin("test")) } } + } +} - val jvmTest by getting { - dependencies { - implementation(project(":protokt-util")) - } +sourceSets { + test { + java { + srcDir(liteOptionTestSourceDir()) + srcDir(rootProject.file("shared-src/lite-util")) } - - jvmTest.kotlin.srcDir(liteOptionTestSourceDir()) } } From e2e0379219a27d22356d9ed4b6ede8b077390bb0 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 3 Jan 2024 23:52:02 -0500 Subject: [PATCH 24/38] lint --- buildSrc/src/main/kotlin/LocalProtoktBuild.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt index 00606bb31..fbe211ddd 100644 --- a/buildSrc/src/main/kotlin/LocalProtoktBuild.kt +++ b/buildSrc/src/main/kotlin/LocalProtoktBuild.kt @@ -15,10 +15,8 @@ import com.google.protobuf.gradle.GenerateProtoTask import org.gradle.api.Project -import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.compile.JavaCompile import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.the import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl import protokt.v1.gradle.CODEGEN_NAME From 33206b3f5bd1b9016f516c82afa3f45917135c38 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Fri, 5 Jan 2024 00:06:51 -0500 Subject: [PATCH 25/38] fix map wrapper types for well known wrappers --- .../v1/codegen/generate/BuilderGenerator.kt | 4 +- .../codegen/generate/DeserializerGenerator.kt | 23 +---- .../codegen/generate/DeserializerSupport.kt | 7 +- .../protokt/v1/codegen/generate/Implements.kt | 3 +- .../v1/codegen/generate/KotlinPoetUtil.kt | 13 +-- .../v1/codegen/generate/MapEntryGenerator.kt | 77 +++++++++++----- .../v1/codegen/generate/MessageGenerator.kt | 44 +++++---- .../codegen/generate/MessageSizeGenerator.kt | 27 +----- .../v1/codegen/generate/OneofGenerator.kt | 10 +- .../v1/codegen/generate/PropertyAnnotator.kt | 37 +++----- .../codegen/generate/SerializerGenerator.kt | 30 ++---- .../v1/codegen/generate/WellKnownTypes.kt | 11 +-- .../protokt/v1/codegen/generate/Wrapper.kt | 86 +++++++---------- .../protokt/v1/codegen/util/ClassLookup.kt | 56 ++++++----- .../protokt/v1/codegen/util/ClassNames.kt | 22 +++++ .../protokt/v1/codegen/util/FieldParser.kt | 92 ++++++++----------- .../protokt/v1/codegen/util/FieldType.kt | 25 +++++ .../v1/codegen/util/FileContentParser.kt | 2 +- .../util/GrpcKotlinGeneratorSupport.kt | 2 +- .../protokt/v1/codegen/util/MessageParser.kt | 8 +- .../v1/codegen/util/PackageResolution.kt | 37 +++++--- .../protokt/v1/codegen/util/ServiceParser.kt | 5 +- .../kotlin/protokt/v1/codegen/util/Types.kt | 18 ++-- .../proto/protokt/v1/testing/wkt_test.proto | 4 + .../protokt/v1/testing/WellKnownTypesTest.kt | 2 + 25 files changed, 321 insertions(+), 324 deletions(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt index 2b0785225..b5fb53b40 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/BuilderGenerator.kt @@ -70,7 +70,7 @@ private class BuilderGenerator( .mutable(true) .handleDeprecation(it.deprecation) .apply { - if (it.map) { + if (it.isMap) { setter( FunSpec.setterBuilder() .addParameter("newValue", Map::class) @@ -88,7 +88,7 @@ private class BuilderGenerator( } .initializer( when { - it.map -> CodeBlock.of("emptyMap()") + it.isMap -> CodeBlock.of("emptyMap()") it.repeated -> CodeBlock.of("emptyList()") it.fieldType == FieldType.Message || it.wrapped || it.nullable -> CodeBlock.of("null") else -> it.defaultValue diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt index 08c73b7db..b6a1b3a57 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerGenerator.kt @@ -30,10 +30,7 @@ import protokt.v1.KtMessageDeserializer import protokt.v1.UnknownFieldSet import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptRead -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.generate.Wrapper.wrapField -import protokt.v1.codegen.generate.Wrapper.wrapper import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.FieldType.Enum import protokt.v1.codegen.util.FieldType.SFixed32 @@ -142,7 +139,7 @@ private class DeserializerGenerator( } private fun deserializeType(p: PropertyInfo) = - if (p.repeated || p.map) { + if (p.repeated || p.isMap) { p.deserializeType as ParameterizedTypeName ClassName(p.deserializeType.rawType.packageName, "Mutable" + p.deserializeType.rawType.simpleName) .parameterizedBy(p.deserializeType.typeArguments) @@ -217,10 +214,10 @@ private class DeserializerGenerator( fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false): CodeBlock { val read = CodeBlock.of("deserializer.%L", interceptRead(f, f.readFn())) - val wrappedRead = wrapper(f, ctx)?.let { wrapField(it, read) } ?: read + val wrappedRead = wrapField(f, ctx, read) ?: read return when { - f.map -> deserializeMap(f, ctx, read) + f.isMap -> deserializeMap(f, read) f.repeated -> buildCodeBlock { add("\n(%N ?: mutableListOf())", f.fieldName) @@ -234,24 +231,14 @@ fun deserialize(f: StandardField, ctx: Context, packed: Boolean = false): CodeBl } } -private fun deserializeMap(f: StandardField, ctx: Context, read: CodeBlock): CodeBlock { - val key = - mapKeyConverter(f, ctx) - ?.let { wrapField(it, CodeBlock.of("it.key")) } - ?: CodeBlock.of("it.key") - - val value = - mapValueConverter(f, ctx) - ?.let { wrapField(it, CodeBlock.of("it.value")) } - ?: CodeBlock.of("it.value") - +private fun deserializeMap(f: StandardField, read: CodeBlock): CodeBlock { return buildCodeBlock { add("\n(%N ?: mutableMapOf())", f.fieldName) beginControlFlow(".apply") beginControlFlow("deserializer.readRepeated(false)") add(read) beginControlFlow(".let") - add("put(%L, %L)\n", key, value) + add("put(%L, %L)\n", CodeBlock.of("it.key"), CodeBlock.of("it.value")) endControlFlow() endControlFlow() endControlFlowWithoutNewline() diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt index 4ed4651aa..09da0cfe5 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/DeserializerSupport.kt @@ -21,10 +21,7 @@ import com.squareup.kotlinpoet.withIndent import protokt.v1.codegen.util.FieldType fun deserializeVarInitialState(p: PropertyInfo) = - if ( - (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) && - !p.mapEntry - ) { + if (p.repeated || p.wrapped || p.nullable || p.fieldType == FieldType.Message) { CodeBlock.of("null") } else { p.defaultValue @@ -48,7 +45,7 @@ fun wrapDeserializedValueForConstructor(p: PropertyInfo) = endControlFlowWithoutNewline() } } else { - if (p.map) { + if (p.isMap) { CodeBlock.of("%M(%N)", unmodifiableMap, p.name) } else if (p.repeated) { CodeBlock.of("%M(%N)", unmodifiableList, p.name) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt index 23fe0331b..4d14b33b2 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Implements.kt @@ -27,7 +27,7 @@ object Implements { msg: Message ) = msg.superInterface(ctx) - ?.let { fieldName in ctx.info.context.classLookup.properties(it) } + ?.let { fieldName in ctx.info.context.classLookup.properties(it.canonicalName) } ?: false fun TypeSpec.Builder.handleSuperInterface(implements: ClassName?, v: OneofGeneratorInfo? = null) = @@ -46,7 +46,6 @@ object Implements { if (msg.options.protokt.implements.isNotEmpty()) { if (msg.options.protokt.implements.delegates()) { addSuperinterface( - // TODO: parameterize this by the ctx package? ClassName.bestGuess(msg.options.protokt.implements.substringBefore(" by ")), msg.options.protokt.implements.substringAfter(" by ") ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt index f8419e90f..c266eea15 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/KotlinPoetUtil.kt @@ -26,6 +26,7 @@ import com.squareup.kotlinpoet.asTypeName import protokt.v1.Collections import protokt.v1.SizeCodecs import protokt.v1.codegen.generate.CodeGenerator.Context +import protokt.v1.codegen.util.inferClassName import kotlin.reflect.KClass import kotlin.reflect.KFunction1 @@ -85,14 +86,6 @@ fun CodeBlock.Builder.endControlFlowWithoutNewline() { add("}") } -fun inferClassName(className: String, ctx: Context) = +internal fun inferClassName(className: String, ctx: Context) = inferClassName(className, ctx.info.kotlinPackage) - -fun inferClassName(className: String, pkg: String): ClassName { - val inferred = ClassName.bestGuess(className) - return if (inferred.packageName == "") { - ClassName(pkg, className.split(".")) - } else { - inferred - } -} + .let { (pkg, names) -> ClassName(pkg, names) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt index e8a2414cd..3d9ac9466 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MapEntryGenerator.kt @@ -29,14 +29,16 @@ import protokt.v1.KtMessage import protokt.v1.KtMessageDeserializer import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context +import protokt.v1.codegen.generate.Wrapper.interceptDefaultValue +import protokt.v1.codegen.generate.Wrapper.interceptTypeName +import protokt.v1.codegen.generate.Wrapper.wrapField import protokt.v1.codegen.util.DESERIALIZER import protokt.v1.codegen.util.FieldType -import protokt.v1.codegen.util.MapEntry import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.StandardField import kotlin.reflect.KProperty0 -fun generateMapEntry(msg: Message, ctx: Context) = +internal fun generateMapEntry(msg: Message, ctx: Context) = MapEntryGenerator(msg, ctx).generate() private class MapEntryGenerator( @@ -46,8 +48,15 @@ private class MapEntryGenerator( private val key = msg.fields[0] as StandardField private val value = msg.fields[1] as StandardField - private val keyProp = constructorProperty("key", key.className, false) - private val valProp = constructorProperty("value", value.className, false) + private val keyTypeName = key.interceptTypeName(ctx) + private val valueTypeName = value.interceptTypeName(ctx) + + private val keyProp = constructorProperty("key", keyTypeName, false) + private val valProp = constructorProperty("value", valueTypeName, false) + + private val propInfo = annotateProperties(msg, ctx) + private val keyPropInfo = propInfo[0] + private val valPropInfo = propInfo[1] fun generate() = TypeSpec.classBuilder(msg.className).apply { @@ -64,8 +73,8 @@ private class MapEntryGenerator( private fun TypeSpec.Builder.addConstructor() { primaryConstructor( FunSpec.constructorBuilder() - .addParameter("key", key.className) - .addParameter("value", value.className) + .addParameter("key", keyTypeName) + .addParameter("value", valueTypeName) .build() ) } @@ -79,7 +88,8 @@ private class MapEntryGenerator( .addCode( "return·%L", sizeOfCall( - MapEntry(key, value), + key, + value, CodeBlock.of("key"), CodeBlock.of("value") ) @@ -102,8 +112,6 @@ private class MapEntryGenerator( } private fun TypeSpec.Builder.addDeserializer() { - val propInfo = annotateProperties(msg, ctx) - addType( TypeSpec.companionObjectBuilder(DESERIALIZER) .superclass( @@ -115,10 +123,10 @@ private class MapEntryGenerator( buildFunSpec("entrySize") { returns(Int::class) if (key.type.sizeFn is FieldType.Method) { - addParameter("key", key.className) + addParameter("key", keyTypeName) } if (value.type.sizeFn is FieldType.Method) { - addParameter("value", value.className) + addParameter("value", valueTypeName) } addStatement("return %L + %L", sizeOf(key, ctx), sizeOf(value, ctx)) } @@ -128,12 +136,12 @@ private class MapEntryGenerator( addModifiers(KModifier.OVERRIDE) addParameter("deserializer", KtMessageDeserializer::class) returns(msg.className) - addStatement("%L", deserializeVar(propInfo, ::key)) - addStatement("%L", deserializeVar(propInfo, ::value)) + addStatement("%L", deserializeVar(keyPropInfo, ::key)) + addStatement("%L", deserializeVar(valPropInfo, ::value)) addCode("\n") beginControlFlow("while (true)") beginControlFlow("when (deserializer.readTag())") - addStatement("%L", constructOnZero(value)) + addStatement("%L", constructOnZero()) addStatement( "${key.tag.value}u -> key = %L", deserialize(key, ctx) @@ -150,13 +158,12 @@ private class MapEntryGenerator( ) } - private fun deserializeVar(propInfo: List, accessor: KProperty0): CodeBlock { + private fun deserializeVar(prop: PropertyInfo, accessor: KProperty0): CodeBlock { val field = accessor.get() - val prop = propInfo.single { it.name == field.fieldName } return namedCodeBlock( "var ${accessor.name}" + - if (field.type == FieldType.Message) { + if (field.type == FieldType.Message || prop.wrapped || prop.nullable) { ": %type:T" } else { "" @@ -168,25 +175,45 @@ private class MapEntryGenerator( ) } - private fun constructOnZero(f: StandardField) = + private fun constructOnZero() = buildCodeBlock { - add("0u -> return %T(key, value", msg.className) - if (f.type == FieldType.Message) { - add(" ?: %T{}", value.className) + add("0u -> return %T(key", msg.className) + if (keyPropInfo.nullable || keyPropInfo.wrapped) { + add("?: %L", keyPropInfo.defaultValue) + } + add(", value") + if (valPropInfo.nullable) { + if (valPropInfo.wrapped) { + if (value.type == FieldType.Message) { + add("?: %L", wrapField(value, ctx, CodeBlock.of("%T {}", value.className))) + } else { + add("?: %L", valPropInfo.defaultValue) + } + } else { + if (value.type == FieldType.Message) { + add("?: %T {}", value.className) + } else { + add("?: %L", interceptDefaultValue(value, valPropInfo.defaultValue, ctx)) + } + } + } else { + if (valPropInfo.wrapped) { + add("?: %L", valPropInfo.defaultValue) + } } add(")") } } -fun sizeOfCall(mapEntry: MapEntry, keyStr: CodeBlock, valueStr: CodeBlock) = - if (mapEntry.key.type.sizeFn is FieldType.Method) { - if (mapEntry.value.type.sizeFn is FieldType.Method) { +internal fun sizeOfCall(key: StandardField, value: StandardField, keyStr: CodeBlock, valueStr: CodeBlock) = + if (key.type.sizeFn is FieldType.Method) { + if (value.type.sizeFn is FieldType.Method) { CodeBlock.of("entrySize(%L,·%L)", keyStr, valueStr) } else { CodeBlock.of("entrySize(%L)", keyStr) } } else { - if (mapEntry.value.type.sizeFn is FieldType.Method) { + if (value.type.sizeFn is FieldType.Method) { CodeBlock.of("entrySize(%L)", valueStr) } else { CodeBlock.of("entrySize()") diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt index a38fdf9c7..33a526914 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageGenerator.kt @@ -45,29 +45,27 @@ private class MessageGenerator( private val msg: Message, private val ctx: Context ) { - fun generate() = - if (msg.mapEntry) { - generateMapEntry(msg, ctx) - } else { - val properties = annotateProperties(msg, ctx) - val propertySpecs = properties(properties) - - TypeSpec.classBuilder(msg.className).apply { - annotateMessageDocumentation(ctx)?.let { addKdoc(formatDoc(it)) } - handleAnnotations() - handleConstructor(propertySpecs) - addTypes(annotateOneofs(msg, ctx)) - handleMessageSize() - addFunction(generateMessageSize(msg, propertySpecs, ctx)) - addFunction(generateSerializer(msg, propertySpecs, ctx)) - handleEquals(properties) - handleHashCode(properties) - handleToString(properties) - handleBuilder(msg, properties) - addType(generateDeserializer(msg, ctx, properties)) - addTypes(msg.nestedTypes.flatMap { generate(it, ctx) }) - }.build() - } + fun generate(): TypeSpec { + val properties = annotateProperties(msg, ctx) + val propertySpecs = properties(properties) + + return TypeSpec.classBuilder(msg.className).apply { + annotateMessageDocumentation(ctx)?.let { addKdoc(formatDoc(it)) } + handleAnnotations() + handleConstructor(propertySpecs) + addTypes(annotateOneofs(msg, ctx)) + handleMessageSize() + addFunction(generateMessageSize(msg, propertySpecs, ctx)) + addFunction(generateSerializer(msg, propertySpecs, ctx)) + handleEquals(properties) + handleHashCode(properties) + handleToString(properties) + handleBuilder(msg, properties) + addType(generateDeserializer(msg, ctx, properties)) + addTypes(properties.mapNotNull { it.mapEntry }.map { generateMapEntry(it, ctx) }) + addTypes(msg.nestedTypes.filterNot { it is Message && it.mapEntry }.flatMap { generate(it, ctx) }) + }.build() + } private fun TypeSpec.Builder.handleAnnotations() = apply { addAnnotation( diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt index 6cad639d6..d1533f368 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/MessageSizeGenerator.kt @@ -25,8 +25,6 @@ import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.Wrapper.interceptFieldSizeof import protokt.v1.codegen.generate.Wrapper.interceptSizeof import protokt.v1.codegen.generate.Wrapper.interceptValueAccess -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof @@ -114,7 +112,7 @@ fun sizeOf( } return when { - f.map -> sizeOfMap(f, fieldAccess, ctx) + f.isMap -> sizeOfMap(f, fieldAccess) f.repeated && f.packed -> { namedCodeBlock( "sizeOf(${f.tag}u) + " + @@ -151,30 +149,15 @@ fun sizeOf( } } -private fun sizeOfMap( - f: StandardField, - name: CodeBlock, - ctx: Context -): CodeBlock { - val key = - mapKeyConverter(f, ctx) - ?.let { CodeBlock.of("%T.unwrap(k)", it) } - ?: CodeBlock.of("k") - - val value = - mapValueConverter(f, ctx) - ?.let { CodeBlock.of("%T.unwrap(v)", it) } - ?: CodeBlock.of("v") - - val mapEntry = f.mapEntry!! - val sizeOfCall = sizeOfCall(mapEntry, key, value) +private fun sizeOfMap(f: StandardField, name: CodeBlock): CodeBlock { + val sizeOfCall = sizeOfCall(f.mapKey, f.mapValue, CodeBlock.of("k"), CodeBlock.of("v")) return buildCodeBlock { add( "%M($name, ${f.tag}u)·{·%L,·%L·->\n", sizeOf, - mapEntry.key.loopVar("k"), - mapEntry.value.loopVar("v") + f.mapKey.loopVar("k"), + f.mapValue.loopVar("v") ) indent() add("%T.%L\n", f.className, sizeOfCall) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt index cd8ce5af4..f944c83f8 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/OneofGenerator.kt @@ -26,7 +26,6 @@ import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Deprecation.renderOptions import protokt.v1.codegen.generate.Implements.handleSuperInterface import protokt.v1.codegen.generate.Wrapper.interceptTypeName -import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField @@ -44,7 +43,7 @@ private class OneofGenerator( val implements = oneof.options.protokt.implements .takeIf { it.isNotEmpty() } - ?.let { inferClassName(it, ctx.info.kotlinPackage) } + ?.let { inferClassName(it, ctx) } TypeSpec.classBuilder(oneof.name) .addModifiers(KModifier.SEALED) @@ -103,12 +102,7 @@ private class OneofGenerator( OneofGeneratorInfo( fieldName = f.fieldName, number = f.number, - type = - if (f.wrapped) { - interceptTypeName(f, ctx) ?: f.className - } else { - f.className - }, + type = f.interceptTypeName(ctx), documentation = annotatePropertyDocumentation(f, ctx), deprecation = deprecation(f) ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt index dec9f931b..6066c1546 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/PropertyAnnotator.kt @@ -28,8 +28,6 @@ import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.Nullability.nullable import protokt.v1.codegen.generate.Nullability.propertyType import protokt.v1.codegen.generate.Wrapper.interceptDefaultValue -import protokt.v1.codegen.generate.Wrapper.interceptMapKeyTypeName -import protokt.v1.codegen.generate.Wrapper.interceptMapValueTypeName import protokt.v1.codegen.generate.Wrapper.interceptTypeName import protokt.v1.codegen.generate.Wrapper.wrapped import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNullability @@ -40,7 +38,7 @@ import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField -fun annotateProperties(msg: Message, ctx: Context) = +internal fun annotateProperties(msg: Message, ctx: Context) = PropertyAnnotator(msg, ctx).annotate() private class PropertyAnnotator( @@ -66,8 +64,7 @@ private class PropertyAnnotator( defaultValue = field.defaultValue(ctx, msg.mapEntry), fieldType = field.type, repeated = field.repeated, - map = field.map, - mapEntry = msg.mapEntry, + mapEntry = field.mapEntry, nullable = field.nullable || field.optional || wrapperRequiresNullability, nonNullOption = field.hasNonNullOption, overrides = field.overrides(ctx, msg), @@ -102,13 +99,12 @@ private class PropertyAnnotator( } private fun annotateStandard(f: StandardField): TypeName = - if (f.map) { - val mapTypes = resolveMapEntryTypes(f, ctx) + if (f.isMap) { Map::class .asTypeName() - .parameterizedBy(mapTypes.kType, mapTypes.vType) + .parameterizedBy(f.mapKey.interceptTypeName(ctx), f.mapValue.interceptTypeName(ctx)) } else { - val parameter = interceptTypeName(f, ctx) ?: f.className + val parameter = f.interceptTypeName(ctx) if (f.repeated) { List::class.asTypeName().parameterizedBy(parameter) @@ -117,26 +113,13 @@ private class PropertyAnnotator( } } - private fun resolveMapEntryTypes(f: StandardField, ctx: Context) = - f.mapEntry!!.let { - MapTypeParams( - interceptMapKeyTypeName(f, ctx) ?: it.key.className, - interceptMapValueTypeName(f, ctx) ?: it.value.className - ) - } - - private class MapTypeParams( - val kType: TypeName, - val vType: TypeName - ) - private fun Field.defaultValue(ctx: Context, mapEntry: Boolean) = when (this) { is StandardField -> interceptDefaultValue( this, when { - map -> CodeBlock.of("emptyMap()") + isMap -> CodeBlock.of("emptyMap()") repeated -> CodeBlock.of("emptyList()") type == FieldType.Message -> CodeBlock.of("null") type == FieldType.Enum -> CodeBlock.of("%T.from(0)", className) @@ -158,13 +141,15 @@ class PropertyInfo( val defaultValue: CodeBlock, val nullable: Boolean, val nonNullOption: Boolean, - val mapEntry: Boolean = false, val fieldType: FieldType? = null, val repeated: Boolean = false, - val map: Boolean = false, + val mapEntry: Message? = null, val oneof: Boolean = false, val wrapped: Boolean = false, val overrides: Boolean = false, val documentation: List?, val deprecation: Deprecation.RenderOptions? = null -) +) { + val isMap + get() = mapEntry != null +} diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt index c97a5d48f..b258d1523 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/SerializerGenerator.kt @@ -23,9 +23,6 @@ import com.squareup.kotlinpoet.buildCodeBlock import protokt.v1.KtMessageSerializer import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Wrapper.interceptValueAccess -import protokt.v1.codegen.generate.Wrapper.mapKeyConverter -import protokt.v1.codegen.generate.Wrapper.mapValueConverter -import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.Message import protokt.v1.codegen.util.Oneof import protokt.v1.codegen.util.StandardField @@ -86,11 +83,11 @@ fun serialize( ) add("%N.forEach·{·serializer.%L·}", p, f.write(CodeBlock.of("it"))) } - f.map -> buildCodeBlock { + f.isMap -> buildCodeBlock { beginControlFlow("%N.entries.forEach", p) add( "serializer.writeTag(${f.tag.value}u).write(%L)\n", - f.boxMap(ctx) + f.boxMap() ) endControlFlowWithoutNewline() } @@ -114,22 +111,13 @@ fun serialize( } } -private fun StandardField.boxMap(ctx: Context): CodeBlock { - if (type != FieldType.Message) { - return CodeBlock.of("") - } - val keyParam = - mapKeyConverter(this, ctx) - ?.let { CodeBlock.of("%T.unwrap(it.key)", it) } - ?: CodeBlock.of("it.key") - - val valParam = - mapValueConverter(this, ctx) - ?.let { CodeBlock.of("%T.unwrap(it.value)", it) } - ?: CodeBlock.of("it.value") - - return CodeBlock.of("%T(%L, %L)", className, keyParam, valParam) -} +private fun StandardField.boxMap() = + CodeBlock.of( + "%T(%L, %L)", + className, + CodeBlock.of("it.key"), + CodeBlock.of("it.value") + ) private fun StandardField.write(value: CodeBlock) = CodeBlock.of("%L(%L)", type.writeFn, value) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt index d2b4625e7..daeb328df 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/WellKnownTypes.kt @@ -17,13 +17,12 @@ package protokt.v1.codegen.generate import protokt.v1.Bytes import protokt.v1.codegen.util.DOT_GOOGLE_PROTOBUF -import protokt.v1.codegen.util.StandardField -object WellKnownTypes { - val StandardField.wrapWithWellKnownInterception - get() = options.protokt.wrap.takeIf { it.isNotEmpty() } - ?: if (protoTypeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { - classNameForWellKnownType(protoTypeName.removePrefix("$DOT_GOOGLE_PROTOBUF.")) +internal object WellKnownTypes { + fun wrapWithWellKnownInterception(wrap: String?, typeName: String) = + wrap + ?: if (typeName.startsWith("$DOT_GOOGLE_PROTOBUF.")) { + classNameForWellKnownType(typeName.removePrefix("$DOT_GOOGLE_PROTOBUF.")) } else { null } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt index edfafd536..6892a7aaa 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/generate/Wrapper.kt @@ -26,37 +26,40 @@ import protokt.v1.OptimizedSizeOfConverter import protokt.v1.codegen.generate.CodeGenerator.Context import protokt.v1.codegen.generate.Nullability.hasNonNullOption import protokt.v1.codegen.generate.WellKnownTypes.wrapWithWellKnownInterception +import protokt.v1.codegen.util.ClassLookup import protokt.v1.codegen.util.ConverterDetails import protokt.v1.codegen.util.FieldType import protokt.v1.codegen.util.GeneratorContext import protokt.v1.codegen.util.StandardField +import protokt.v1.codegen.util.inferClassName import kotlin.reflect.KFunction2 internal object Wrapper { val StandardField.wrapped - get() = wrapWithWellKnownInterception != null + get() = wrapWithWellKnownInterception(options.wrap, protoTypeName) != null fun StandardField.wrapperRequiresNullability(ctx: Context) = wrapperRequiresNonNullOptionForNonNullity(ctx.info.context) && !hasNonNullOption fun StandardField.wrapperRequiresNonNullOptionForNonNullity(ctx: GeneratorContext) = - withWrapper(ctx) { it.cannotDeserializeDefaultValue && !repeated } ?: false + wrapped && withWrapper(ctx) { it.cannotDeserializeDefaultValue && !repeated } ?: false private fun StandardField.withWrapper( - wrapOption: String?, + wrap: String?, ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> T ) = - wrapOption?.let { wrap -> + wrapWithWellKnownInterception(wrap, protoTypeName)?.let { ifWrapped( converter( - protoTypeName.takeIf { it.isNotEmpty() } - ?.let { className } - // Protobuf primitives have no typeName - ?: requireNotNull(type.kotlinRepresentation) { - "no kotlin representation for type of $fieldName: $type" - }.asClassName(), - inferClassName(wrap, ctx.kotlinPackage), + ClassLookup.evaluateProtobufTypeCanonicalName( + protoTypeName, + className.canonicalName, + type, + fieldName + ), + inferClassName(it, ctx.kotlinPackage) + .let { (pkg, names) -> ClassName(pkg, names).canonicalName }, ctx ) ) @@ -66,7 +69,7 @@ internal object Wrapper { ctx: GeneratorContext, ifWrapped: (ConverterDetails) -> R ) = - withWrapper(wrapWithWellKnownInterception, ctx, ifWrapped) + withWrapper(options.wrap, ctx, ifWrapped) fun interceptSizeof( f: StandardField, @@ -104,18 +107,15 @@ internal object Wrapper { callConverterMethod(Converter::unwrap, it, accessValue) } ?: accessValue - fun wrapField(wrapName: TypeName, arg: CodeBlock) = - CodeBlock.of("%T.%L(%L)", wrapName, Converter::wrap.name, arg) - private fun callConverterMethod( method: KFunction2<*, *, *>, converterDetails: ConverterDetails, access: CodeBlock, ) = - CodeBlock.of("%T.%L(%L)", converterDetails.converterClassName, method.name, access) + CodeBlock.of("%T.%L(%L)", converterDetails.converter::class.asClassName(), method.name, access) fun wrapper(f: StandardField, ctx: Context) = - f.withWrapper(ctx.info.context, ConverterDetails::converterClassName) + f.withWrapper(ctx.info.context, ::converterClassName) fun interceptRead(f: StandardField, readFunction: CodeBlock) = if (f.bytesSlice) { @@ -131,52 +131,32 @@ internal object Wrapper { if (f.type == FieldType.Message && !f.repeated) { defaultValue } else { - wrapper(f, ctx)?.let { wrapField(it, defaultValue) } ?: defaultValue + wrapField(f, ctx, defaultValue) ?: defaultValue } } - fun interceptTypeName(f: StandardField, ctx: Context) = - if (f.bytesSlice) { + fun wrapField(f: StandardField, ctx: Context, argToConverter: CodeBlock) = + wrapper(f, ctx)?.let { wrapField(it, argToConverter) } + + private fun wrapField(wrapName: TypeName, arg: CodeBlock) = + CodeBlock.of("%T.%L(%L)", wrapName, Converter::wrap.name, arg) + + fun StandardField.interceptTypeName(ctx: Context) = + if (bytesSlice) { BytesSlice::class.asTypeName() } else { - f.withWrapper(ctx.info.context, ConverterDetails::kotlinClassName) - } + withWrapper(ctx.info.context, ::kotlinClassName) + } ?: className private val StandardField.bytesSlice get() = options.protokt.bytesSlice - private fun StandardField.withKeyWrap( - ctx: Context, - ifWrapped: (ConverterDetails) -> R - ) = - mapEntry!!.key.withWrapper( - options.protokt.keyWrap.takeIf { it.isNotEmpty() }, - ctx.info.context, - ifWrapped - ) - - fun interceptMapKeyTypeName(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ConverterDetails::kotlinClassName) - - fun mapKeyConverter(f: StandardField, ctx: Context) = - f.withKeyWrap(ctx, ConverterDetails::converterClassName) - - fun interceptMapValueTypeName(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ConverterDetails::kotlinClassName) + private fun kotlinClassName(converterDetails: ConverterDetails) = + ClassName.bestGuess(converterDetails.kotlinCanonicalClassName) - fun mapValueConverter(f: StandardField, ctx: Context) = - f.withValueWrap(ctx, ConverterDetails::converterClassName) - - private fun StandardField.withValueWrap( - ctx: Context, - ifWrapped: (ConverterDetails) -> R - ) = - mapEntry!!.value.withWrapper( - options.protokt.valueWrap.takeIf { it.isNotEmpty() }, - ctx.info.context, - ifWrapped - ) + private fun converterClassName(converterDetails: ConverterDetails) = + converterDetails.converter::class.asClassName() - private fun converter(protoClassName: ClassName, kotlinClassName: ClassName, ctx: GeneratorContext) = + private fun converter(protoClassName: String, kotlinClassName: String, ctx: GeneratorContext) = ctx.classLookup.converter(protoClassName, kotlinClassName) } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt index 8ea599766..52da2b310 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassLookup.kt @@ -18,9 +18,6 @@ package protokt.v1.codegen.util import com.google.common.collect.HashBasedTable import com.google.common.collect.ImmutableTable import com.google.common.collect.Table -import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.asClassName -import io.github.oshai.kotlinlogging.KotlinLogging import protokt.v1.Bytes import protokt.v1.Converter import protokt.v1.OptimizedSizeOfConverter @@ -31,11 +28,7 @@ import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.memberProperties class ClassLookup(classpath: List) { - private val logger = KotlinLogging.logger { } - private val classLoader by lazy { - logger.info { "Creating class loader with extra classpath: $classpath" } - val current = Thread.currentThread().contextClassLoader when { @@ -63,28 +56,32 @@ class ClassLookup(classpath: List) { .toList() } }.run { - val table = HashBasedTable.create>>() - forEach { table.getOrPut(it.wrapped.asClassName(), it.wrapper.asClassName()) { mutableListOf() }.add(it) } - ImmutableTable.builder>>().putAll(table).build() + val table = HashBasedTable.create>>() + forEach { table.getOrPut(it.wrapped.qualifiedName!!, it.wrapper.qualifiedName!!) { mutableListOf() }.add(it) } + ImmutableTable.builder>>().putAll(table).build() } } - private val classLookup = mutableMapOf>() + private val classLookup = mutableMapOf>() - fun properties(className: ClassName): Collection = + fun properties(canonicalClassName: String): Collection = try { - classLookup.getOrPut(className) { - classLoader.loadClass(className.canonicalName).kotlin + classLookup.getOrPut(canonicalClassName) { + classLoader.loadClass(canonicalClassName).kotlin }.memberProperties.map { it.name } } catch (t: Throwable) { - throw Exception("Class not found: ${className.canonicalName}") + throw Exception("Class not found: $canonicalClassName") } - fun converter(protoClassName: ClassName, kotlinClassName: ClassName): ConverterDetails { - val converters = convertersByProtoClassNameAndKotlinClassName.get(protoClassName, kotlinClassName) ?: emptyList() + fun converter(protoClassCanonicalName: String, kotlinClassCanonicalName: String): ConverterDetails { + val converters = + convertersByProtoClassNameAndKotlinClassName.get( + protoClassCanonicalName, + kotlinClassCanonicalName + ) ?: emptyList() require(converters.isNotEmpty()) { - "No converter found for wrapper type $kotlinClassName from type $protoClassName" + "No converter found for wrapper type $kotlinClassCanonicalName from type $protoClassCanonicalName" } val converter = @@ -107,12 +104,27 @@ class ClassLookup(classpath: List) { } return ConverterDetails( - converter::class.asClassName(), - kotlinClassName, + converter, + kotlinClassCanonicalName, converter is OptimizedSizeOfConverter<*, *>, !converter.acceptsDefaultValue ) } + + companion object { + fun evaluateProtobufTypeCanonicalName( + fieldDescriptorTypeName: String, + canonicalClassName: String, + type: FieldType, + fieldName: String + ): String = + fieldDescriptorTypeName.takeIf { it.isNotEmpty() } + ?.let { canonicalClassName } + // Protobuf primitives have no typeName + ?: requireNotNull(type.kotlinRepresentation) { + "no kotlin representation for type of $fieldName: $type" + }.qualifiedName!! + } } private fun tryDeserializeDefaultValue(converter: Converter): Throwable? { @@ -142,8 +154,8 @@ private fun tryDeserializeDefaultValue(converter: Converter): Th } class ConverterDetails( - val converterClassName: ClassName, - val kotlinClassName: ClassName, + val converter: Converter<*, *>, + val kotlinCanonicalClassName: String, val optimizedSizeof: Boolean, val cannotDeserializeDefaultValue: Boolean ) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt index 30be6089f..4c86b0326 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ClassNames.kt @@ -22,3 +22,25 @@ const val BUILDER = "Builder" fun GeneratorContext.className(simpleNames: List) = ClassName(kotlinPackage, simpleNames) + +fun inferClassName(className: String, pkg: String): Pair> { + val inferred = bestGuessPackageName(className) + return if (inferred == null) { + pkg to className.split(".") + } else { + inferred to className.substringAfter("$inferred.").split(".") + } +} + +private fun bestGuessPackageName(classNameString: String): String? { + var p = 0 + while (p < classNameString.length && Character.isLowerCase(classNameString.codePointAt(p))) { + p = classNameString.indexOf('.', p) + 1 + require(p != 0) { "couldn't make a guess for $classNameString" } + } + return if (p != 0) { + classNameString.substring(0, p - 1) + } else { + null + } +} diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt index f1017995d..364bae2ce 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldParser.kt @@ -26,7 +26,6 @@ import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type import com.google.protobuf.DescriptorProtos.FileDescriptorProto import com.google.protobuf.DescriptorProtos.OneofDescriptorProto import com.squareup.kotlinpoet.ClassName -import com.squareup.kotlinpoet.asTypeName import com.toasttab.protokt.v1.ProtoktProtos import protokt.v1.codegen.generate.Wrapper.wrapperRequiresNonNullOptionForNonNullity import protokt.v1.codegen.util.ErrorContext.withFieldName @@ -34,7 +33,9 @@ import protokt.v1.codegen.util.ErrorContext.withFieldName class FieldParser( private val ctx: GeneratorContext, private val desc: DescriptorProto, - private val enclosingMessages: List + private val enclosingMessages: List, + private val keyWrap: String?, + private val valueWrap: String? ) { fun toFields(): List { val generatedOneofIndices = mutableSetOf() @@ -102,10 +103,22 @@ class FieldParser( fdp: FieldDescriptorProto, withinOneof: Boolean = false ): StandardField { - val fieldType = toFieldType(fdp.type) + val fieldType = FieldType.from(fdp.type) val protoktOptions = fdp.options.getExtension(ProtoktProtos.property) val repeated = fdp.label == LABEL_REPEATED - val mapEntry = mapEntry(fdp) + val mapEntry = mapEntry(fdp, protoktOptions) + if (mapEntry == null) { + require(protoktOptions.keyWrap.isEmpty()) { + "key wrap is not applicable to non-map-entry" + } + require(protoktOptions.valueWrap.isEmpty()) { + "value wrap is not applicable to non-map-entry" + } + } else { + require(protoktOptions.wrap.isEmpty()) { + "wrap is not applicable to map entry" + } + } val optional = optional(fdp) val packed = packed(fieldType, fdp) val tag = @@ -124,9 +137,17 @@ class FieldParser( packed = packed, mapEntry = mapEntry, fieldName = LOWER_UNDERSCORE.to(LOWER_CAMEL, fdp.name), - options = FieldOptions(fdp.options, protoktOptions), + options = FieldOptions( + fdp.options, + protoktOptions, + when { + keyWrap != null && idx == 0 -> keyWrap + valueWrap != null && idx == 1 -> valueWrap + else -> protoktOptions.wrap.takeIf { it.isNotEmpty() } + } + ), protoTypeName = fdp.typeName, - className = typeName(fdp.typeName, fieldType), + className = ClassName.bestGuess(typeName(fdp.typeName, fieldType)), index = idx ) @@ -137,21 +158,24 @@ class FieldParser( return result } - private fun mapEntry(fdp: FieldDescriptorProto) = + private fun mapEntry(fdp: FieldDescriptorProto, options: ProtoktProtos.FieldOptions) = if (fdp.label == LABEL_REPEATED && fdp.type == Type.TYPE_MESSAGE) { findMapEntry(ctx.fdp, fdp.typeName) ?.takeIf { it.options.mapEntry } - ?.let { resolveMapEntry(MessageParser(ctx, -1, it, enclosingMessages).toMessage()) } + ?.let { entry -> + MessageParser( + ctx, + -1, + entry, + enclosingMessages + desc.name, + options.keyWrap.takeIf { it.isNotEmpty() }, + options.valueWrap.takeIf { it.isNotEmpty() } + ).toMessage() + } } else { null } - private fun resolveMapEntry(m: Message) = - MapEntry( - (m.fields[0] as StandardField), - (m.fields[1] as StandardField) - ) - private fun findMapEntry( fdp: FileDescriptorProto, name: String, @@ -180,22 +204,6 @@ class FieldParser( } } - private fun typeName(protoTypeName: String, fieldType: FieldType): ClassName { - val fullyProtoQualified = protoTypeName.startsWith(".") - - return if (fullyProtoQualified) { - requalifyProtoType(protoTypeName) - } else { - protoTypeName.let { - if (it.isEmpty()) { - fieldType.protoktFieldType.asTypeName() - } else { - ClassName.bestGuess(it) - } - } - } - } - private fun optional(fdp: FieldDescriptorProto) = (fdp.label == LABEL_OPTIONAL && ctx.proto2) || fdp.proto3Optional @@ -247,7 +255,7 @@ class FieldParser( "and is inapplicable to non-message " + when { field.mapEntry != null -> - "map<${name(field.mapEntry.key)}, ${name(field.mapEntry.value)}>" + "map<${name(field.mapKey)}, ${name(field.mapValue)}>" field.repeated -> "repeated $typeName" @@ -258,25 +266,3 @@ class FieldParser( } } } - -private fun toFieldType(type: Type) = - when (type) { - Type.TYPE_BOOL -> FieldType.Bool - Type.TYPE_BYTES -> FieldType.Bytes - Type.TYPE_DOUBLE -> FieldType.Double - Type.TYPE_ENUM -> FieldType.Enum - Type.TYPE_FIXED32 -> FieldType.Fixed32 - Type.TYPE_FIXED64 -> FieldType.Fixed64 - Type.TYPE_FLOAT -> FieldType.Float - Type.TYPE_INT32 -> FieldType.Int32 - Type.TYPE_INT64 -> FieldType.Int64 - Type.TYPE_MESSAGE -> FieldType.Message - Type.TYPE_SFIXED32 -> FieldType.SFixed32 - Type.TYPE_SFIXED64 -> FieldType.SFixed64 - Type.TYPE_SINT32 -> FieldType.SInt32 - Type.TYPE_SINT64 -> FieldType.SInt64 - Type.TYPE_STRING -> FieldType.String - Type.TYPE_UINT32 -> FieldType.UInt32 - Type.TYPE_UINT64 -> FieldType.UInt64 - else -> error("Unknown type: $type") - } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt index 12fb04eb9..5178eb690 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldType.kt @@ -15,6 +15,7 @@ package protokt.v1.codegen.util +import com.google.protobuf.DescriptorProtos.FieldDescriptorProto.Type import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.MemberName import com.squareup.kotlinpoet.MemberName.Companion.member @@ -139,4 +140,28 @@ sealed class FieldType { Bytes -> CodeBlock.of("%T.empty()", protokt.v1.Bytes::class) String -> CodeBlock.of("\"\"") } + + companion object { + fun from(type: Type) = + when (type) { + Type.TYPE_BOOL -> Bool + Type.TYPE_BYTES -> Bytes + Type.TYPE_DOUBLE -> Double + Type.TYPE_ENUM -> Enum + Type.TYPE_FIXED32 -> Fixed32 + Type.TYPE_FIXED64 -> Fixed64 + Type.TYPE_FLOAT -> Float + Type.TYPE_INT32 -> Int32 + Type.TYPE_INT64 -> Int64 + Type.TYPE_MESSAGE -> Message + Type.TYPE_SFIXED32 -> SFixed32 + Type.TYPE_SFIXED64 -> SFixed64 + Type.TYPE_SINT32 -> SInt32 + Type.TYPE_SINT64 -> SInt64 + Type.TYPE_STRING -> String + Type.TYPE_UINT32 -> UInt32 + Type.TYPE_UINT64 -> UInt64 + else -> error("Unknown type: $type") + } + } } diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt index 0fadb6cce..a554d3b90 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FileContentParser.kt @@ -51,7 +51,7 @@ class FileContentParser( } + messages.mapIndexed { idx, desc -> withMessageName((enclosingMessages + desc.name).joinToString(".")) { - MessageParser(ctx, idx, desc, enclosingMessages).toMessage() + MessageParser(ctx, idx, desc, enclosingMessages, null, null).toMessage() } } + services.mapIndexed { idx, desc -> diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt index d2b7cd15a..c79d65023 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/GrpcKotlinGeneratorSupport.kt @@ -44,7 +44,7 @@ private fun stripPackages(request: CodeGeneratorRequest) = fdp.toBuilder() .setOptions( fdp.options.toBuilder() - .setJavaPackage(resolvePackage(fdp)) + .setJavaPackage(resolvePackage(fdp.`package`)) .build() ) .build() diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt index bb08a1844..e95896cb0 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/MessageParser.kt @@ -22,10 +22,12 @@ class MessageParser( private val ctx: GeneratorContext, private val idx: Int, private val desc: DescriptorProto, - private val enclosingMessages: List + private val enclosingMessages: List, + private val keyWrap: String?, + private val valueWrap: String? ) { fun toMessage(): Message { - val fieldList = FieldParser(ctx, desc, enclosingMessages).toFields() + val fieldList = FieldParser(ctx, desc, enclosingMessages, keyWrap, valueWrap).toFields() val simpleNames = enclosingMessages + desc.name return Message( fields = fieldList.sortedBy { @@ -41,7 +43,7 @@ class MessageParser( emptyList(), simpleNames ).parseContents(), - mapEntry = desc.options?.mapEntry == true, + mapEntry = desc.options.mapEntry, options = MessageOptions( desc.options, desc.options.getExtension(ProtoktProtos.class_) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt index 0cbc1c724..11a2ed6fd 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/PackageResolution.kt @@ -16,7 +16,6 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.FileDescriptorProto -import com.squareup.kotlinpoet.ClassName import protokt.v1.Bytes val PROTOKT_V1 = Bytes::class.java.`package`.name @@ -24,21 +23,33 @@ const val DOT_GOOGLE_PROTOBUF = ".google.protobuf" val PROTOKT_V1_GOOGLE_PROTO = PROTOKT_V1 + DOT_GOOGLE_PROTOBUF fun packagesByFileName(protoFileList: List) = - protoFileList.associate { it.name to resolvePackage(it) } + protoFileList.associate { it.name to resolvePackage(it.`package`) } -fun resolvePackage(fdp: FileDescriptorProto) = - if (fdp.`package`.startsWith(PROTOKT_V1)) { - fdp.`package` +fun resolvePackage(pkg: String) = + if (pkg.startsWith(PROTOKT_V1)) { + pkg } else { - "$PROTOKT_V1." + fdp.`package` + "$PROTOKT_V1.$pkg" } -fun requalifyProtoType(typeName: String): ClassName = +fun requalifyProtoType(typeName: String): String = // type name might have a `.` prefix - ClassName.bestGuess( - if (typeName.startsWith(".$PROTOKT_V1")) { - typeName.removePrefix(".") - } else { - "$PROTOKT_V1." + typeName.removePrefix(".") + if (typeName.startsWith(".$PROTOKT_V1")) { + typeName.removePrefix(".") + } else { + "$PROTOKT_V1." + typeName.removePrefix(".") + } + +internal fun typeName(protoTypeName: String, fieldType: FieldType): String { + val fullyProtoQualified = protoTypeName.startsWith(".") + + return if (fullyProtoQualified) { + requalifyProtoType(protoTypeName) + } else { + protoTypeName.let { + it.ifEmpty { + fieldType.protoktFieldType.qualifiedName!! + } } - ) + } +} diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt index 75d3e9789..017afe64f 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/ServiceParser.kt @@ -17,6 +17,7 @@ package protokt.v1.codegen.util import com.google.protobuf.DescriptorProtos.MethodDescriptorProto import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto +import com.squareup.kotlinpoet.ClassName import com.toasttab.protokt.v1.ProtoktProtos class ServiceParser( @@ -38,8 +39,8 @@ class ServiceParser( private fun toMethod(desc: MethodDescriptorProto) = Method( name = desc.name, - inputType = requalifyProtoType(desc.inputType), - outputType = requalifyProtoType(desc.outputType), + inputType = ClassName.bestGuess(requalifyProtoType(desc.inputType)), + outputType = ClassName.bestGuess(requalifyProtoType(desc.outputType)), clientStreaming = desc.clientStreaming, serverStreaming = desc.serverStreaming, deprecated = desc.options.deprecated, diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt index 1227248f2..e71bbc576 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/Types.kt @@ -111,13 +111,19 @@ class StandardField( val repeated: Boolean, val optional: Boolean, val packed: Boolean, - val mapEntry: MapEntry?, + val mapEntry: Message?, val protoTypeName: String, val options: FieldOptions, val index: Int ) : Field() { - val map + val isMap get() = mapEntry != null + + val mapKey + get() = mapEntry!!.fields[0] as StandardField + + val mapValue + get() = mapEntry!!.fields[1] as StandardField } class Oneof( @@ -130,14 +136,10 @@ class Oneof( val index: Int ) : Field() -class MapEntry( - val key: StandardField, - val value: StandardField -) - class FieldOptions( val default: DescriptorProtos.FieldOptions, - val protokt: ProtoktProtos.FieldOptions + val protokt: ProtoktProtos.FieldOptions, + val wrap: String? ) class OneofOptions( diff --git a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto index 5e3297f29..b5e9c49ca 100644 --- a/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto +++ b/testing/protokt-generation/src/main/proto/protokt/v1/testing/wkt_test.proto @@ -29,4 +29,8 @@ message WellKnownTypes { google.protobuf.BoolValue bool = 7; google.protobuf.StringValue string = 8; google.protobuf.BytesValue bytes = 9; + + repeated google.protobuf.DoubleValue doubles = 10; + + map string_values = 11; } diff --git a/testing/protokt-generation/src/test/kotlin/protokt/v1/testing/WellKnownTypesTest.kt b/testing/protokt-generation/src/test/kotlin/protokt/v1/testing/WellKnownTypesTest.kt index 94fdc2151..eeee1a381 100644 --- a/testing/protokt-generation/src/test/kotlin/protokt/v1/testing/WellKnownTypesTest.kt +++ b/testing/protokt-generation/src/test/kotlin/protokt/v1/testing/WellKnownTypesTest.kt @@ -33,6 +33,8 @@ class WellKnownTypesTest { bool = false string = "some-string" bytes = Bytes.from(byteArrayOf(4, 5, 3)) + doubles = listOf(0.1, 0.2, 0.3) + stringValues = mapOf("foo" to "bar", "baz" to "qux") } assertThat(WellKnownTypes.deserialize(original.serialize())) From ed9c87b4664b788ce7fd6cdb529c76c75ed3f236 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 6 Jan 2024 03:10:18 -0500 Subject: [PATCH 26/38] remove guava --- gradle/libs.versions.toml | 2 - protokt-reflect/build.gradle.kts | 1 - .../v1/google/protobuf/ProtoktReflect.kt | 87 +++++++++---------- 3 files changed, 41 insertions(+), 49 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1708966e9..c6611d633 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,6 @@ autoService = "1.0.1" classgraph = "4.8.153" grpc-java = "1.58.0" grpc-kotlin = "1.4.0" -guava = "33.0.0-android" kotlinLogging = "5.1.0" kotlinPoet = "1.14.2" kotlinx-coroutines = "1.6.0" @@ -66,7 +65,6 @@ classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classg grpc-kotlin-gen = { module = "io.grpc:protoc-gen-grpc-kotlin", version.ref = "grpc-kotlin" } grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc-java" } grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc-java" } -guava = { module = "com.google.guava:guava", version.ref = "guava" } kotlinLogging = { module = "io.github.oshai:kotlin-logging", version.ref = "kotlinLogging" } kotlinPoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinPoet" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 55d08396c..4fdb9f746 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -33,7 +33,6 @@ kotlin { api(libs.protobuf.java) implementation(kotlin("reflect")) - implementation(libs.guava) implementation(libs.classgraph) } } diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt index d016c4ee5..c35d29b8b 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/ProtoktReflect.kt @@ -15,8 +15,6 @@ package protokt.v1.google.protobuf -import com.google.common.cache.CacheBuilder -import com.google.common.cache.CacheLoader import com.google.protobuf.Descriptors.FieldDescriptor import com.google.protobuf.Descriptors.FieldDescriptor.Type import protokt.v1.Fixed32Val @@ -28,6 +26,7 @@ import protokt.v1.LengthDelimitedVal import protokt.v1.UnknownFieldSet import protokt.v1.VarintVal import java.nio.charset.StandardCharsets +import java.util.concurrent.ConcurrentHashMap import kotlin.Any import kotlin.reflect.KClass import kotlin.reflect.KProperty1 @@ -36,18 +35,17 @@ import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.isSubclassOf internal object ProtoktReflect { - private val reflectedGettersByClass = - CacheBuilder.newBuilder() - .build( - object : CacheLoader, (FieldDescriptor, KtMessage) -> Any?>() { - override fun load(messageClass: KClass) = - { field: FieldDescriptor, message: KtMessage -> - topLevelProperty(messageClass)(field, message) - ?: oneofProperty(messageClass)(field, message) - ?: getUnknownField(field, message) - } - }, - ) + private val reflectedGettersByClass = ConcurrentHashMap, (FieldDescriptor, KtMessage) -> Any?>() + + private fun getReflectedGettersByClass(messageClass: KClass) = + reflectedGettersByClass.computeIfAbsent(messageClass) { + { + field, message -> + topLevelProperty(messageClass)(field, message) + ?: oneofProperty(messageClass)(field, message) + ?: getUnknownField(field, message) + } + } private fun topLevelProperty(klass: KClass): (FieldDescriptor, KtMessage) -> Any? { val gettersByNumber = gettersByNumber(klass) @@ -97,43 +95,40 @@ internal object ProtoktReflect { return { field, msg -> gettersByNumber[field.number]?.invoke(msg) } } - private fun getUnknownField( - field: FieldDescriptor, - message: KtMessage, - ) = getUnknownFields(message)[field.number.toUInt()]?.let { value -> - when { - value.varint.isNotEmpty() -> - value.varint - .map(VarintVal::value) - .map { - if (field.type == Type.UINT64) { - it - } else { - it.toLong() + private fun getUnknownField(field: FieldDescriptor, message: KtMessage) = + getUnknownFields(message)[field.number.toUInt()]?.let { value -> + when { + value.varint.isNotEmpty() -> + value.varint + .map(VarintVal::value) + .map { + if (field.type == Type.UINT64) { + it + } else { + it.toLong() + } } - } - value.fixed32.isNotEmpty() -> - value.fixed32.map(Fixed32Val::value) + value.fixed32.isNotEmpty() -> + value.fixed32.map(Fixed32Val::value) - value.fixed64.isNotEmpty() -> - value.fixed64.map(Fixed64Val::value) + value.fixed64.isNotEmpty() -> + value.fixed64.map(Fixed64Val::value) - value.lengthDelimited.isNotEmpty() -> - value.lengthDelimited - .map(LengthDelimitedVal::value) - .map { - if (field.type == Type.STRING) { - StandardCharsets.UTF_8.decode(it.asReadOnlyBuffer()).toString() - } else { - it + value.lengthDelimited.isNotEmpty() -> + value.lengthDelimited + .map(LengthDelimitedVal::value) + .map { + if (field.type == Type.STRING) { + StandardCharsets.UTF_8.decode(it.asReadOnlyBuffer()).toString() + } else { + it + } } - } - else -> error("unknown field for field number ${field.number} existed but was empty") - } - } - .let { + else -> error("unknown field for field number ${field.number} existed but was empty") + } + }.let { if (field.isRepeated) { if (field.isMapField) { it ?: emptyMap() @@ -146,7 +141,7 @@ internal object ProtoktReflect { } fun getField(message: KtMessage, field: FieldDescriptor): Any? = - reflectedGettersByClass[message::class](field, message) + getReflectedGettersByClass(message::class)(field, message) } internal fun getUnknownFields(message: KtMessage) = From 294fb53167ab431348cad1727ebae4604fe0c86e Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 6 Jan 2024 12:13:13 -0500 Subject: [PATCH 27/38] rm guava --- .../reflect/protokt/v1/reflect/ClassLookup.kt | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt index 3df340a92..9a6d766a2 100644 --- a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt +++ b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -15,9 +15,6 @@ package protokt.v1.reflect -import com.google.common.collect.HashBasedTable -import com.google.common.collect.ImmutableTable -import com.google.common.collect.Table import protokt.v1.Bytes import protokt.v1.Converter import protokt.v1.OptimizedSizeOfConverter @@ -43,7 +40,7 @@ internal class ClassLookup(classpath: List) { } } - private val convertersByProtoClassNameAndKotlinClassName by lazy { + private val convertersByProtoClassNameAndKotlinClassName: Map>>> by lazy { classLoader.getResources("META-INF/services/${Converter::class.qualifiedName}") .asSequence() .flatMap { url -> @@ -55,10 +52,12 @@ internal class ClassLookup(classpath: List) { .map { classLoader.loadClass(it).kotlin.objectInstance as Converter<*, *> } .toList() } - }.run { - val table = HashBasedTable.create>>() - forEach { table.getOrPut(it.wrapped.qualifiedName!!, it.wrapper.qualifiedName!!) { mutableListOf() }.add(it) } - ImmutableTable.builder>>().putAll(table).build() + }.fold(mutableMapOf>>>()) { acc, converter -> + acc.apply { + getOrPut(converter.wrapped.qualifiedName!!, ::mutableMapOf) + .getOrPut(converter.wrapper.qualifiedName!!, ::mutableListOf) + .add(converter) + } } } @@ -75,10 +74,9 @@ internal class ClassLookup(classpath: List) { fun converter(protoClassCanonicalName: String, kotlinClassCanonicalName: String): ConverterDetails { val converters = - convertersByProtoClassNameAndKotlinClassName.get( - protoClassCanonicalName, - kotlinClassCanonicalName - ) ?: emptyList() + convertersByProtoClassNameAndKotlinClassName[protoClassCanonicalName] + ?.get(kotlinClassCanonicalName) + .orEmpty() require(converters.isNotEmpty()) { "No converter found for wrapper type $kotlinClassCanonicalName from type $protoClassCanonicalName" @@ -159,6 +157,3 @@ internal class ConverterDetails( val optimizedSizeof: Boolean, val cannotDeserializeDefaultValue: Boolean ) - -private fun Table.getOrPut(r: R, c: C, v: () -> V): V = - get(r, c) ?: v().also { put(r, c, it) } From 3af2204a523a3636f46dad060725adc518446c3f Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 6 Jan 2024 12:14:19 -0500 Subject: [PATCH 28/38] rm line --- shared-src/reflect/protokt/v1/reflect/ClassLookup.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt index 9a6d766a2..a79665853 100644 --- a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt +++ b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -50,7 +50,6 @@ internal class ClassLookup(classpath: List) { lines.map { it.substringBefore("#").trim() } .filter { it.isNotEmpty() } .map { classLoader.loadClass(it).kotlin.objectInstance as Converter<*, *> } - .toList() } }.fold(mutableMapOf>>>()) { acc, converter -> acc.apply { From d150db2329216b8095083857bf5ecbac3a4a5b3b Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 6 Jan 2024 12:21:09 -0500 Subject: [PATCH 29/38] reflect need not be compatible with android --- protokt-reflect/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 4fdb9f746..6f9ec6415 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -22,7 +22,6 @@ plugins { localProtokt(false) enablePublishing() -compatibleWithAndroid() trackKotlinApiCompatibility() kotlin { From 0e82a0893985e18e96c7f36ad051304371301d11 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sat, 6 Jan 2024 12:30:15 -0500 Subject: [PATCH 30/38] turns out this line was needed --- shared-src/reflect/protokt/v1/reflect/ClassLookup.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt index a79665853..9a6d766a2 100644 --- a/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt +++ b/shared-src/reflect/protokt/v1/reflect/ClassLookup.kt @@ -50,6 +50,7 @@ internal class ClassLookup(classpath: List) { lines.map { it.substringBefore("#").trim() } .filter { it.isNotEmpty() } .map { classLoader.loadClass(it).kotlin.objectInstance as Converter<*, *> } + .toList() } }.fold(mutableMapOf>>>()) { acc, converter -> acc.apply { From 301a9e277cd2ee1c739070d83eab9097dcfadc19 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Mon, 8 Jan 2024 22:48:52 -0500 Subject: [PATCH 31/38] Update build.gradle.kts --- protokt-reflect/build.gradle.kts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 6f9ec6415..4ee7ad14a 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -46,9 +46,7 @@ sourceSets { srcDir(rootProject.file("shared-src/reflect")) } proto { - srcDirs( - "../extensions/protokt-extensions-lite/src/extensions-proto" - ) + srcDir("../extensions/protokt-extensions-lite/src/extensions-proto") } } } From af1af5597933d9cd30ecb2e686cebf790fdc4421 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 7 Feb 2024 11:58:15 -0500 Subject: [PATCH 32/38] Update FieldTypeExt.kt --- .../src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt index 9a4f6b6fe..3891b031c 100644 --- a/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt +++ b/protokt-codegen/src/main/kotlin/protokt/v1/codegen/util/FieldTypeExt.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Toast, Inc. + * Copyright (c) 2023 Toast, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From ad92a9f72978f7c0c684134facdef10e9b5a50f6 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sun, 17 Mar 2024 11:31:13 -0400 Subject: [PATCH 33/38] no data objects --- .../reflect/protokt/v1/reflect/FieldType.kt | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/shared-src/reflect/protokt/v1/reflect/FieldType.kt b/shared-src/reflect/protokt/v1/reflect/FieldType.kt index b8c45baaf..3f3ac97df 100644 --- a/shared-src/reflect/protokt/v1/reflect/FieldType.kt +++ b/shared-src/reflect/protokt/v1/reflect/FieldType.kt @@ -31,28 +31,28 @@ internal sealed class FieldType { override val ktRepresentation: KClass<*>? = null ) : FieldType() - data object Enum : Nonscalar(ktRepresentation = KtEnum::class) - data object Message : Nonscalar(ktRepresentation = KtMessage::class) - data object String : Nonscalar(kotlin.String::class) - data object Bytes : Nonscalar(protokt.v1.Bytes::class) + object Enum : Nonscalar(ktRepresentation = KtEnum::class) + object Message : Nonscalar(ktRepresentation = KtMessage::class) + object String : Nonscalar(kotlin.String::class) + object Bytes : Nonscalar(protokt.v1.Bytes::class) sealed class Scalar( override val kotlinRepresentation: KClass<*>? = null ) : FieldType() - data object Bool : Scalar(Boolean::class) - data object Double : Scalar(kotlin.Double::class) - data object Float : Scalar(kotlin.Float::class) - data object Fixed32 : Scalar(UInt::class) - data object Fixed64 : Scalar(ULong::class) - data object Int32 : Scalar(Int::class) - data object Int64 : Scalar(Long::class) - data object SFixed32 : Scalar(Int::class) - data object SFixed64 : Scalar(Long::class) - data object SInt32 : Scalar(Int::class) - data object SInt64 : Scalar(Long::class) - data object UInt32 : Scalar(UInt::class) - data object UInt64 : Scalar(ULong::class) + object Bool : Scalar(Boolean::class) + object Double : Scalar(kotlin.Double::class) + object Float : Scalar(kotlin.Float::class) + object Fixed32 : Scalar(UInt::class) + object Fixed64 : Scalar(ULong::class) + object Int32 : Scalar(Int::class) + object Int64 : Scalar(Long::class) + object SFixed32 : Scalar(Int::class) + object SFixed64 : Scalar(Long::class) + object SInt32 : Scalar(Int::class) + object SInt64 : Scalar(Long::class) + object UInt32 : Scalar(UInt::class) + object UInt64 : Scalar(ULong::class) val protoktFieldType get() = when (this) { From ae1c6099053c842f2ef95ecd1708eba20581c9ec Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Sun, 21 Apr 2024 23:32:50 -0400 Subject: [PATCH 34/38] don't allow conversion of null --- .../kotlin/protokt/v1/google/protobuf/KtMessages.kt | 8 ++++---- .../test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt index 3eb3e7941..f3853c50c 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/KtMessages.kt @@ -79,7 +79,7 @@ class RuntimeContext internal constructor( internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } - fun convertValue(value: Any?) = + fun convertValue(value: Any) = when (value) { is KtEnum -> value.value is UInt -> value.toInt() @@ -234,7 +234,7 @@ private fun convertList( val wrap = wrap(field, fieldOptions) return value.map { if (wrap == null) { - context.convertValue(it) + it?.let(context::convertValue) } else { context.convertValue(context.unwrap(it!!, field, wrap)) } @@ -280,14 +280,14 @@ private fun convertMap( defaultEntry.toBuilder() .setKey( if (keyWrap == null) { - context.convertValue(k) + k?.let(context::convertValue) } else { context.convertValue(context.unwrap(k!!, keyDesc, keyWrap)) } ) .setValue( if (valWrap == null) { - context.convertValue(v) + v?.let(context::convertValue) } else { context.convertValue(context.unwrap(v!!, valDesc, valWrap)) } diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt index 8a19fec1a..dcc8b6e8b 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt @@ -37,7 +37,7 @@ class ProtoktReflectTest { assertThat(javaDefault.hasField(field)).isFalse() assertThat(protoktDefault.hasField(field)).isFalse() - assertThat(context.convertValue(protoktDefault.getField(field))) + assertThat(protoktDefault.getField(field)?.let(context::convertValue)) .isEqualTo(javaDefault.getField(field)) } From 27ff3cc6197718d65f7e2578bb3e1b9fd2bf2f1d Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 8 May 2024 11:19:18 -0400 Subject: [PATCH 35/38] classpath scan only in tests --- gradle/libs.versions.toml | 4 +- protokt-reflect/build.gradle.kts | 1 - .../protokt/v1/google/protobuf/Messages.kt | 275 +----------------- .../v1/google/protobuf/RuntimeContext.kt | 242 +++++++++++++++ testing/interop/build.gradle.kts | 1 + .../protokt/v1/testing/DynamicMessageTest.kt | 3 +- .../protokt/v1/testing/ProtoktReflectTest.kt | 3 +- .../protokt/v1/testing/RuntimeContextUtil.kt | 60 ++++ 8 files changed, 310 insertions(+), 279 deletions(-) create mode 100644 protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/RuntimeContext.kt create mode 100644 testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d225cb26c..c85bc433b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,6 @@ [versions] autoService = "1.1.1" -classgraph = "4.8.153" grpc-java = "1.58.0" grpc-kotlin = "1.4.1" kotlinLogging = "5.1.0" @@ -45,6 +44,7 @@ jmh = "1.37" wire = "4.9.7" # test +classgraph = "4.8.153" grpc-js = "1.8.14" jackson = "2.17.0" junit = "5.10.2" @@ -62,7 +62,6 @@ wire = { id = "com.squareup.wire", version.ref = "wire" } [libraries] autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } autoServiceAnnotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoService" } -classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } grpc-kotlin-gen = { module = "io.grpc:protoc-gen-grpc-kotlin", version.ref = "grpc-kotlin" } grpc-netty = { module = "io.grpc:grpc-netty", version.ref = "grpc-java" } grpc-stub = { module = "io.grpc:grpc-stub", version.ref = "grpc-java" } @@ -93,6 +92,7 @@ wireRuntime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" protoGoogleCommonProtos = { module = "com.google.api.grpc:proto-google-common-protos", version.ref = "protoGoogleCommonProtos" } # test +classgraph = { module = "io.github.classgraph:classgraph", version.ref = "classgraph" } grpc-kotlin-stub = { module = "io.grpc:grpc-kotlin-stub", version.ref = "grpc-kotlin" } grpc-testing = { module = "io.grpc:grpc-testing", version.ref = "grpc-java" } jackson = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" } diff --git a/protokt-reflect/build.gradle.kts b/protokt-reflect/build.gradle.kts index 4ee7ad14a..4cbb890c9 100644 --- a/protokt-reflect/build.gradle.kts +++ b/protokt-reflect/build.gradle.kts @@ -32,7 +32,6 @@ kotlin { api(libs.protobuf.java) implementation(kotlin("reflect")) - implementation(libs.classgraph) } } } diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/Messages.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/Messages.kt index 932130be1..2760694fd 100644 --- a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/Messages.kt +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/Messages.kt @@ -17,35 +17,11 @@ package protokt.v1.google.protobuf -import com.google.protobuf.DescriptorProtos -import com.google.protobuf.Descriptors import com.google.protobuf.Descriptors.FieldDescriptor import com.google.protobuf.Descriptors.FieldDescriptor.Type import com.google.protobuf.DynamicMessage -import com.google.protobuf.MapEntry -import com.google.protobuf.UnknownFieldSet -import com.google.protobuf.UnknownFieldSet.Field -import com.google.protobuf.UnsafeByteOperations -import com.google.protobuf.WireFormat -import com.toasttab.protokt.v1.ProtoktProtos -import io.github.classgraph.ClassGraph import protokt.v1.Bytes -import protokt.v1.Converter -import protokt.v1.Enum -import protokt.v1.GeneratedFileDescriptor -import protokt.v1.GeneratedMessage import protokt.v1.Message -import protokt.v1.reflect.ClassLookup -import protokt.v1.reflect.FieldType -import protokt.v1.reflect.WellKnownTypes -import protokt.v1.reflect.inferClassName -import protokt.v1.reflect.resolvePackage -import protokt.v1.reflect.typeName -import kotlin.Any -import kotlin.reflect.KClass -import kotlin.reflect.full.declaredMemberProperties -import kotlin.reflect.full.findAnnotation -import com.google.protobuf.Message as ProtobufMessage fun Message.toDynamicMessage(context: RuntimeContext): DynamicMessage = context.convertValue(this) as DynamicMessage @@ -60,6 +36,9 @@ fun Message.hasField(field: FieldDescriptor): Boolean { } } +fun Message.getField(field: FieldDescriptor) = + ProtoktReflect.getField(this, field) + private fun defaultValue(field: FieldDescriptor) = when (field.type) { Type.UINT64, Type.FIXED64 -> 0uL @@ -67,251 +46,3 @@ private fun defaultValue(field: FieldDescriptor) = Type.BYTES -> Bytes.empty() else -> field.defaultValue } - -fun Message.getField(field: FieldDescriptor) = - ProtoktReflect.getField(this, field) - -class RuntimeContext internal constructor( - descriptors: Iterable, - private val classLookup: ClassLookup -) { - constructor(descriptors: Iterable) : this(descriptors, DEFAULT_CLASS_LOOKUP) - - internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } - - fun convertValue(value: Any) = - when (value) { - is Enum -> value.value - is UInt -> value.toInt() - is ULong -> value.toLong() - is Message -> toDynamicMessage(value, this) - is Bytes -> UnsafeByteOperations.unsafeWrap(value.asReadOnlyBuffer()) - - // pray - else -> value - } - - internal fun unwrap(value: Any, field: FieldDescriptor, wrap: String): Any { - val proto = field.toProto() - val type = FieldType.from(proto.type) - val converterDetails = - classLookup.converter( - ClassLookup.evaluateProtobufTypeCanonicalName( - proto.typeName, - typeName(proto.typeName, type), - type, - field.name - ), - wrap - ) - - @Suppress("UNCHECKED_CAST") - val converter = converterDetails.converter as Converter - return converter.unwrap(value) - } - - companion object { - private val DEFAULT_CLASS_LOOKUP by lazy { ClassLookup(emptyList()) } - - private val reflectiveContext by lazy { - RuntimeContext(getDescriptors(), DEFAULT_CLASS_LOOKUP) - } - - fun getContextReflectively() = - reflectiveContext - } -} - -private fun getDescriptors() = - ClassGraph() - .enableAnnotationInfo() - .scan() - .use { - it.getClassesWithAnnotation(GeneratedFileDescriptor::class.java) - .map { info -> - @Suppress("UNCHECKED_CAST") - info.loadClass().kotlin as KClass - } - } - .asSequence() - .map { klassWithDescriptor -> - klassWithDescriptor - .declaredMemberProperties - .single { it.returnType.classifier == FileDescriptor::class } - .get(klassWithDescriptor.objectInstance!!) as FileDescriptor - } - .flatMap { it.toProtobufJavaDescriptor().messageTypes } - .flatMap(::collectDescriptors) - .asIterable() - -private fun collectDescriptors(descriptor: Descriptors.Descriptor): Iterable = - listOf(descriptor) + descriptor.nestedTypes.flatMap(::collectDescriptors) - -private fun FileDescriptor.toProtobufJavaDescriptor(): Descriptors.FileDescriptor = - Descriptors.FileDescriptor.buildFrom( - DescriptorProtos.FileDescriptorProto.parseFrom(proto.serialize()), - dependencies.map { it.toProtobufJavaDescriptor() }.toTypedArray(), - true, - ) - -private fun toDynamicMessage( - message: Message, - context: RuntimeContext, -): ProtobufMessage { - val descriptor = - context.descriptorsByTypeName - .getValue(message::class.findAnnotation()!!.fullTypeName) - - return DynamicMessage.newBuilder(descriptor) - .apply { - descriptor.fields.forEach { field -> - message.getField(field)?.let { value -> - val fieldOptions = fieldOptions(field) - - setField( - field, - when { - field.type == Type.ENUM -> - if (field.isRepeated) { - (value as List<*>).map { field.enumType.findValueByNumberCreatingIfUnknown(((it as Enum).value)) } - } else { - field.enumType.findValueByNumberCreatingIfUnknown(((value as Enum).value)) - } - - field.isMapField -> - convertMap(value, field, fieldOptions, context) - - field.isRepeated -> - convertList((value as List<*>), field, fieldOptions, context) - - else -> { - val wrap = wrap(field, fieldOptions) - if (wrap == null) { - context.convertValue(value) - } else { - context.convertValue(context.unwrap(value, field, wrap)) - } - } - }, - ) - } - } - } - .setUnknownFields(mapUnknownFields(message)) - .build() -} - -private fun fieldOptions(field: FieldDescriptor): ProtoktProtos.FieldOptions { - val options = field.toProto().options - - return if (options.hasField(ProtoktProtos.property.descriptor)) { - options.getField(ProtoktProtos.property.descriptor) as ProtoktProtos.FieldOptions - } else if (options.unknownFields.hasField(ProtoktProtos.property.number)) { - ProtoktProtos.FieldOptions.parseFrom( - options.unknownFields.getField(ProtoktProtos.property.number) - .lengthDelimitedList - .last() - ) - } else { - ProtoktProtos.FieldOptions.getDefaultInstance() - } -} - -private fun wrap(field: FieldDescriptor, fieldOptions: ProtoktProtos.FieldOptions) = - getClassName(fieldOptions.wrap, field) - -private fun getClassName(wrap: String, field: FieldDescriptor): String? = - WellKnownTypes.wrapWithWellKnownInterception(wrap.takeIf { it.isNotEmpty() }, field.toProto().typeName) - ?.let { inferClassName(it, resolvePackage(field.file.`package`)) } - ?.let { (pkg, names) -> pkg + "." + names.joinToString(".") } - -private fun convertList( - value: List<*>, - field: FieldDescriptor, - fieldOptions: ProtoktProtos.FieldOptions, - context: RuntimeContext -): List<*> { - val wrap = wrap(field, fieldOptions) - return value.map { - if (wrap == null) { - it?.let(context::convertValue) - } else { - context.convertValue(context.unwrap(it!!, field, wrap)) - } - } -} - -private fun convertMap( - value: Any, - field: FieldDescriptor, - fieldOptions: ProtoktProtos.FieldOptions, - context: RuntimeContext -): List> { - val keyDesc = field.messageType.findFieldByNumber(1) - val valDesc = field.messageType.findFieldByNumber(2) - - val keyDefault = - if (keyDesc.type == Type.MESSAGE) { - null - } else { - keyDesc.defaultValue - } - - val valDefault = - if (valDesc.type == Type.MESSAGE) { - null - } else { - valDesc.defaultValue - } - - val keyWrap = getClassName(fieldOptions.keyWrap, keyDesc) - val valWrap = getClassName(fieldOptions.valueWrap, valDesc) - - val defaultEntry = - MapEntry.newDefaultInstance( - field.messageType, - WireFormat.FieldType.valueOf(keyDesc.type.name), - keyDefault, - WireFormat.FieldType.valueOf(valDesc.type.name), - valDefault - ) as MapEntry - - return (value as Map<*, *>).map { (k, v) -> - defaultEntry.toBuilder() - .setKey( - if (keyWrap == null) { - k?.let(context::convertValue) - } else { - context.convertValue(context.unwrap(k!!, keyDesc, keyWrap)) - } - ) - .setValue( - if (valWrap == null) { - v?.let(context::convertValue) - } else { - context.convertValue(context.unwrap(v!!, valDesc, valWrap)) - } - ) - .build() - } -} - -private fun mapUnknownFields(message: Message): UnknownFieldSet { - val unknownFields = UnknownFieldSet.newBuilder() - - getUnknownFields(message).forEach { (number, field) -> - unknownFields.mergeField( - number.toInt(), - Field.newBuilder() - .apply { - field.varint.forEach { addVarint(it.value.toLong()) } - field.fixed32.forEach { addFixed32(it.value.toInt()) } - field.fixed64.forEach { addFixed64(it.value.toLong()) } - field.lengthDelimited.forEach { addLengthDelimited(UnsafeByteOperations.unsafeWrap(it.value.asReadOnlyBuffer())) } - } - .build() - ) - } - - return unknownFields.build() -} diff --git a/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/RuntimeContext.kt b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/RuntimeContext.kt new file mode 100644 index 000000000..96b5d5b97 --- /dev/null +++ b/protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/RuntimeContext.kt @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2024 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.google.protobuf + +import com.google.protobuf.Descriptors +import com.google.protobuf.Descriptors.FieldDescriptor +import com.google.protobuf.Descriptors.FieldDescriptor.Type +import com.google.protobuf.DynamicMessage +import com.google.protobuf.MapEntry +import com.google.protobuf.UnknownFieldSet +import com.google.protobuf.UnknownFieldSet.Field +import com.google.protobuf.UnsafeByteOperations +import com.google.protobuf.WireFormat +import com.toasttab.protokt.v1.ProtoktProtos +import protokt.v1.Bytes +import protokt.v1.Converter +import protokt.v1.Enum +import protokt.v1.GeneratedMessage +import protokt.v1.Message +import protokt.v1.reflect.ClassLookup +import protokt.v1.reflect.FieldType +import protokt.v1.reflect.WellKnownTypes +import protokt.v1.reflect.inferClassName +import protokt.v1.reflect.resolvePackage +import protokt.v1.reflect.typeName +import kotlin.Any +import kotlin.reflect.full.findAnnotation + +class RuntimeContext internal constructor( + descriptors: Iterable, + private val classLookup: ClassLookup +) { + constructor(descriptors: Iterable) : this(descriptors, ClassLookup(emptyList())) + + internal val descriptorsByTypeName = descriptors.associateBy { it.fullName } + + fun convertValue(value: Any) = + when (value) { + is Enum -> value.value + is UInt -> value.toInt() + is ULong -> value.toLong() + is Message -> toDynamicMessage(value, this) + is Bytes -> UnsafeByteOperations.unsafeWrap(value.asReadOnlyBuffer()) + + // pray + else -> value + } + + internal fun unwrap(value: Any, field: FieldDescriptor, wrap: String): Any { + val proto = field.toProto() + val type = FieldType.from(proto.type) + val converterDetails = + classLookup.converter( + ClassLookup.evaluateProtobufTypeCanonicalName( + proto.typeName, + typeName(proto.typeName, type), + type, + field.name + ), + wrap + ) + + @Suppress("UNCHECKED_CAST") + val converter = converterDetails.converter as Converter + return converter.unwrap(value) + } +} + +private fun toDynamicMessage( + message: Message, + context: RuntimeContext, +): com.google.protobuf.Message { + val descriptor = + context.descriptorsByTypeName + .getValue(message::class.findAnnotation()!!.fullTypeName) + + return DynamicMessage.newBuilder(descriptor) + .apply { + descriptor.fields.forEach { field -> + message.getField(field)?.let { value -> + val fieldOptions = fieldOptions(field) + + setField( + field, + when { + field.type == Type.ENUM -> + if (field.isRepeated) { + (value as List<*>).map { field.enumType.findValueByNumberCreatingIfUnknown(((it as Enum).value)) } + } else { + field.enumType.findValueByNumberCreatingIfUnknown(((value as Enum).value)) + } + + field.isMapField -> + convertMap(value, field, fieldOptions, context) + + field.isRepeated -> + convertList((value as List<*>), field, fieldOptions, context) + + else -> { + val wrap = wrap(field, fieldOptions) + if (wrap == null) { + context.convertValue(value) + } else { + context.convertValue(context.unwrap(value, field, wrap)) + } + } + }, + ) + } + } + } + .setUnknownFields(mapUnknownFields(message)) + .build() +} + +private fun fieldOptions(field: FieldDescriptor): ProtoktProtos.FieldOptions { + val options = field.toProto().options + + return if (options.hasField(ProtoktProtos.property.descriptor)) { + options.getField(ProtoktProtos.property.descriptor) as ProtoktProtos.FieldOptions + } else if (options.unknownFields.hasField(ProtoktProtos.property.number)) { + ProtoktProtos.FieldOptions.parseFrom( + options.unknownFields.getField(ProtoktProtos.property.number) + .lengthDelimitedList + .last() + ) + } else { + ProtoktProtos.FieldOptions.getDefaultInstance() + } +} + +private fun wrap(field: FieldDescriptor, fieldOptions: ProtoktProtos.FieldOptions) = + getClassName(fieldOptions.wrap, field) + +private fun getClassName(wrap: String, field: FieldDescriptor): String? = + WellKnownTypes.wrapWithWellKnownInterception(wrap.takeIf { it.isNotEmpty() }, field.toProto().typeName) + ?.let { inferClassName(it, resolvePackage(field.file.`package`)) } + ?.let { (pkg, names) -> pkg + "." + names.joinToString(".") } + +private fun convertList( + value: List<*>, + field: FieldDescriptor, + fieldOptions: ProtoktProtos.FieldOptions, + context: RuntimeContext +): List<*> { + val wrap = wrap(field, fieldOptions) + return value.map { + if (wrap == null) { + it?.let(context::convertValue) + } else { + context.convertValue(context.unwrap(it!!, field, wrap)) + } + } +} + +private fun convertMap( + value: Any, + field: FieldDescriptor, + fieldOptions: ProtoktProtos.FieldOptions, + context: RuntimeContext +): List> { + val keyDesc = field.messageType.findFieldByNumber(1) + val valDesc = field.messageType.findFieldByNumber(2) + + val keyDefault = + if (keyDesc.type == Type.MESSAGE) { + null + } else { + keyDesc.defaultValue + } + + val valDefault = + if (valDesc.type == Type.MESSAGE) { + null + } else { + valDesc.defaultValue + } + + val keyWrap = getClassName(fieldOptions.keyWrap, keyDesc) + val valWrap = getClassName(fieldOptions.valueWrap, valDesc) + + val defaultEntry = + MapEntry.newDefaultInstance( + field.messageType, + WireFormat.FieldType.valueOf(keyDesc.type.name), + keyDefault, + WireFormat.FieldType.valueOf(valDesc.type.name), + valDefault + ) as MapEntry + + return (value as Map<*, *>).map { (k, v) -> + defaultEntry.toBuilder() + .setKey( + if (keyWrap == null) { + k?.let(context::convertValue) + } else { + context.convertValue(context.unwrap(k!!, keyDesc, keyWrap)) + } + ) + .setValue( + if (valWrap == null) { + v?.let(context::convertValue) + } else { + context.convertValue(context.unwrap(v!!, valDesc, valWrap)) + } + ) + .build() + } +} + +private fun mapUnknownFields(message: Message): UnknownFieldSet { + val unknownFields = UnknownFieldSet.newBuilder() + + getUnknownFields(message).forEach { (number, field) -> + unknownFields.mergeField( + number.toInt(), + Field.newBuilder() + .apply { + field.varint.forEach { addVarint(it.value.toLong()) } + field.fixed32.forEach { addFixed32(it.value.toInt()) } + field.fixed64.forEach { addFixed64(it.value.toLong()) } + field.lengthDelimited.forEach { addLengthDelimited(UnsafeByteOperations.unsafeWrap(it.value.asReadOnlyBuffer())) } + } + .build() + ) + } + + return unknownFields.build() +} diff --git a/testing/interop/build.gradle.kts b/testing/interop/build.gradle.kts index ec02d0cee..036ad70f8 100644 --- a/testing/interop/build.gradle.kts +++ b/testing/interop/build.gradle.kts @@ -39,6 +39,7 @@ dependencies { testImplementation(project(":protokt-reflect")) testImplementation(project(":testing:protobuf-java")) testImplementation(kotlin("reflect")) + testImplementation(libs.classgraph) testImplementation(libs.jackson) testImplementation(libs.protobuf.java) } diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt index dded6882d..38b4f19a0 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/DynamicMessageTest.kt @@ -18,7 +18,6 @@ package protokt.v1.testing import com.google.common.truth.Truth.assertThat import org.junit.jupiter.api.Test import protokt.v1.Message -import protokt.v1.google.protobuf.RuntimeContext import protokt.v1.google.protobuf.toDynamicMessage import java.net.InetAddress import java.net.InetSocketAddress @@ -140,7 +139,7 @@ class DynamicMessageTest { } private fun verifyMessage(message: Message) { - val dynamicMessage = message.toDynamicMessage(RuntimeContext.getContextReflectively()) + val dynamicMessage = message.toDynamicMessage(getContextReflectively()) assertThat(dynamicMessage.serializedSize).isEqualTo(message.messageSize()) assertThat(dynamicMessage.toByteArray()).isEqualTo(message.serialize()) diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt index dcc8b6e8b..99cb2d458 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/ProtoktReflectTest.kt @@ -20,13 +20,12 @@ import com.google.protobuf.Descriptors.FieldDescriptor import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.MethodSource import proto3_unittest.UnittestProto3 -import protokt.v1.google.protobuf.RuntimeContext import protokt.v1.google.protobuf.getField import protokt.v1.google.protobuf.hasField import protokt.v1.proto3_unittest.TestAllTypes class ProtoktReflectTest { - private val context = RuntimeContext.getContextReflectively() + private val context = getContextReflectively() @ParameterizedTest @MethodSource("optionalDescriptors") diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt new file mode 100644 index 000000000..a5a240d92 --- /dev/null +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 Toast, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package protokt.v1.testing + +import com.google.protobuf.DescriptorProtos +import com.google.protobuf.Descriptors +import io.github.classgraph.ClassGraph +import protokt.v1.GeneratedFileDescriptor +import protokt.v1.google.protobuf.FileDescriptor +import protokt.v1.google.protobuf.RuntimeContext +import kotlin.reflect.KClass +import kotlin.reflect.full.declaredMemberProperties + +fun getContextReflectively() = + RuntimeContext(getDescriptors()) + +private fun getDescriptors() = + ClassGraph() + .enableAnnotationInfo() + .scan() + .use { + it.getClassesWithAnnotation(GeneratedFileDescriptor::class.java) + .map { info -> + @Suppress("UNCHECKED_CAST") + info.loadClass().kotlin as KClass + } + } + .asSequence() + .map { klassWithDescriptor -> + klassWithDescriptor + .declaredMemberProperties + .single { it.returnType.classifier == FileDescriptor::class } + .get(klassWithDescriptor.objectInstance!!) as FileDescriptor + } + .flatMap { it.toProtobufJavaDescriptor().messageTypes } + .flatMap(::collectDescriptors) + .asIterable() + +private fun collectDescriptors(descriptor: Descriptors.Descriptor): Iterable = + listOf(descriptor) + descriptor.nestedTypes.flatMap(::collectDescriptors) + +private fun FileDescriptor.toProtobufJavaDescriptor(): Descriptors.FileDescriptor = + Descriptors.FileDescriptor.buildFrom( + DescriptorProtos.FileDescriptorProto.parseFrom(proto.serialize()), + dependencies.map { it.toProtobufJavaDescriptor() }.toTypedArray(), + true, + ) From 5eaae73f3057e0226e0b091d562dfc19f8f1a9ec Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 8 May 2024 11:19:34 -0400 Subject: [PATCH 36/38] apidump --- protokt-reflect/api/protokt-reflect.api | 5 ----- 1 file changed, 5 deletions(-) diff --git a/protokt-reflect/api/protokt-reflect.api b/protokt-reflect/api/protokt-reflect.api index d4f0fb632..d951bdb00 100644 --- a/protokt-reflect/api/protokt-reflect.api +++ b/protokt-reflect/api/protokt-reflect.api @@ -1239,12 +1239,7 @@ public final class protokt/v1/google/protobuf/Messages { } public final class protokt/v1/google/protobuf/RuntimeContext { - public static final field Companion Lprotokt/v1/google/protobuf/RuntimeContext$Companion; public fun (Ljava/lang/Iterable;)V public final fun convertValue (Ljava/lang/Object;)Ljava/lang/Object; } -public final class protokt/v1/google/protobuf/RuntimeContext$Companion { - public final fun getContextReflectively ()Lprotokt/v1/google/protobuf/RuntimeContext; -} - From c7e643e1e14926f20879422b4bd0636be989a334 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 8 May 2024 11:49:13 -0400 Subject: [PATCH 37/38] update readme --- README.md | 236 ++++++++++++------ .../protokt/v1/testing/RuntimeContextUtil.kt | 2 +- 2 files changed, 159 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 1650ab5e4..c022b67ba 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Supports only version 3 of the Protocol Buffers language. ### Features - Idiomatic and concise [Kotlin builder DSL](#generated-code) -- Protokt-specific options: [non-null types](#non-null-fields), +- Protokt-specific options: [non-null types (dangerous)](#non-null-fields), [wrapper types](#wrapper-types), [interface implementation](#interface-implementation), and more @@ -313,7 +313,7 @@ allowing representation of unknown values. public sealed class PhoneType( override val `value`: Int, override val name: String -) : KtEnum() { +) : Enum() { public object MOBILE : PhoneType(0, "MOBILE") public object HOME : PhoneType(1, "HOME") @@ -324,7 +324,7 @@ public sealed class PhoneType( `value`: Int ) : PhoneType(value, "UNRECOGNIZED") - public companion object Deserializer : KtEnumDeserializer { + public companion object Deserializer : EnumReader { override fun from(`value`: Int): PhoneType = when (value) { 0 -> MOBILE @@ -343,6 +343,74 @@ all values [prefixed with the enum type name](https://developers.google.com/protocol-buffers/docs/style#enums) will have that prefix stripped in their Kotlin representations. +### Reflection + +#### Descriptors + +Protokt generates and embeds descriptors for protobuf files in its output by default. Generation can be disabled +while using the lite runtime: + +```kotlin +protokt { + generate { + descriptors = false + } +} +``` + +#### Interop with `protobuf-java` + +Protokt includes [utilities](protokt-reflect/src/jvmMain/kotlin/protokt/v1/google/protobuf/Messages.kt) to reflectively +(i.e., no-copy) convert a `protokt.v1.Message` to a `com.google.protobuf.Message`. Conversion requires that you specify +the RuntimeContext of your proto files. If you would like to scan your classpath for all known descriptors at runtime, +you may use Protokt's `GeneratedFileDescriptor` annotation [to do so](testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt): + +```kotlin +import com.google.protobuf.DescriptorProtos +import com.google.protobuf.Descriptors +import io.github.classgraph.ClassGraph +import protokt.v1.GeneratedFileDescriptor +import protokt.v1.google.protobuf.FileDescriptor +import protokt.v1.google.protobuf.RuntimeContext +import kotlin.reflect.KClass +import kotlin.reflect.full.declaredMemberProperties + +fun getContextReflectively() = + RuntimeContext(getDescriptors()) + +private fun getDescriptors() = + ClassGraph() + .enableAnnotationInfo() + .scan() + .use { + it.getClassesWithAnnotation(GeneratedFileDescriptor::class.java) + .map { info -> + @Suppress("UNCHECKED_CAST") + info.loadClass().kotlin as KClass + } + } + .asSequence() + .map { klassWithDescriptor -> + klassWithDescriptor + .declaredMemberProperties + .single { it.returnType.classifier == FileDescriptor::class } + .get(klassWithDescriptor.objectInstance!!) as FileDescriptor + } + .flatMap { it.toProtobufJavaDescriptor().messageTypes } + .flatMap(::collectDescriptors) + .asIterable() + +private fun collectDescriptors(descriptor: Descriptors.Descriptor): Iterable = + listOf(descriptor) + descriptor.nestedTypes.flatMap(::collectDescriptors) + +private fun FileDescriptor.toProtobufJavaDescriptor(): Descriptors.FileDescriptor = + Descriptors.FileDescriptor.buildFrom( + DescriptorProtos.FileDescriptorProto.parseFrom(proto.serialize()), + dependencies.map { it.toProtobufJavaDescriptor() }.toTypedArray(), + true + ) +``` + ### Other Notes - `optimize_for` is ignored. @@ -417,30 +485,34 @@ object InstantConverter : AbstractConverter() { ``` ```kotlin -@V1KtGeneratedMessage("protokt.v1.testing.Wrappers") -@RtKtGeneratedMessage("protokt.v1.testing.Wrappers") -public class Wrappers private constructor( - public val instant: Instant, +@GeneratedMessage("protokt.v1.testing.WrapperMessage") +public class WrapperMessage private constructor( + @GeneratedProperty(1) + public val instant: Instant?, public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() -) : AbstractKtMessage() { - override val messageSize: Int by lazy { messageSize() } - - private fun messageSize(): Int { +) : AbstractMessage() { + private val `$messageSize`: Int by lazy { var result = 0 - result += sizeOf(50u) + sizeOf(InstantConverter.unwrap(instant)) + if (instant != null) { + result += sizeOf(10u) + sizeOf(InstantConverter.unwrap(instant)) + } result += unknownFields.size() - return result + result } - override fun serialize(serializer: KtMessageSerializer) { - serializer.writeTag(50u).write(InstantConverter.unwrap(instant)) - serializer.writeUnknown(unknownFields) + override fun messageSize(): Int = `$messageSize` + + override fun serialize(writer: Writer) { + if (instant != null) { + writer.writeTag(10u).write(InstantConverter.unwrap(instant)) + } + writer.writeUnknown(unknownFields) } override fun equals(other: Any?): Boolean = - other is Wrappers && - other.instant == instant && - other.unknownFields == unknownFields + other is WrapperMessage && + other.instant == instant && + other.unknownFields == unknownFields override fun hashCode(): Int { var result = unknownFields.hashCode() @@ -449,60 +521,54 @@ public class Wrappers private constructor( } override fun toString(): String = - "Wrappers(" + - "instant=$instant" + - if (unknownFields.isEmpty()) ")" else ", unknownFields=$unknownFields)" + "WrapperMessage(" + + "instant=$instant" + + if (unknownFields.isEmpty()) ")" else ", unknownFields=$unknownFields)" - public fun copy(builder: Builder.() -> Unit): Wrappers = + public fun copy(builder: Builder.() -> Unit): WrapperMessage = Builder().apply { - instant = this@Wrappers.instant - unknownFields = this@Wrappers.unknownFields + instant = this@WrapperMessage.instant + unknownFields = this@WrapperMessage.unknownFields builder() }.build() - @KtBuilderDsl + @BuilderDsl public class Builder { public var instant: Instant? = null public var unknownFields: UnknownFieldSet = UnknownFieldSet.empty() - public fun build(): Wrappers = - Wrappers( - requireNotNull(instant) { - StringBuilder("instant") - .append(" specified nonnull with (protokt.property).non_null but was null") - }, + public fun build(): WrapperMessage = + WrapperMessage( + instant, unknownFields ) - } + } - public companion object Deserializer : AbstractKtDeserializer() { + public companion object Deserializer : AbstractDeserializer() { @JvmStatic - override fun deserialize(deserializer: KtMessageDeserializer): Wrappers { + override fun deserialize(reader: Reader): WrapperMessage { var instant: Instant? = null var unknownFields: UnknownFieldSet.Builder? = null while (true) { - when (deserializer.readTag()) { - 0 -> return Wrappers( - requireNotNull(instant) { - StringBuilder("instant") - .append(" specified nonnull with (protokt.property).non_null but was null") - }, + when (reader.readTag()) { + 0u -> return WrapperMessage( + instant, UnknownFieldSet.from(unknownFields) ) - 50 -> instant = InstantConverter.wrap(deserializer.readMessage(Timestamp)) + 10u -> instant = InstantConverter.wrap(reader.readMessage(Timestamp)) else -> unknownFields = (unknownFields ?: UnknownFieldSet.Builder()).also { - it.add(deserializer.readUnknown()) + it.add(reader.readUnknown()) } } } } @JvmStatic - public operator fun invoke(dsl: Builder.() -> Unit): Wrappers = Builder().apply(dsl).build() + public operator fun invoke(dsl: Builder.() -> Unit): WrapperMessage = Builder().apply(dsl).build() } } ``` @@ -653,6 +719,8 @@ message NonNullSampleMessage { Note that deserialization of a message with a non-nullable field will fail if the message being decoded does not contain an instance of the required field. +This functionality will likely be removed. + ### Interface implementation #### Messages @@ -757,7 +825,7 @@ message MyObjectWithConfig { } message ServerSpecified { - option (protokt.v1.class).implements = "Config"; + option (protokt.v1.class).implements = "com.toasttab.example.Config"; int32 version = 1; @@ -766,7 +834,7 @@ message ServerSpecified { } message ClientResolved { - option (protokt.v1.class).implements = "Config by config"; + option (protokt.v1.class).implements = "com.toasttab.example.Config by config"; ServerSpecified config = 1 [ (protokt.v1.property).non_null = true @@ -781,46 +849,56 @@ message ClientResolved { Protokt will generate: ```kotlin -@V1KtGeneratedMessage("toasttab.example.MyObjectWithConfig") -@RtKtGeneratedMessage("toasttab.example.MyObjectWithConfig") +@GeneratedMessage("toasttab.example.MyObjectWithConfig") public class MyObjectWithConfig private constructor( - public val id: UUID, + @GeneratedProperty(1) + public val id: UUID?, public val config: Config, public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() -) : AbstractKtMessage() { - // methods omitted +) : AbstractMessage() { + + // methods and builders omitted - public sealed class Config : ExampleConfig { + public sealed class Config : com.toasttab.example.Config { public data class ServerSpecified( + @GeneratedProperty(2) public val serverSpecified: protokt.v1.toasttab.example.ServerSpecified - ) : Config(), ExampleConfig by serverSpecified + ) : Config(), com.toasttab.example.Config by serverSpecified public data class ClientResolved( + @GeneratedProperty(3) public val clientResolved: protokt.v1.toasttab.example.ClientResolved - ) : Config(), ExampleConfig by clientResolved + ) : Config(), com.toasttab.example.Config by clientResolved } +} - @V1KtGeneratedMessage("toasttab.example.ServerSpecified") - @RtKtGeneratedMessage("toasttab.example.ServerSpecified") - public class ServerSpecified private constructor( - override val version: Int, - public val serverRegistry: String, - public val serverName: String, - public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() - ) : AbstractKtMessage(), ExampleConfig { - // methods omitted - } +@GeneratedMessage("toasttab.example.ServerSpecified") +public class ServerSpecified private constructor( + @GeneratedProperty(1) + override val version: Int, + @GeneratedProperty(2) + public val serverRegistry: String, + @GeneratedProperty(3) + public val serverName: String, + public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() +) : AbstractMessage(), Config { + // methods and builders omitted - @V1KtGeneratedMessage("toasttab.example.ClientResolved") - @RtKtGeneratedMessage("toasttab.example.ClientResolved") - public class ClientResolved private constructor( - public val config: ServerSpecified, - public val lastKnownAddress: InetAddress, - public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() - ) : AbstractKtMessage(), Config by config { - // methods omitted - } +} + +@GeneratedMessage("toasttab.example.ClientResolved") +public class ClientResolved private constructor( + @GeneratedProperty(1) + public val config: ServerSpecified, + @GeneratedProperty(2) + public val lastKnownAddress: InetAddress?, + public val unknownFields: UnknownFieldSet = UnknownFieldSet.empty() +) : AbstractMessage(), Config by config { + + // methods and builders omitted + +} ``` A MyObjectWithConfig.Config instance can be queried for its version without @@ -832,12 +910,14 @@ fun printVersion(config: MyObjectWithConfig.Config) { } ``` -This pattern can be dangerous: since the oneof must be marked non-nullable, you +This pattern is dangerous: since the oneof must be marked non-nullable, you cannot compatibly add new implementing fields to a producer before a consumer is updated with the new generated code. The old consumer will attempt to deserialize the new field as an unknown field and the non-null assertion on the oneof field during the constructor call will fail. +This functionality will likely be removed. + ### BytesSlice When reading messages that contain other serialized messages as `bytes` fields, @@ -863,10 +943,10 @@ when the gRPC generation options are enabled: ```groovy protokt { - generate { - grpcDescriptors = true - grpcKotlinStubs = true - } + generate { + grpcDescriptors = true + grpcKotlinStubs = true + } } ``` diff --git a/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt b/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt index a5a240d92..dff5742a0 100644 --- a/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt +++ b/testing/interop/src/test/kotlin/protokt/v1/testing/RuntimeContextUtil.kt @@ -56,5 +56,5 @@ private fun FileDescriptor.toProtobufJavaDescriptor(): Descriptors.FileDescripto Descriptors.FileDescriptor.buildFrom( DescriptorProtos.FileDescriptorProto.parseFrom(proto.serialize()), dependencies.map { it.toProtobufJavaDescriptor() }.toTypedArray(), - true, + true ) From bc8cea8988e32ebff7147869d7e9adb5c6d37cc2 Mon Sep 17 00:00:00 2001 From: Andrew Parmet Date: Wed, 8 May 2024 11:50:36 -0400 Subject: [PATCH 38/38] space --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c022b67ba..88b3a8410 100644 --- a/README.md +++ b/README.md @@ -945,7 +945,7 @@ when the gRPC generation options are enabled: protokt { generate { grpcDescriptors = true - grpcKotlinStubs = true + grpcKotlinStubs = true } } ```