Skip to content

Commit

Permalink
Sample of new handling for OneOf's
Browse files Browse the repository at this point in the history
  • Loading branch information
oldergod committed Nov 13, 2020
1 parent 94045c8 commit 88eced9
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.squareup.wire

data class OneOf<T>(
val key: Key<T>,
val value: T
) {
fun <R : Any> get(key: Key<R>): R? {
if (this.key == key) return value as R
return null
}

data class Key<R>(
val tag: Int,
val adapter: ProtoAdapter<R>,
val redacted: Boolean = false,
val declaredName: String = "",
val jsonName: String = "",
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.squareup.wire.ProtoWriter.Companion.varint64Size
import com.squareup.wire.internal.Throws
import com.squareup.wire.internal.missingRequiredFields
import com.squareup.wire.internal.redactElements
import com.squareup.wire.internal.sanitize
import okio.Buffer
import okio.BufferedSink
import okio.BufferedSource
Expand Down Expand Up @@ -202,6 +203,7 @@ expect abstract class ProtoAdapter<E>(
@JvmField val BOOL_VALUE: ProtoAdapter<Boolean?>
@JvmField val STRING_VALUE: ProtoAdapter<String?>
@JvmField val BYTES_VALUE: ProtoAdapter<ByteString?>
@JvmField val ONE_OF: OneOfProtoAdapter
}
}

Expand Down Expand Up @@ -1098,3 +1100,30 @@ internal fun <T : Any> commonWrapper(delegate: ProtoAdapter<T>, typeUrl: String)
}
}
}

internal fun commonOneOf(): OneOfProtoAdapter {
return OneOfProtoAdapter()
}

class OneOfProtoAdapter() {
fun toString(oneOf: OneOf<*>): String {
TODO()
// {
// when {
// choice.get(ChoiceOneOf.CHOICE_FOO) != null -> result += """foo=${choice.get(ChoiceOneOf.CHOICE_FOO)}"""
// choice.get(ChoiceOneOf.CHOICE_BAR) != null ->
// result += """foo=${sanitize(choice.get(ChoiceOneOf.CHOICE_BAR)!!)}"""
// choice.get(ChoiceOneOf.CHOICE_BAZ) != null ->
// result += """foo=${sanitize(choice.get(ChoiceOneOf.CHOICE_BAZ)!!)}"""
// }
// }
}

fun encodedSizeWithTag(oneOf: OneOf<*>): Byte {
oneOf.key.adapter.encodedSizeWithTag(oneOf.key.tag, oneOf.value)
}

fun encodeWithTag(writer: ProtoWriter, oneOf: OneOf<*>) {
oneOf.key.adapter.encodeWithTag(writer, oneOf.key.tag, oneOf.value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.squareup.wire
import okio.BufferedSink
import okio.BufferedSource
import okio.ByteString
import kotlin.jvm.JvmField
import kotlin.reflect.KClass

actual abstract class ProtoAdapter<E> actual constructor(
Expand Down Expand Up @@ -181,5 +182,6 @@ actual abstract class ProtoAdapter<E> actual constructor(
actual val BOOL_VALUE : ProtoAdapter<Boolean?> = commonWrapper(BOOL, "type.googleapis.com/google.protobuf.BoolValue")
actual val STRING_VALUE : ProtoAdapter<String?> = commonWrapper(STRING, "type.googleapis.com/google.protobuf.StringValue")
actual val BYTES_VALUE : ProtoAdapter<ByteString?> = commonWrapper(BYTES, "type.googleapis.com/google.protobuf.BytesValue")
actual val ONE_OF: OneOfProtoAdapter = commonOneOf()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ actual abstract class ProtoAdapter<E> actual constructor(
@JvmField actual val BOOL_VALUE: ProtoAdapter<Boolean?> = commonWrapper(BOOL, "type.googleapis.com/google.protobuf.BoolValue")
@JvmField actual val STRING_VALUE: ProtoAdapter<String?> = commonWrapper(STRING, "type.googleapis.com/google.protobuf.StringValue")
@JvmField actual val BYTES_VALUE: ProtoAdapter<ByteString?> = commonWrapper(BYTES, "type.googleapis.com/google.protobuf.BytesValue")
@JvmField actual val ONE_OF: OneOfProtoAdapter = commonOneOf()
@JvmField actual val DURATION: ProtoAdapter<Duration> = try {
commonDuration()
} catch (_: NoClassDefFoundError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,6 @@ actual abstract class ProtoAdapter<E> actual constructor(
actual val BOOL_VALUE: ProtoAdapter<Boolean?> = commonWrapper(BOOL, "type.googleapis.com/google.protobuf.BoolValue")
actual val STRING_VALUE: ProtoAdapter<String?> = commonWrapper(STRING, "type.googleapis.com/google.protobuf.StringValue")
actual val BYTES_VALUE: ProtoAdapter<ByteString?> = commonWrapper(BYTES, "type.googleapis.com/google.protobuf.BytesValue")
actual val ONE_OF: OneOfProtoAdapter = commonOneOf()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,39 @@ package com.squareup.wire.protos.kotlin

import com.squareup.wire.FieldEncoding
import com.squareup.wire.Message
import com.squareup.wire.OneOf
import com.squareup.wire.OneOfProtoAdapter
import com.squareup.wire.ProtoAdapter
import com.squareup.wire.ProtoReader
import com.squareup.wire.ProtoWriter
import com.squareup.wire.Syntax.PROTO_2
import com.squareup.wire.WireField
import com.squareup.wire.`internal`.countNonNull
import com.squareup.wire.`internal`.sanitize
import kotlin.Any
import kotlin.AssertionError
import kotlin.Boolean
import kotlin.Deprecated
import kotlin.DeprecationLevel
import kotlin.Int
import kotlin.Long
import kotlin.Nothing
import kotlin.String
import kotlin.Unit
import kotlin.hashCode
import kotlin.jvm.JvmField
import com.squareup.wire.internal.countNonNull
import com.squareup.wire.internal.sanitize
import com.squareup.wire.protos.kotlin.OneOfMessage.ChoiceOneOf.CHOICE_BAR
import com.squareup.wire.protos.kotlin.OneOfMessage.ChoiceOneOf.CHOICE_BAZ
import com.squareup.wire.protos.kotlin.OneOfMessage.ChoiceOneOf.CHOICE_FOO
import okio.ByteString
import kotlin.jvm.JvmField

/**
* It's a one of message.
*/
public class OneOfMessage(
/**
* What foo.
*/
@field:WireField(
tag = 1,
adapter = "com.squareup.wire.ProtoAdapter#INT32"
)
public val foo: Int? = null,
/**
* Such bar.
*/
@field:WireField(
tag = 3,
adapter = "com.squareup.wire.ProtoAdapter#STRING"
)
public val bar: String? = null,
/**
* Nice baz.
*/
@field:WireField(
tag = 4,
adapter = "com.squareup.wire.ProtoAdapter#STRING"
)
public val baz: String? = null,
choice: OneOf<*>? = null,
unknownFields: ByteString = ByteString.EMPTY
) : Message<OneOfMessage, Nothing>(ADAPTER, unknownFields) {
init {
require(countNonNull(foo, bar, baz) <= 1) {
"At most one of foo, bar, baz may be non-null"
val choice: OneOf<*>? = run {
if (choice == null) return@run null
if (choice.key !in listOf(CHOICE_FOO,CHOICE_BAR,CHOICE_BAZ)) {
throw IllegalArgumentException("Key isn't in the expected scope something.")
}
return@run choice
}

object ChoiceOneOf {
val CHOICE_FOO = OneOf.Key(tag = 1, adapter = ProtoAdapter.INT32)
val CHOICE_BAR = OneOf.Key(tag = 3, adapter = ProtoAdapter.STRING)
val CHOICE_BAZ = OneOf.Key(tag = 4, adapter = ProtoAdapter.STRING)
}

@Deprecated(
Expand All @@ -71,67 +49,61 @@ public class OneOfMessage(
if (other === this) return true
if (other !is OneOfMessage) return false
if (unknownFields != other.unknownFields) return false
if (foo != other.foo) return false
if (bar != other.bar) return false
if (baz != other.baz) return false
if (choice != other.choice) return false
return true
}

public override fun hashCode(): Int {
var result = super.hashCode
if (result == 0) {
result = unknownFields.hashCode()
result = result * 37 + foo.hashCode()
result = result * 37 + bar.hashCode()
result = result * 37 + baz.hashCode()
result = result * 37 + choice.hashCode()
super.hashCode = result
}
return result
}

public override fun toString(): String {
val result = mutableListOf<String>()
if (foo != null) result += """foo=$foo"""
if (bar != null) result += """bar=${sanitize(bar)}"""
if (baz != null) result += """baz=${sanitize(baz)}"""
// TODO(Benoit) Delegate to something.
if (choice != null) ProtoAdapter.ONE_OF.toString(choice)
return result.joinToString(prefix = "OneOfMessage{", separator = ", ", postfix = "}")
}

public fun copy(
foo: Int? = this.foo,
bar: String? = this.bar,
baz: String? = this.baz,
choice: OneOf<*>? = this.choice,
unknownFields: ByteString = this.unknownFields
): OneOfMessage = OneOfMessage(foo, bar, baz, unknownFields)
): OneOfMessage = OneOfMessage(choice, unknownFields)

public companion object {
@JvmField
public val ADAPTER: ProtoAdapter<OneOfMessage> = object : ProtoAdapter<OneOfMessage>(
FieldEncoding.LENGTH_DELIMITED,
OneOfMessage::class,
"type.googleapis.com/squareup.protos.kotlin.oneof.OneOfMessage",
PROTO_2,
FieldEncoding.LENGTH_DELIMITED,
OneOfMessage::class,
"type.googleapis.com/squareup.protos.kotlin.oneof.OneOfMessage",
PROTO_2,
null
) {
public override fun encodedSize(value: OneOfMessage): Int {
var size = value.unknownFields.size
size += ProtoAdapter.INT32.encodedSizeWithTag(1, value.foo)
size += ProtoAdapter.STRING.encodedSizeWithTag(3, value.bar)
size += ProtoAdapter.STRING.encodedSizeWithTag(4, value.baz)
if (value.choice != null) {
size += ProtoAdapter.ONE_OF.encodedSizeWithTag(value.choice.key.tag, value.choice)
}
return size
}

public override fun encode(writer: ProtoWriter, value: OneOfMessage): Unit {
ProtoAdapter.INT32.encodeWithTag(writer, 1, value.foo)
ProtoAdapter.STRING.encodeWithTag(writer, 3, value.bar)
ProtoAdapter.STRING.encodeWithTag(writer, 4, value.baz)
if (value.choice != null) {
ProtoAdapter.ONE_OF.encodeWithTag(writer, value.choice.key.tag, value.choice)
}
writer.writeBytes(value.unknownFields)
}

public override fun decode(reader: ProtoReader): OneOfMessage {
var foo: Int? = null
var bar: String? = null
var baz: String? = null
// TODO(Benoit) How would we delegate that without consuming the reader?
val unknownFields = reader.forEachTag { tag ->
when (tag) {
1 -> foo = ProtoAdapter.INT32.decode(reader)
Expand All @@ -140,10 +112,17 @@ public class OneOfMessage(
else -> reader.readUnknownField(tag)
}
}
require(countNonNull(foo, bar, baz) <= 1) {
"At most one of foo, bar, baz may be non-null"
}
val choice: OneOf<*>? = when {
foo != null -> OneOf(ChoiceOneOf.CHOICE_FOO, foo!!)
bar != null -> OneOf(ChoiceOneOf.CHOICE_BAR, bar!!)
baz != null -> OneOf(ChoiceOneOf.CHOICE_BAZ, baz!!)
else -> null
}
return OneOfMessage(
foo = foo,
bar = bar,
baz = baz,
choice = choice,
unknownFields = unknownFields
)
}
Expand Down

0 comments on commit 88eced9

Please sign in to comment.