diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a9ebe1f94..c3affbdef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ Change Log Unreleased ---------- +Version 5.3.6 +--------------------- + +_2025-08-05_ + +### CLI + +* New CLI option `--ignore_unused_roots_and_prunes` (#3354) + +### JVM + +* Fix: Handle negative hexadecimal in default values (#3355) +* Optimization: Avoid copying of repeated and map types when mutableTypes are being used (#3352 by [Rahul Ravikumar][tikurahul]) + +### Swift + +* Fix: Properly disambiguate OneOf enum if it has the same name as enclosing type (#3350 by [Dimitris Koutsogiorgas][dnkoutso]) + Version 5.3.5 --------------------- diff --git a/gradle.properties b/gradle.properties index 18b20b3add..df26e9486a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ org.gradle.jvmargs='-Dfile.encoding=UTF-8' GROUP=com.squareup.wire -VERSION_NAME=5.3.5 +VERSION_NAME=5.3.6 # Publishing SHA 256 and 512 hashes of maven-metadata is not supported by Sonatype and Nexus. # See https://github.com/gradle/gradle/issues/11308 and https://issues.sonatype.org/browse/NEXUS-21802 diff --git a/wire-compiler/api/wire-compiler.api b/wire-compiler/api/wire-compiler.api index 3c4adee9a2..fa8a348576 100644 --- a/wire-compiler/api/wire-compiler.api +++ b/wire-compiler/api/wire-compiler.api @@ -8,7 +8,7 @@ public final class com/squareup/wire/DryRunFileSystem : okio/ForwardingFileSyste public final class com/squareup/wire/WireCompiler { public static final field CODE_GENERATED_BY_WIRE Ljava/lang/String; public static final field Companion Lcom/squareup/wire/WireCompiler$Companion; - public synthetic fun (Lokio/FileSystem;Lcom/squareup/wire/WireLogger;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/Map;ZZZZZZZZIZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ZLjava/lang/String;ZZZZLcom/squareup/wire/kotlin/EnumMode;Ljava/util/List;Ljava/util/Map;Ljava/util/List;IILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun (Lokio/FileSystem;Lcom/squareup/wire/WireLogger;Ljava/util/List;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;ZLjava/util/Map;ZZZZZZZZIZZZLcom/squareup/wire/kotlin/RpcCallStyle;Lcom/squareup/wire/kotlin/RpcRole;ZLjava/lang/String;ZZZZLcom/squareup/wire/kotlin/EnumMode;Ljava/util/List;Ljava/util/Map;Ljava/util/List;IILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun compile ()V public static final fun forArgs (Ljava/nio/file/FileSystem;Lcom/squareup/wire/WireLogger;[Ljava/lang/String;)Lcom/squareup/wire/WireCompiler; public static final fun forArgs (Lokio/FileSystem;Lcom/squareup/wire/WireLogger;[Ljava/lang/String;)Lcom/squareup/wire/WireCompiler; @@ -44,6 +44,7 @@ public final class com/squareup/wire/WireCompiler { public final fun getOpaqueTypes ()Ljava/util/List; public final fun getPermitPackageCycles ()Z public final fun getProtoPaths ()Ljava/util/List; + public final fun getRejectUnusedRootsOrPrunes ()Z public final fun getSchemaHandlerFactoryClass ()Ljava/lang/String; public final fun getSourceFileNames ()Ljava/util/List; public final fun getSwiftExclusive ()Z diff --git a/wire-compiler/src/main/java/com/squareup/wire/WireCompiler.kt b/wire-compiler/src/main/java/com/squareup/wire/WireCompiler.kt index 2b130afba0..fa55747a77 100644 --- a/wire-compiler/src/main/java/com/squareup/wire/WireCompiler.kt +++ b/wire-compiler/src/main/java/com/squareup/wire/WireCompiler.kt @@ -128,6 +128,7 @@ class WireCompiler internal constructor( val sourceFileNames: List, val treeShakingRoots: List, val treeShakingRubbish: List, + val rejectUnusedRootsOrPrunes: Boolean, val modules: Map, val emitAndroid: Boolean, val emitAndroidAnnotations: Boolean, @@ -230,6 +231,7 @@ class WireCompiler internal constructor( permitPackageCycles = permitPackageCycles, loadExhaustively = loadExhaustively, eventListeners = eventListenerFactoryClasses.map { newEventListenerFactory(it).create() }, + rejectUnusedRootsOrPrunes = rejectUnusedRootsOrPrunes, opaqueTypes = opaqueTypes, ) @@ -301,6 +303,7 @@ class WireCompiler internal constructor( private const val KOTLIN_ENUM_MODE = "--kotlin_enum_mode=" private const val CUSTOM_OPTION_FLAG = "--custom_option=" private const val OPAQUE_TYPES_FLAG = "--opaque_types=" + private const val IGNORE_UNUSED_ROOTS_AND_PRUNES = "--ignore_unused_roots_and_prunes" private const val KOTLIN_EXPLICIT_STREAMING_CALLS = "--kotlin_explicit_streaming_calls" @Throws(IOException::class) @@ -369,6 +372,7 @@ class WireCompiler internal constructor( var kotlinExplicitStreamingCalls = false var dryRun = false val customOptions = mutableMapOf() + var rejectUnusedRootsOrPrunes = true val opaqueTypes = mutableListOf() for (arg in args) { @@ -492,6 +496,7 @@ class WireCompiler internal constructor( arg == JAVA_INTEROP -> javaInterop = true arg == EMIT_PROTO_READER_32 -> emitProtoReader32 = true arg == KOTLIN_EXPLICIT_STREAMING_CALLS -> kotlinExplicitStreamingCalls = true + arg == IGNORE_UNUSED_ROOTS_AND_PRUNES -> rejectUnusedRootsOrPrunes = false arg.startsWith("--") -> throw IllegalArgumentException("Unknown argument '$arg'.") else -> sourceFileNames.add(arg) } @@ -547,6 +552,7 @@ class WireCompiler internal constructor( eventListenerFactoryClasses = eventListenerFactoryClasses, customOptions = customOptions, opaqueTypes = opaqueTypes, + rejectUnusedRootsOrPrunes = rejectUnusedRootsOrPrunes, kotlinExplicitStreamingCalls = kotlinExplicitStreamingCalls, ) } diff --git a/wire-compiler/src/test/java/com/squareup/wire/CommandLineOptionsTest.kt b/wire-compiler/src/test/java/com/squareup/wire/CommandLineOptionsTest.kt index e4d62a0c81..8f4c44fbad 100644 --- a/wire-compiler/src/test/java/com/squareup/wire/CommandLineOptionsTest.kt +++ b/wire-compiler/src/test/java/com/squareup/wire/CommandLineOptionsTest.kt @@ -21,6 +21,7 @@ import assertk.assertions.containsOnly import assertk.assertions.hasMessage import assertk.assertions.isEmpty import assertk.assertions.isEqualTo +import assertk.assertions.isFalse import com.squareup.wire.kotlin.EnumMode import com.squareup.wire.schema.WireRun import java.io.File @@ -112,6 +113,9 @@ class CommandLineOptionsTest { compiler = parseArgs("--java_out=.", "--includes=com.example.Foo,com.example.Bar") assertThat(compiler.treeShakingRoots).containsExactly("com.example.Foo", "com.example.Bar") + + compiler = parseArgs("--java_out=.", "--ignore_unused_roots_and_prunes") + assertThat(compiler.rejectUnusedRootsOrPrunes).isFalse() } @Test diff --git a/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePacket.kt b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePacket.kt index e543105c1f..16c46dcd22 100644 --- a/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePacket.kt +++ b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePacket.kt @@ -16,7 +16,6 @@ import com.squareup.wire.ReverseProtoWriter import com.squareup.wire.Syntax.PROTO_2 import com.squareup.wire.WireField import com.squareup.wire.`internal`.JvmField -import com.squareup.wire.`internal`.immutableCopyOf import kotlin.Any import kotlin.Boolean import kotlin.Deprecated @@ -38,17 +37,15 @@ public class MutablePacket( schemaIndex = 0, ) public var header_: MutableHeader? = null, - payload: List = emptyList(), - override var unknownFields: ByteString = ByteString.EMPTY, -) : Message(ADAPTER, unknownFields) { @field:WireField( tag = 2, adapter = "squareup.wire.mutable.MutablePayload#ADAPTER", label = WireField.Label.REPEATED, schemaIndex = 1, ) - public var payload: List = immutableCopyOf("payload", payload) - + public var payload: List = emptyList(), + override var unknownFields: ByteString = ByteString.EMPTY, +) : Message(ADAPTER, unknownFields) { @Deprecated( message = "Shouldn't be used in Kotlin", level = DeprecationLevel.HIDDEN, diff --git a/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePayload.kt b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePayload.kt index 2b363717cc..8ff0258de1 100644 --- a/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePayload.kt +++ b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePayload.kt @@ -19,7 +19,6 @@ import com.squareup.wire.WireEnum import com.squareup.wire.WireField import com.squareup.wire.`internal`.JvmField import com.squareup.wire.`internal`.JvmStatic -import com.squareup.wire.`internal`.immutableCopyOf import com.squareup.wire.`internal`.sanitize import kotlin.Any import kotlin.Boolean @@ -53,17 +52,15 @@ public class MutablePayload( schemaIndex = 2, ) public var type: Type? = null, - footers: List = emptyList(), - override var unknownFields: ByteString = ByteString.EMPTY, -) : Message(ADAPTER, unknownFields) { @field:WireField( tag = 4, adapter = "com.squareup.wire.ProtoAdapter#STRING", label = WireField.Label.REPEATED, schemaIndex = 3, ) - public var footers: List = immutableCopyOf("footers", footers) - + public var footers: List = emptyList(), + override var unknownFields: ByteString = ByteString.EMPTY, +) : Message(ADAPTER, unknownFields) { @Deprecated( message = "Shouldn't be used in Kotlin", level = DeprecationLevel.HIDDEN, diff --git a/wire-gradle-plugin/src/test/projects/configuration-cache-failure/gradle.properties b/wire-gradle-plugin/src/test/projects/configuration-cache-failure/gradle.properties index 781429b483..da466d1d3a 100644 --- a/wire-gradle-plugin/src/test/projects/configuration-cache-failure/gradle.properties +++ b/wire-gradle-plugin/src/test/projects/configuration-cache-failure/gradle.properties @@ -1,4 +1,4 @@ org.gradle.caching=false org.gradle.unsafe.configuration-cache=true org.gradle.configuration-cache=true -VERSION_NAME=5.3.5 +VERSION_NAME=5.3.6 diff --git a/wire-gradle-plugin/src/test/projects/kotlin-multiplatform/gradle.properties b/wire-gradle-plugin/src/test/projects/kotlin-multiplatform/gradle.properties index b1f6d7d505..3a2c8af887 100644 --- a/wire-gradle-plugin/src/test/projects/kotlin-multiplatform/gradle.properties +++ b/wire-gradle-plugin/src/test/projects/kotlin-multiplatform/gradle.properties @@ -1 +1 @@ -VERSION_NAME=5.3.5 +VERSION_NAME=5.3.6 diff --git a/wire-gradle-plugin/src/test/projects/lazy-configuration-resolution/gradle.properties b/wire-gradle-plugin/src/test/projects/lazy-configuration-resolution/gradle.properties index 2c211d2d57..35799d9ab8 100644 --- a/wire-gradle-plugin/src/test/projects/lazy-configuration-resolution/gradle.properties +++ b/wire-gradle-plugin/src/test/projects/lazy-configuration-resolution/gradle.properties @@ -1,2 +1,2 @@ org.gradle.configureondemand=true -VERSION_NAME=5.3.5 +VERSION_NAME=5.3.6 diff --git a/wire-java-generator/src/test/java/com/squareup/wire/java/JavaGeneratorTest.java b/wire-java-generator/src/test/java/com/squareup/wire/java/JavaGeneratorTest.java index 40191e77ca..8f5033a559 100644 --- a/wire-java-generator/src/test/java/com/squareup/wire/java/JavaGeneratorTest.java +++ b/wire-java-generator/src/test/java/com/squareup/wire/java/JavaGeneratorTest.java @@ -502,6 +502,8 @@ public void defaultValues() throws IOException { + " optional double f = 6 [default = -inf ];\n" + " optional double g = 7 [default = nan ];\n" + " optional double h = 8 [default = -nan ];\n" + + " optional int32 i = 9 [default = -0x80000000\n];\n" + + " optional int64 j = 10 [default = -0x7FFFFFFF\n];\n" + "}\n") .build(); String code = new JavaWithProfilesGenerator(schema).generateJava("Message"); @@ -513,6 +515,8 @@ public void defaultValues() throws IOException { assertThat(code).contains(" public static final Double DEFAULT_F = Double.NEGATIVE_INFINITY;"); assertThat(code).contains(" public static final Double DEFAULT_G = Double.NaN;"); assertThat(code).contains(" public static final Double DEFAULT_H = Double.NaN;"); + assertThat(code).contains(" public static final Integer DEFAULT_I = -2147483648;"); + assertThat(code).contains(" public static final Long DEFAULT_J = -2147483647L;"); } @Test diff --git a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt index b2763324bd..ef15cc4ac6 100644 --- a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt +++ b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt @@ -1251,12 +1251,17 @@ class KotlinGenerator private constructor( CodeBlock.of(if (buildersOnly) "builder.$fieldName" else fieldName) } field.isRepeated || field.isMap -> { - CodeBlock.of( - if (buildersOnly) "%M(%S, builder.%N)" else "%M(%S, %N)", - MemberName("com.squareup.wire.internal", "immutableCopyOf"), - fieldName, - fieldName, - ) + if (mutableTypes) { + // For mutable types, don't bother using immutableCopyOf(...) + CodeBlock.of("%N", fieldName) + } else { + CodeBlock.of( + if (buildersOnly) "%M(%S, builder.%N)" else "%M(%S, %N)", + MemberName("com.squareup.wire.internal", "immutableCopyOf"), + fieldName, + fieldName, + ) + } } !field.isRepeated && !field.isMap && field.isRequired && buildersOnly -> { CodeBlock.of("builder.%N!!", fieldName) diff --git a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt index 45a2426bde..f2a81da509 100644 --- a/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt +++ b/wire-kotlin-generator/src/test/java/com/squareup/wire/kotlin/KotlinGeneratorTest.kt @@ -136,6 +136,8 @@ class KotlinGeneratorTest { | optional double n = 14 [default = -inf]; | optional double o = 15 [default = nan]; | optional double p = 16 [default = -nan]; + | optional int32 q = 17 [default = -0x80000000]; + | optional int64 r = 18 [default = -0x7FFFFFFF]; |} """.trimMargin(), ) @@ -160,6 +162,8 @@ class KotlinGeneratorTest { assertThat(code).contains("const val DEFAULT_N: Double = Double.NEGATIVE_INFINITY") assertThat(code).contains("const val DEFAULT_O: Double = Double.NaN") assertThat(code).contains("const val DEFAULT_P: Double = Double.NaN") + assertThat(code).contains("const val DEFAULT_Q: Int = Int.MIN_VALUE") + assertThat(code).contains("const val DEFAULT_R: Long = -2_147_483_647L") } @Test fun nameAllocatorIsUsed() { diff --git a/wire-schema/src/jvmMain/kotlin/com/squareup/wire/schema/internal/JvmLanguages.kt b/wire-schema/src/jvmMain/kotlin/com/squareup/wire/schema/internal/JvmLanguages.kt index 97ac5ad8b3..15fb43c0d8 100644 --- a/wire-schema/src/jvmMain/kotlin/com/squareup/wire/schema/internal/JvmLanguages.kt +++ b/wire-schema/src/jvmMain/kotlin/com/squareup/wire/schema/internal/JvmLanguages.kt @@ -119,10 +119,15 @@ fun optionValueToInt(value: Any?): Int { if (value == null) return 0 val string = value.toString() + val negativeSign = if (string.startsWith('-')) { "-" } else { "" } return when { // Hexadecimal. - string.startsWith("0x") || string.startsWith("0X") -> string.substring("0x".length).toInt(16) + string.startsWith("${negativeSign}0x", ignoreCase = true) -> + buildString { + append(negativeSign) + append(string.substring("${negativeSign}0x".length)) + }.toInt(16) // Octal. string.startsWith("0") && string != "0" -> error("Octal literal unsupported: $value") @@ -136,10 +141,15 @@ fun optionValueToLong(value: Any?): Long { if (value == null) return 0L val string = value.toString() + val negativeSign = if (string.startsWith('-')) { "-" } else { "" } return when { // Hexadecimal. - string.startsWith("0x") || string.startsWith("0X") -> string.substring("0x".length).toLong(16) + string.startsWith("${negativeSign}0x", ignoreCase = true) -> + buildString { + append(negativeSign) + append(string.substring("${negativeSign}0x".length)) + }.toLong(16) // Octal. string.startsWith("0") && string != "0" -> error("Octal literal unsupported: $value") diff --git a/wire-swift-generator/src/main/java/com/squareup/wire/swift/SwiftGenerator.kt b/wire-swift-generator/src/main/java/com/squareup/wire/swift/SwiftGenerator.kt index 5c8263be2a..8333ccbd09 100644 --- a/wire-swift-generator/src/main/java/com/squareup/wire/swift/SwiftGenerator.kt +++ b/wire-swift-generator/src/main/java/com/squareup/wire/swift/SwiftGenerator.kt @@ -626,7 +626,7 @@ class SwiftGenerator private constructor( addStatement("var %N: %T = %L", field.safeName, localType, initializer) } type.oneOfs.forEach { oneOf -> - val enumName = oneOfEnumNames.getValue(oneOf) + val enumName = oneOfSafeDeclaredTypeName(oneOf, type, oneOfEnumNames) addStatement("var %N: %T = nil", oneOf.name, enumName.makeOptional()) } if (type.declaredFieldsAndOneOfFields.isNotEmpty()) { @@ -1063,7 +1063,7 @@ class SwiftGenerator private constructor( } if (includeOneOfs) { type.oneOfs.forEach { oneOf -> - val enumName = oneOfEnumNames.getValue(oneOf).makeOptional() + val enumName = oneOfSafeDeclaredTypeName(oneOf, type, oneOfEnumNames) addParameter( ParameterSpec.builder(oneOf.name, enumName) .defaultValue("nil") @@ -1360,7 +1360,7 @@ class SwiftGenerator private constructor( } type.oneOfs.forEach { oneOf -> - val enumName = oneOfEnumNames.getValue(oneOf) + val enumName = oneOfSafeDeclaredTypeName(oneOf, type, oneOfEnumNames) addProperty( PropertySpec.varBuilder(oneOf.name, enumName.makeOptional(), PUBLIC) @@ -1515,7 +1515,7 @@ class SwiftGenerator private constructor( } type.oneOfs.forEach { oneOf -> - val enumName = oneOfEnumNames.getValue(oneOf) + val enumName = oneOfSafeDeclaredTypeName(oneOf, type, oneOfEnumNames) addProperty( PropertySpec.varBuilder(oneOf.name, enumName.makeOptional(), PUBLIC) @@ -1560,7 +1560,7 @@ class SwiftGenerator private constructor( fileMembers: MutableList, ) { type.oneOfs.forEach { oneOf -> - val enumName = oneOfEnumNames.getValue(oneOf) + val enumName = oneOfSafeDeclaredTypeName(oneOf, type, oneOfEnumNames) // TODO use a NameAllocator val writer = if (oneOf.fields.any { it.name == "protoWriter" }) "_protoWriter" else "protoWriter" @@ -1649,6 +1649,27 @@ class SwiftGenerator private constructor( } } + private fun oneOfSafeDeclaredTypeName( + oneOf: OneOf, + type: MessageType, + oneOfEnumNames: Map, + ): DeclaredTypeName { + var currentType: ProtoType? = type.type + + while (currentType != null) { + val simpleName = currentType.simpleName + if (oneOf.name.equals(simpleName, ignoreCase = true)) { + val oneOfTypeName = oneOfEnumNames.getValue(oneOf) + return oneOfTypeName.peerType("${oneOfTypeName.simpleName}_OneOf") + } + + val enclosingName = currentType.enclosingTypeOrPackage ?: break + currentType = schema.getType(enclosingName)?.type + } + + return oneOfEnumNames.getValue(oneOf) + } + private val ProtoType.encoding: String? get() = when (this) { ProtoType.SINT32, ProtoType.SINT64 -> "signed" diff --git a/wire-tests-swift/no-manifest/src/main/swift/Screen.swift b/wire-tests-swift/no-manifest/src/main/swift/Screen.swift index d57bff4311..21dd6d4c12 100644 --- a/wire-tests-swift/no-manifest/src/main/swift/Screen.swift +++ b/wire-tests-swift/no-manifest/src/main/swift/Screen.swift @@ -4,7 +4,8 @@ import Wire public struct Screen { - public var screen: Screen? + public var screen: Screen_OneOf? + public var view: View? public var unknownFields: UnknownFields = .init() public init(configure: (inout Self) -> Swift.Void = { _ in }) { @@ -44,25 +45,32 @@ extension Screen : ProtoMessage { extension Screen : Proto2Codable { public init(from protoReader: ProtoReader) throws { - var screen: Screen? = nil + var screen: Screen_OneOf? = nil + var view: View? = nil let token = try protoReader.beginMessage() while let tag = try protoReader.nextTag(token: token) { switch tag { - case 1: screen = .oneof_string(try protoReader.decode(String.self)) - case 2: screen = .oneof_int32(try protoReader.decode(Int32.self)) + case 1: screen = .screen_oneof_string(try protoReader.decode(String.self)) + case 2: screen = .screen_oneof_int32(try protoReader.decode(Int32.self)) + case 3: screen = .screen_oneof_sub_message(try protoReader.decode(Screen.SubMessage.self)) + case 4: view = .view_oneof_string(try protoReader.decode(String.self)) default: try protoReader.readUnknownField(tag: tag) } } self.unknownFields = try protoReader.endMessage(token: token) self.screen = screen + self.view = view } public func encode(to protoWriter: ProtoWriter) throws { if let screen = self.screen { try screen.encode(to: protoWriter) } + if let view = self.view { + try view.encode(to: protoWriter) + } try protoWriter.writeUnknownFields(unknownFields) } @@ -73,17 +81,28 @@ extension Screen : Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self) - if let oneof_string = try container.decodeIfPresent(String.self, forKey: "oneofString") { - self.screen = .oneof_string(oneof_string) - } else if let oneof_string = try container.decodeIfPresent(String.self, forKey: "oneof_string") { - self.screen = .oneof_string(oneof_string) - } else if let oneof_int32 = try container.decodeIfPresent(Int32.self, forKey: "oneofInt32") { - self.screen = .oneof_int32(oneof_int32) - } else if let oneof_int32 = try container.decodeIfPresent(Int32.self, forKey: "oneof_int32") { - self.screen = .oneof_int32(oneof_int32) + if let screen_oneof_string = try container.decodeIfPresent(String.self, forKey: "screenOneofString") { + self.screen = .screen_oneof_string(screen_oneof_string) + } else if let screen_oneof_string = try container.decodeIfPresent(String.self, forKey: "screen_oneof_string") { + self.screen = .screen_oneof_string(screen_oneof_string) + } else if let screen_oneof_int32 = try container.decodeIfPresent(Int32.self, forKey: "screenOneofInt32") { + self.screen = .screen_oneof_int32(screen_oneof_int32) + } else if let screen_oneof_int32 = try container.decodeIfPresent(Int32.self, forKey: "screen_oneof_int32") { + self.screen = .screen_oneof_int32(screen_oneof_int32) + } else if let screen_oneof_sub_message = try container.decodeIfPresent(Screen.SubMessage.self, forKey: "screenOneofSubMessage") { + self.screen = .screen_oneof_sub_message(screen_oneof_sub_message) + } else if let screen_oneof_sub_message = try container.decodeIfPresent(Screen.SubMessage.self, forKey: "screen_oneof_sub_message") { + self.screen = .screen_oneof_sub_message(screen_oneof_sub_message) } else { self.screen = nil } + if let view_oneof_string = try container.decodeIfPresent(String.self, forKey: "viewOneofString") { + self.view = .view_oneof_string(view_oneof_string) + } else if let view_oneof_string = try container.decodeIfPresent(String.self, forKey: "view_oneof_string") { + self.view = .view_oneof_string(view_oneof_string) + } else { + self.view = nil + } } public func encode(to encoder: Encoder) throws { @@ -91,8 +110,13 @@ extension Screen : Codable { let preferCamelCase = encoder.protoKeyNameEncodingStrategy == .camelCase switch self.screen { - case .oneof_string(let oneof_string): try container.encode(oneof_string, forKey: preferCamelCase ? "oneofString" : "oneof_string") - case .oneof_int32(let oneof_int32): try container.encode(oneof_int32, forKey: preferCamelCase ? "oneofInt32" : "oneof_int32") + case .screen_oneof_string(let screen_oneof_string): try container.encode(screen_oneof_string, forKey: preferCamelCase ? "screenOneofString" : "screen_oneof_string") + case .screen_oneof_int32(let screen_oneof_int32): try container.encode(screen_oneof_int32, forKey: preferCamelCase ? "screenOneofInt32" : "screen_oneof_int32") + case .screen_oneof_sub_message(let screen_oneof_sub_message): try container.encode(screen_oneof_sub_message, forKey: preferCamelCase ? "screenOneofSubMessage" : "screen_oneof_sub_message") + case Optional.none: break + } + switch self.view { + case .view_oneof_string(let view_oneof_string): try container.encode(view_oneof_string, forKey: preferCamelCase ? "viewOneofString" : "view_oneof_string") case Optional.none: break } } @@ -105,31 +129,322 @@ extension Screen : Codable { */ extension Screen { - public enum Screen { + public enum Screen_OneOf { + + case screen_oneof_string(String) + case screen_oneof_int32(Int32) + case screen_oneof_sub_message(Screen.SubMessage) + + fileprivate func encode(to protoWriter: ProtoWriter) throws { + switch self { + case .screen_oneof_string(let screen_oneof_string): try protoWriter.encode(tag: 1, value: screen_oneof_string) + case .screen_oneof_int32(let screen_oneof_int32): try protoWriter.encode(tag: 2, value: screen_oneof_int32) + case .screen_oneof_sub_message(let screen_oneof_sub_message): try protoWriter.encode(tag: 3, value: screen_oneof_sub_message) + } + } + + } + + public enum View { - case oneof_string(String) - case oneof_int32(Int32) + case view_oneof_string(String) fileprivate func encode(to protoWriter: ProtoWriter) throws { switch self { - case .oneof_string(let oneof_string): try protoWriter.encode(tag: 1, value: oneof_string) - case .oneof_int32(let oneof_int32): try protoWriter.encode(tag: 2, value: oneof_int32) + case .view_oneof_string(let view_oneof_string): try protoWriter.encode(tag: 4, value: view_oneof_string) } } } + public struct SubMessage { + + @ProtoDefaulted + public var string: String? + public var screen: Screen.SubMessage.Screen_OneOf? + public var submessage: Screen.SubMessage.Submessage_OneOf? + public var unknownFields: UnknownFields = .init() + + public init(configure: (inout Self) -> Swift.Void = { _ in }) { + configure(&self) + } + + } + +} + +#if !WIRE_REMOVE_EQUATABLE +extension Screen.Screen_OneOf : Equatable { +} +#endif + +#if !WIRE_REMOVE_HASHABLE +extension Screen.Screen_OneOf : Hashable { +} +#endif + +extension Screen.Screen_OneOf : Sendable { +} + +#if !WIRE_REMOVE_EQUATABLE +extension Screen.View : Equatable { +} +#endif + +#if !WIRE_REMOVE_HASHABLE +extension Screen.View : Hashable { +} +#endif + +extension Screen.View : Sendable { } #if !WIRE_REMOVE_EQUATABLE -extension Screen.Screen : Equatable { +extension Screen.SubMessage : Equatable { } #endif #if !WIRE_REMOVE_HASHABLE -extension Screen.Screen : Hashable { +extension Screen.SubMessage : Hashable { } #endif -extension Screen.Screen : Sendable { +extension Screen.SubMessage : Sendable { +} + +extension Screen.SubMessage : ProtoDefaultedValue { + + public static var defaultedValue: Self { + .init() + } +} + +extension Screen.SubMessage : ProtoMessage { + + public static func protoMessageTypeURL() -> String { + return "type.googleapis.com/squareup.protos.kotlin.swift_modules.Screen.SubMessage" + } + } + +extension Screen.SubMessage : Proto2Codable { + + public init(from protoReader: ProtoReader) throws { + var string: String? = nil + var screen: Screen.SubMessage.Screen_OneOf? = nil + var submessage: Screen.SubMessage.Submessage_OneOf? = nil + + let token = try protoReader.beginMessage() + while let tag = try protoReader.nextTag(token: token) { + switch tag { + case 1: string = try protoReader.decode(String.self) + case 2: screen = .submessage_screen_oneof_string(try protoReader.decode(String.self)) + case 3: submessage = .submessage_oneof_string(try protoReader.decode(String.self)) + case 4: submessage = .submessage_oneof_nested_sub_message(try protoReader.decode(Screen.SubMessage.NestedSubMessage.self)) + default: try protoReader.readUnknownField(tag: tag) + } + } + self.unknownFields = try protoReader.endMessage(token: token) + + self._string.wrappedValue = string + self.screen = screen + self.submessage = submessage + } + + public func encode(to protoWriter: ProtoWriter) throws { + try protoWriter.encode(tag: 1, value: self.string) + if let screen = self.screen { + try screen.encode(to: protoWriter) + } + if let submessage = self.submessage { + try submessage.encode(to: protoWriter) + } + try protoWriter.writeUnknownFields(unknownFields) + } + +} + +#if !WIRE_REMOVE_CODABLE +extension Screen.SubMessage : Codable { + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self) + self._string.wrappedValue = try container.decodeIfPresent(String.self, forKey: "string") + if let submessage_screen_oneof_string = try container.decodeIfPresent(String.self, forKey: "submessageScreenOneofString") { + self.screen = .submessage_screen_oneof_string(submessage_screen_oneof_string) + } else if let submessage_screen_oneof_string = try container.decodeIfPresent(String.self, forKey: "submessage_screen_oneof_string") { + self.screen = .submessage_screen_oneof_string(submessage_screen_oneof_string) + } else { + self.screen = nil + } + if let submessage_oneof_string = try container.decodeIfPresent(String.self, forKey: "submessageOneofString") { + self.submessage = .submessage_oneof_string(submessage_oneof_string) + } else if let submessage_oneof_string = try container.decodeIfPresent(String.self, forKey: "submessage_oneof_string") { + self.submessage = .submessage_oneof_string(submessage_oneof_string) + } else if let submessage_oneof_nested_sub_message = try container.decodeIfPresent(Screen.SubMessage.NestedSubMessage.self, forKey: "submessageOneofNestedSubMessage") { + self.submessage = .submessage_oneof_nested_sub_message(submessage_oneof_nested_sub_message) + } else if let submessage_oneof_nested_sub_message = try container.decodeIfPresent(Screen.SubMessage.NestedSubMessage.self, forKey: "submessage_oneof_nested_sub_message") { + self.submessage = .submessage_oneof_nested_sub_message(submessage_oneof_nested_sub_message) + } else { + self.submessage = nil + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringLiteralCodingKeys.self) + let preferCamelCase = encoder.protoKeyNameEncodingStrategy == .camelCase + + try container.encodeIfPresent(self.string, forKey: "string") + switch self.screen { + case .submessage_screen_oneof_string(let submessage_screen_oneof_string): try container.encode(submessage_screen_oneof_string, forKey: preferCamelCase ? "submessageScreenOneofString" : "submessage_screen_oneof_string") + case Optional.none: break + } + switch self.submessage { + case .submessage_oneof_string(let submessage_oneof_string): try container.encode(submessage_oneof_string, forKey: preferCamelCase ? "submessageOneofString" : "submessage_oneof_string") + case .submessage_oneof_nested_sub_message(let submessage_oneof_nested_sub_message): try container.encode(submessage_oneof_nested_sub_message, forKey: preferCamelCase ? "submessageOneofNestedSubMessage" : "submessage_oneof_nested_sub_message") + case Optional.none: break + } + } + +} +#endif + +/** + * Subtypes within Screen.SubMessage + */ +extension Screen.SubMessage { + + public enum Screen_OneOf { + + case submessage_screen_oneof_string(String) + + fileprivate func encode(to protoWriter: ProtoWriter) throws { + switch self { + case .submessage_screen_oneof_string(let submessage_screen_oneof_string): try protoWriter.encode(tag: 2, value: submessage_screen_oneof_string) + } + } + + } + + public enum Submessage_OneOf { + + case submessage_oneof_string(String) + case submessage_oneof_nested_sub_message(Screen.SubMessage.NestedSubMessage) + + fileprivate func encode(to protoWriter: ProtoWriter) throws { + switch self { + case .submessage_oneof_string(let submessage_oneof_string): try protoWriter.encode(tag: 3, value: submessage_oneof_string) + case .submessage_oneof_nested_sub_message(let submessage_oneof_nested_sub_message): try protoWriter.encode(tag: 4, value: submessage_oneof_nested_sub_message) + } + } + + } + + public struct NestedSubMessage { + + @ProtoDefaulted + public var string: String? + public var unknownFields: UnknownFields = .init() + + public init(configure: (inout Self) -> Swift.Void = { _ in }) { + configure(&self) + } + + } + +} + +#if !WIRE_REMOVE_EQUATABLE +extension Screen.SubMessage.Screen_OneOf : Equatable { +} +#endif + +#if !WIRE_REMOVE_HASHABLE +extension Screen.SubMessage.Screen_OneOf : Hashable { +} +#endif + +extension Screen.SubMessage.Screen_OneOf : Sendable { +} + +#if !WIRE_REMOVE_EQUATABLE +extension Screen.SubMessage.Submessage_OneOf : Equatable { +} +#endif + +#if !WIRE_REMOVE_HASHABLE +extension Screen.SubMessage.Submessage_OneOf : Hashable { +} +#endif + +extension Screen.SubMessage.Submessage_OneOf : Sendable { +} + +#if !WIRE_REMOVE_EQUATABLE +extension Screen.SubMessage.NestedSubMessage : Equatable { +} +#endif + +#if !WIRE_REMOVE_HASHABLE +extension Screen.SubMessage.NestedSubMessage : Hashable { +} +#endif + +extension Screen.SubMessage.NestedSubMessage : Sendable { +} + +extension Screen.SubMessage.NestedSubMessage : ProtoDefaultedValue { + + public static var defaultedValue: Self { + .init() + } +} + +extension Screen.SubMessage.NestedSubMessage : ProtoMessage { + + public static func protoMessageTypeURL() -> String { + return "type.googleapis.com/squareup.protos.kotlin.swift_modules.Screen.SubMessage.NestedSubMessage" + } + +} + +extension Screen.SubMessage.NestedSubMessage : Proto2Codable { + + public init(from protoReader: ProtoReader) throws { + var string: String? = nil + + let token = try protoReader.beginMessage() + while let tag = try protoReader.nextTag(token: token) { + switch tag { + case 1: string = try protoReader.decode(String.self) + default: try protoReader.readUnknownField(tag: tag) + } + } + self.unknownFields = try protoReader.endMessage(token: token) + + self._string.wrappedValue = string + } + + public func encode(to protoWriter: ProtoWriter) throws { + try protoWriter.encode(tag: 1, value: self.string) + try protoWriter.writeUnknownFields(unknownFields) + } + +} + +#if !WIRE_REMOVE_CODABLE +extension Screen.SubMessage.NestedSubMessage : Codable { + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self) + self._string.wrappedValue = try container.decodeIfPresent(String.self, forKey: "string") + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringLiteralCodingKeys.self) + + try container.encodeIfPresent(self.string, forKey: "string") + } + +} +#endif diff --git a/wire-tests/src/commonTest/proto/kotlin/swift_edge_cases.proto b/wire-tests/src/commonTest/proto/kotlin/swift_edge_cases.proto index cefdcbaf27..637a80c3bc 100644 --- a/wire-tests/src/commonTest/proto/kotlin/swift_edge_cases.proto +++ b/wire-tests/src/commonTest/proto/kotlin/swift_edge_cases.proto @@ -35,8 +35,30 @@ message SwiftEdgeCases { message Screen { oneof screen { - string oneof_string = 1; - int32 oneof_int32 = 2; + string screen_oneof_string = 1; + int32 screen_oneof_int32 = 2; + SubMessage screen_oneof_sub_message = 3; + } + + oneof view { + string view_oneof_string = 4; + } + + message SubMessage { + optional string string = 1; + + oneof screen { + string submessage_screen_oneof_string = 2; + } + + oneof submessage { + string submessage_oneof_string = 3; + NestedSubMessage submessage_oneof_nested_sub_message = 4; + } + + message NestedSubMessage { + optional string string = 1; + } } }