diff --git a/wire-compiler/src/main/java/com/squareup/wire/schema/Target.kt b/wire-compiler/src/main/java/com/squareup/wire/schema/Target.kt index cd16a3eab3..f334bb7dae 100644 --- a/wire-compiler/src/main/java/com/squareup/wire/schema/Target.kt +++ b/wire-compiler/src/main/java/com/squareup/wire/schema/Target.kt @@ -142,6 +142,11 @@ data class KotlinTarget( * when targeting Kotlin/JS, where `Long` cursors are inefficient. */ private val emitProtoReader32: Boolean = false, + + /** + * If true, the generated classes will be mutable.. + */ +private val mutableTypes: Boolean = false, ) : Target() { override fun newHandler(): SchemaHandler { return KotlinSchemaHandler( @@ -159,6 +164,7 @@ data class KotlinTarget( escapeKotlinKeywords = escapeKotlinKeywords, enumMode = enumMode, emitProtoReader32 = emitProtoReader32, +mutableTypes = mutableTypes, ) } diff --git a/wire-golden-files/build.gradle.kts b/wire-golden-files/build.gradle.kts index 31534da057..6a96f9aae0 100644 --- a/wire-golden-files/build.gradle.kts +++ b/wire-golden-files/build.gradle.kts @@ -5,6 +5,12 @@ plugins { } wire { + kotlin { + includes = listOf("squareup.wire.mutable.*") + out = "src/main/kotlin" + mutableTypes = true + } + kotlin { includes = listOf("squareup.wire.unrecognized_constant.*") out = "src/main/kotlin" diff --git a/wire-golden-files/src/main/kotlin/HundredsFields.kt b/wire-golden-files/src/main/kotlin/HundredsFields.kt index 8ec2c23ca3..dfd4476c13 100644 --- a/wire-golden-files/src/main/kotlin/HundredsFields.kt +++ b/wire-golden-files/src/main/kotlin/HundredsFields.kt @@ -26,9 +26,6 @@ import kotlin.String import kotlin.Suppress import okio.ByteString -/** - * import "google/protobuf/descriptor.proto"; - */ public class HundredsFields( @field:WireField( tag = 1, diff --git a/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutableHeader.kt b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutableHeader.kt new file mode 100644 index 0000000000..1f0a44a9a6 --- /dev/null +++ b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutableHeader.kt @@ -0,0 +1,103 @@ +// Code generated by Wire protocol buffer compiler, do not edit. +// Source: squareup.wire.mutable.Header in squareup/wire/mutable_types.proto +@file:Suppress( + "DEPRECATION", + "RUNTIME_ANNOTATION_NOT_SUPPORTED", +) + +package squareup.wire.mutable + +import com.squareup.wire.FieldEncoding +import com.squareup.wire.Message +import com.squareup.wire.ProtoAdapter +import com.squareup.wire.ProtoReader +import com.squareup.wire.ProtoWriter +import com.squareup.wire.ReverseProtoWriter +import com.squareup.wire.Syntax.PROTO_2 +import com.squareup.wire.WireField +import com.squareup.wire.`internal`.JvmField +import kotlin.Any +import kotlin.Boolean +import kotlin.Int +import kotlin.Long +import kotlin.Nothing +import kotlin.String +import kotlin.Suppress +import kotlin.UnsupportedOperationException +import okio.ByteString + +public class MutableHeader( + @field:WireField( + tag = 1, + adapter = "com.squareup.wire.ProtoAdapter#UINT64", + schemaIndex = 0, + ) + public var id: Long? = null, + unknownFields: ByteString = ByteString.EMPTY, +) : Message(ADAPTER, unknownFields) { + override fun equals(other: Any?): Boolean { + if (other !is MutableHeader) return false + if (unknownFields != other.unknownFields) return false + if (id != other.id) return false + return true + } + + override fun hashCode(): Int { + var result = 0 + result = unknownFields.hashCode() + result = result * 37 + (id?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + val result = mutableListOf() + if (id != null) result += """id=$id""" + return result.joinToString(prefix = "MutableHeader{", separator = ", ", postfix = "}") + } + + public companion object { + @JvmField + public val ADAPTER: ProtoAdapter = object : ProtoAdapter( + FieldEncoding.LENGTH_DELIMITED, + MutableHeader::class, + "type.googleapis.com/squareup.wire.mutable.Header", + PROTO_2, + null, + "squareup/wire/mutable_types.proto" + ) { + override fun encodedSize(`value`: MutableHeader): Int { + var size = value.unknownFields.size + size += ProtoAdapter.UINT64.encodedSizeWithTag(1, value.id) + return size + } + + override fun encode(writer: ProtoWriter, `value`: MutableHeader) { + ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id) + writer.writeBytes(value.unknownFields) + } + + override fun encode(writer: ReverseProtoWriter, `value`: MutableHeader) { + writer.writeBytes(value.unknownFields) + ProtoAdapter.UINT64.encodeWithTag(writer, 1, value.id) + } + + override fun decode(reader: ProtoReader): MutableHeader { + var id: Long? = null + val unknownFields = reader.forEachTag { tag -> + when (tag) { + 1 -> id = ProtoAdapter.UINT64.decode(reader) + else -> reader.readUnknownField(tag) + } + } + return MutableHeader( + id = id, + unknownFields = unknownFields + ) + } + + override fun redact(`value`: MutableHeader): MutableHeader = throw UnsupportedOperationException("redact() is unsupported for Mutable message types") + } + + private const val serialVersionUID: Long = 0L + } +} 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 new file mode 100644 index 0000000000..7443a67661 --- /dev/null +++ b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePacket.kt @@ -0,0 +1,119 @@ +// Code generated by Wire protocol buffer compiler, do not edit. +// Source: squareup.wire.mutable.Packet in squareup/wire/mutable_types.proto +@file:Suppress( + "DEPRECATION", + "RUNTIME_ANNOTATION_NOT_SUPPORTED", +) + +package squareup.wire.mutable + +import com.squareup.wire.FieldEncoding +import com.squareup.wire.Message +import com.squareup.wire.ProtoAdapter +import com.squareup.wire.ProtoReader +import com.squareup.wire.ProtoWriter +import com.squareup.wire.ReverseProtoWriter +import com.squareup.wire.Syntax.PROTO_2 +import com.squareup.wire.WireField +import com.squareup.wire.`internal`.JvmField +import kotlin.Any +import kotlin.Boolean +import kotlin.Int +import kotlin.Long +import kotlin.Nothing +import kotlin.String +import kotlin.Suppress +import kotlin.UnsupportedOperationException +import okio.ByteString + +public class MutablePacket( + @field:WireField( + tag = 1, + adapter = "squareup.wire.mutable.MutableHeader#ADAPTER", + declaredName = "header", + schemaIndex = 0, + ) + public var header_: MutableHeader? = null, + @field:WireField( + tag = 2, + adapter = "squareup.wire.mutable.MutablePayload#ADAPTER", + schemaIndex = 1, + ) + public var payload: MutablePayload? = null, + unknownFields: ByteString = ByteString.EMPTY, +) : Message(ADAPTER, unknownFields) { + override fun equals(other: Any?): Boolean { + if (other !is MutablePacket) return false + if (unknownFields != other.unknownFields) return false + if (header_ != other.header_) return false + if (payload != other.payload) return false + return true + } + + override fun hashCode(): Int { + var result = 0 + result = unknownFields.hashCode() + result = result * 37 + (header_?.hashCode() ?: 0) + result = result * 37 + (payload?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + val result = mutableListOf() + if (header_ != null) result += """header_=$header_""" + if (payload != null) result += """payload=$payload""" + return result.joinToString(prefix = "MutablePacket{", separator = ", ", postfix = "}") + } + + public companion object { + @JvmField + public val ADAPTER: ProtoAdapter = object : ProtoAdapter( + FieldEncoding.LENGTH_DELIMITED, + MutablePacket::class, + "type.googleapis.com/squareup.wire.mutable.Packet", + PROTO_2, + null, + "squareup/wire/mutable_types.proto" + ) { + override fun encodedSize(`value`: MutablePacket): Int { + var size = value.unknownFields.size + size += MutableHeader.ADAPTER.encodedSizeWithTag(1, value.header_) + size += MutablePayload.ADAPTER.encodedSizeWithTag(2, value.payload) + return size + } + + override fun encode(writer: ProtoWriter, `value`: MutablePacket) { + MutableHeader.ADAPTER.encodeWithTag(writer, 1, value.header_) + MutablePayload.ADAPTER.encodeWithTag(writer, 2, value.payload) + writer.writeBytes(value.unknownFields) + } + + override fun encode(writer: ReverseProtoWriter, `value`: MutablePacket) { + writer.writeBytes(value.unknownFields) + MutablePayload.ADAPTER.encodeWithTag(writer, 2, value.payload) + MutableHeader.ADAPTER.encodeWithTag(writer, 1, value.header_) + } + + override fun decode(reader: ProtoReader): MutablePacket { + var header_: MutableHeader? = null + var payload: MutablePayload? = null + val unknownFields = reader.forEachTag { tag -> + when (tag) { + 1 -> header_ = MutableHeader.ADAPTER.decode(reader) + 2 -> payload = MutablePayload.ADAPTER.decode(reader) + else -> reader.readUnknownField(tag) + } + } + return MutablePacket( + header_ = header_, + payload = payload, + unknownFields = unknownFields + ) + } + + override fun redact(`value`: MutablePacket): MutablePacket = throw UnsupportedOperationException("redact() is unsupported for Mutable message types") + } + + private const val serialVersionUID: Long = 0L + } +} 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 new file mode 100644 index 0000000000..4706b137d7 --- /dev/null +++ b/wire-golden-files/src/main/kotlin/squareup/wire/mutable/MutablePayload.kt @@ -0,0 +1,103 @@ +// Code generated by Wire protocol buffer compiler, do not edit. +// Source: squareup.wire.mutable.Payload in squareup/wire/mutable_types.proto +@file:Suppress( + "DEPRECATION", + "RUNTIME_ANNOTATION_NOT_SUPPORTED", +) + +package squareup.wire.mutable + +import com.squareup.wire.FieldEncoding +import com.squareup.wire.Message +import com.squareup.wire.ProtoAdapter +import com.squareup.wire.ProtoReader +import com.squareup.wire.ProtoWriter +import com.squareup.wire.ReverseProtoWriter +import com.squareup.wire.Syntax.PROTO_2 +import com.squareup.wire.WireField +import com.squareup.wire.`internal`.JvmField +import kotlin.Any +import kotlin.Boolean +import kotlin.Int +import kotlin.Long +import kotlin.Nothing +import kotlin.String +import kotlin.Suppress +import kotlin.UnsupportedOperationException +import okio.ByteString + +public class MutablePayload( + @field:WireField( + tag = 1, + adapter = "com.squareup.wire.ProtoAdapter#BYTES", + schemaIndex = 0, + ) + public var content: ByteString? = null, + unknownFields: ByteString = ByteString.EMPTY, +) : Message(ADAPTER, unknownFields) { + override fun equals(other: Any?): Boolean { + if (other !is MutablePayload) return false + if (unknownFields != other.unknownFields) return false + if (content != other.content) return false + return true + } + + override fun hashCode(): Int { + var result = 0 + result = unknownFields.hashCode() + result = result * 37 + (content?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + val result = mutableListOf() + if (content != null) result += """content=$content""" + return result.joinToString(prefix = "MutablePayload{", separator = ", ", postfix = "}") + } + + public companion object { + @JvmField + public val ADAPTER: ProtoAdapter = object : ProtoAdapter( + FieldEncoding.LENGTH_DELIMITED, + MutablePayload::class, + "type.googleapis.com/squareup.wire.mutable.Payload", + PROTO_2, + null, + "squareup/wire/mutable_types.proto" + ) { + override fun encodedSize(`value`: MutablePayload): Int { + var size = value.unknownFields.size + size += ProtoAdapter.BYTES.encodedSizeWithTag(1, value.content) + return size + } + + override fun encode(writer: ProtoWriter, `value`: MutablePayload) { + ProtoAdapter.BYTES.encodeWithTag(writer, 1, value.content) + writer.writeBytes(value.unknownFields) + } + + override fun encode(writer: ReverseProtoWriter, `value`: MutablePayload) { + writer.writeBytes(value.unknownFields) + ProtoAdapter.BYTES.encodeWithTag(writer, 1, value.content) + } + + override fun decode(reader: ProtoReader): MutablePayload { + var content: ByteString? = null + val unknownFields = reader.forEachTag { tag -> + when (tag) { + 1 -> content = ProtoAdapter.BYTES.decode(reader) + else -> reader.readUnknownField(tag) + } + } + return MutablePayload( + content = content, + unknownFields = unknownFields + ) + } + + override fun redact(`value`: MutablePayload): MutablePayload = throw UnsupportedOperationException("redact() is unsupported for Mutable message types") + } + + private const val serialVersionUID: Long = 0L + } +} diff --git a/wire-golden-files/src/main/proto/squareup/wire/hundreds_redacted.proto b/wire-golden-files/src/main/proto/squareup/wire/hundreds_redacted.proto index 8273414402..8bb4caa67c 100644 --- a/wire-golden-files/src/main/proto/squareup/wire/hundreds_redacted.proto +++ b/wire-golden-files/src/main/proto/squareup/wire/hundreds_redacted.proto @@ -1,7 +1,5 @@ syntax = "proto3"; -// import "google/protobuf/descriptor.proto"; - message HundredsFields { Field field1 = 1; Field field2 = 2; diff --git a/wire-golden-files/src/main/proto/squareup/wire/mutable_types.proto b/wire-golden-files/src/main/proto/squareup/wire/mutable_types.proto new file mode 100644 index 0000000000..7ea115bb87 --- /dev/null +++ b/wire-golden-files/src/main/proto/squareup/wire/mutable_types.proto @@ -0,0 +1,16 @@ +syntax = "proto2"; + +package squareup.wire.mutable; + +message Header { + optional uint64 id = 1; +} + +message Payload { + optional bytes content = 1; +} + +message Packet { + optional Header header = 1; + optional Payload payload = 2; +} diff --git a/wire-gradle-plugin/src/main/kotlin/com/squareup/wire/gradle/WireOutput.kt b/wire-gradle-plugin/src/main/kotlin/com/squareup/wire/gradle/WireOutput.kt index 5f29a2ce3a..2f1694af8b 100644 --- a/wire-gradle-plugin/src/main/kotlin/com/squareup/wire/gradle/WireOutput.kt +++ b/wire-gradle-plugin/src/main/kotlin/com/squareup/wire/gradle/WireOutput.kt @@ -154,6 +154,11 @@ open class KotlinOutput @Inject constructor() : WireOutput() { */ var emitProtoReader32: Boolean = false + /** + * If true, the generated classes will be mutable.. + */ + var mutableTypes: Boolean = false + override fun toTarget(outputDirectory: String): KotlinTarget { if (grpcServerCompatible) { throw IllegalArgumentException( @@ -197,6 +202,7 @@ open class KotlinOutput @Inject constructor() : WireOutput() { escapeKotlinKeywords = escapeKotlinKeywords, enumMode = enumMode, emitProtoReader32 = emitProtoReader32, + mutableTypes = mutableTypes, ) } } 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 245d8b569c..111340e80e 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 @@ -137,7 +137,7 @@ class KotlinGenerator private constructor( private val escapeKotlinKeywords: Boolean, private val enumMode: EnumMode, private val emitProtoReader32: Boolean, - private val generateMutableMessages: Boolean + private val mutableTypes: Boolean ) { private val nameAllocatorStore = mutableMapOf() @@ -564,7 +564,7 @@ class KotlinGenerator private constructor( .addSuperclassConstructorParameter(adapterName) .addSuperclassConstructorParameter(unknownFields) .apply { - if (!generateMutableMessages) { + if (!mutableTypes) { // Only generate a builder if the message is not already mutable addFunction(generateNewBuilderMethod(type, builderClassName)) } @@ -573,9 +573,9 @@ class KotlinGenerator private constructor( .addFunction(generateHashCodeMethod(type, nameAllocator)) .addFunction(generateToStringMethod(type, nameAllocator)) .apply { - if (buildersOnly || generateMutableMessages) { + if (buildersOnly || mutableTypes) { // buildersOnly: We expect consumers to use the `newBuilder` method instead of the `copy` method. - // generateMutableMessages: The messages are already mutable, so no need to generate a `copy` method. + // mutableTypes: The messages are already mutable, so no need to generate a `copy` method. return@apply } addFunction(generateCopyMethod(type, nameAllocator)) @@ -706,7 +706,7 @@ class KotlinGenerator private constructor( .returns(BOOLEAN) val body = buildCodeBlock { - if (!generateMutableMessages) { + if (!mutableTypes) { // This is true iff the message is not mutable addStatement("if (%N === this) return·true", otherName) } @@ -765,7 +765,7 @@ class KotlinGenerator private constructor( } val body = buildCodeBlock { - if (!generateMutableMessages) { + if (!mutableTypes) { addStatement("var %N = super.hashCode", resultName) beginControlFlow("if (%N == 0)", resultName) } else { @@ -795,7 +795,7 @@ class KotlinGenerator private constructor( } } - if (!generateMutableMessages) { + if (!mutableTypes) { addStatement("super.hashCode = %N", resultName) endControlFlow() } @@ -1203,7 +1203,7 @@ class KotlinGenerator private constructor( } val propertySpec = PropertySpec.builder(fieldName, fieldClass) - .mutable(generateMutableMessages) + .mutable(mutableTypes) .initializer(initializer) .apply { if (field.isDeprecated) { @@ -1242,7 +1242,7 @@ class KotlinGenerator private constructor( parameterSpec.defaultValue(CodeBlock.of("null")) val propertySpec = PropertySpec.builder(fieldName, fieldClass) - .mutable(generateMutableMessages) + .mutable(mutableTypes) .initializer(CodeBlock.of(if (buildersOnly) "builder.%N" else "%N", fieldName)) .apply { if (javaInterOp) { @@ -2057,7 +2057,7 @@ class KotlinGenerator private constructor( .addParameter("value", className) .returns(className) - if (generateMutableMessages) { + if (mutableTypes) { redactBuilder.addStatement( "throw %T(%S)", ClassName("kotlin", "UnsupportedOperationException"), @@ -3112,7 +3112,7 @@ class KotlinGenerator private constructor( escapeKotlinKeywords: Boolean = false, enumMode: EnumMode = ENUM_CLASS, emitProtoReader32: Boolean = false, - generateMutableMessages: Boolean = false, + mutableTypes: Boolean = false, ): KotlinGenerator { val typeToKotlinName = mutableMapOf() val memberToKotlinName = mutableMapOf() @@ -3120,7 +3120,7 @@ class KotlinGenerator private constructor( fun putAll(kotlinPackage: String, enclosingClassName: ClassName?, types: List) { for (type in types) { val simpleName = type.type.simpleName - val name = if (generateMutableMessages) "Mutable$simpleName" else simpleName + val name = if (mutableTypes) "Mutable$simpleName" else simpleName val className = enclosingClassName?.nestedClass(name) ?: ClassName(kotlinPackage, name) typeToKotlinName[type.type] = className @@ -3165,7 +3165,7 @@ class KotlinGenerator private constructor( escapeKotlinKeywords = escapeKotlinKeywords, enumMode = enumMode, emitProtoReader32 = emitProtoReader32, - generateMutableMessages = generateMutableMessages + mutableTypes = mutableTypes ) } diff --git a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinSchemaHandler.kt b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinSchemaHandler.kt index d52612a96e..68156f218d 100644 --- a/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinSchemaHandler.kt +++ b/wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinSchemaHandler.kt @@ -86,6 +86,11 @@ class KotlinSchemaHandler( * when targeting Kotlin/JS, where `Long` cursors are inefficient. */ private val emitProtoReader32: Boolean = false, + + /** + * If true, the generated classes will be mutable.. + */ + private val mutableTypes: Boolean = false ) : SchemaHandler() { private lateinit var kotlinGenerator: KotlinGenerator @@ -107,6 +112,7 @@ class KotlinSchemaHandler( escapeKotlinKeywords = escapeKotlinKeywords, enumMode = enumMode, emitProtoReader32 = emitProtoReader32, + mutableTypes = mutableTypes, ) context.fileSystem.createDirectories(context.outDirectory) super.handle(schema, context)