All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.squareup.wire.ProtoAdapter.kt Maven / Gradle / Ivy

/*
 * Copyright 2015 Square 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 com.squareup.wire

import com.squareup.wire.FieldEncoding.LENGTH_DELIMITED
import com.squareup.wire.FieldEncoding.VARINT
import com.squareup.wire.ProtoWriter.Companion.decodeZigZag32
import com.squareup.wire.ProtoWriter.Companion.decodeZigZag64
import com.squareup.wire.ProtoWriter.Companion.encodeZigZag32
import com.squareup.wire.ProtoWriter.Companion.encodeZigZag64
import com.squareup.wire.ProtoWriter.Companion.int32Size
import com.squareup.wire.ProtoWriter.Companion.tagSize
import com.squareup.wire.ProtoWriter.Companion.varint32Size
import com.squareup.wire.ProtoWriter.Companion.varint64Size
import com.squareup.wire.internal.Throws
import okio.Buffer
import okio.BufferedSink
import okio.BufferedSource
import okio.ByteString
import okio.IOException
import okio.utf8Size
import kotlin.jvm.JvmField
import kotlin.jvm.JvmStatic
import kotlin.reflect.KClass

expect abstract class ProtoAdapter(
  fieldEncoding: FieldEncoding,
  type: KClass<*>?,
  typeUrl: String?,
  syntax: Syntax,
  identity: E? = null,
  sourceFile: String? = null,
) {
  internal val fieldEncoding: FieldEncoding
  val type: KClass<*>?

  /**
   * Identifies this type for inclusion in a `google.protobuf.Any`. This is a string like
   * "type.googleapis.com/packagename.messagename" or null if this type is either not a message
   * (such as scalars and enums), or was code-generated before Wire 3.2 which introduced support for
   * type URLS.
   */
  val typeUrl: String?

  /**
   * Identifies the syntax in which [type] is defined in the proto schema. This string contains
   * either "proto2" or "proto3".
   */
  val syntax: Syntax

  /**
   * A special value that is used when a field is absent from an encoded proto3 message. When
   * encoding a proto3 message, fields that hold this value will be omitted.
   *
   * ```
   * | TYPE                                           | IDENTITY                      |
   * | :--------------------------------------------- | :---------------------------- |
   * | All numeric types (int32, float, double, etc.) | 0                             |
   * | Boolean                                        | false                         |
   * | String                                         | empty string: ""              |
   * | Bytes                                          | empty bytes: ByteString.EMPTY |
   * | Enums                                          | enum constant with tag 0      |
   * | Lists (repeated types)                         | empty list: listOf()          |
   * ```
   */
  val identity: E?

  /**
   * Path to the file containing the protobuf definition of this type.
   */
  val sourceFile: String?

  internal val packedAdapter: ProtoAdapter>?
  internal val repeatedAdapter: ProtoAdapter>?

  /** Returns the redacted form of `value`. */
  abstract fun redact(value: E): E

  /**
   * The size of the non-null data `value`. This does not include the size required for a
   * length-delimited prefix (should the type require one).
   */
  abstract fun encodedSize(value: E): Int

  /**
   * The size of `tag` and `value` in the wire format. This size includes the tag, type,
   * length-delimited prefix (should the type require one), and value. Returns 0 if `value` is
   * null.
   */
  open fun encodedSizeWithTag(tag: Int, value: E?): Int

  /** Write non-null `value` to `writer`. */
  @Throws(IOException::class)
  abstract fun encode(writer: ProtoWriter, value: E)

  /** Write non-null `value` to `writer`. */
  @Throws(IOException::class)
  open fun encode(writer: ReverseProtoWriter, value: E)

  /** Write `tag` and `value` to `writer`. If value is null this does nothing. */
  @Throws(IOException::class)
  open fun encodeWithTag(writer: ProtoWriter, tag: Int, value: E?)

  /** Write `tag` and `value` to `writer`. If value is null this does nothing. */
  @Throws(IOException::class)
  open fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: E?)

  /** Encode `value` and write it to `stream`. */
  @Throws(IOException::class)
  fun encode(sink: BufferedSink, value: E)

  /** Encode `value` as a `byte[]`. */
  fun encode(value: E): ByteArray

  /** Encode `value` as a [ByteString]. */
  fun encodeByteString(value: E): ByteString

  /** Read a non-null value from `reader`. */
  @Throws(IOException::class)
  abstract fun decode(reader: ProtoReader): E

  /** Read an encoded message from `bytes`. */
  @Throws(IOException::class)
  fun decode(bytes: ByteArray): E

  /** Read an encoded message from `bytes`. */
  @Throws(IOException::class)
  fun decode(bytes: ByteString): E

  /** Read an encoded message from `source`. */
  @Throws(IOException::class)
  fun decode(source: BufferedSource): E

  /** Returns a human-readable version of the given `value`. */
  open fun toString(value: E): String

  internal fun withLabel(label: WireField.Label): ProtoAdapter<*>

  /** Returns an adapter for `E` but as a packed, repeated value. */
  fun asPacked(): ProtoAdapter>

  /**
   * Returns an adapter for `E` but as a repeated value.
   *
   * Note: Repeated items are not required to be encoded sequentially. Thus, when decoding using
   * the returned adapter, only single-element lists will be returned and it is the caller's
   * responsibility to merge them into the final list.
   */
  fun asRepeated(): ProtoAdapter>

  class EnumConstantNotFoundException(
    value: Int,
    type: KClass<*>?
  ) : IllegalArgumentException {
    @JvmField val value: Int
  }

  companion object {
    /**
     * Creates a new proto adapter for a map using `keyAdapter` and `valueAdapter`.
     *
     * Note: Map entries are not required to be encoded sequentially. Thus, when decoding using
     * the returned adapter, only single-element maps will be returned and it is the caller's
     * responsibility to merge them into the final map.
     */
    @JvmStatic fun  newMapAdapter(
      keyAdapter: ProtoAdapter,
      valueAdapter: ProtoAdapter
    ): ProtoAdapter>

    @JvmField val BOOL: ProtoAdapter
    @JvmField val INT32: ProtoAdapter
    @JvmField val UINT32: ProtoAdapter
    @JvmField val SINT32: ProtoAdapter
    @JvmField val FIXED32: ProtoAdapter
    @JvmField val SFIXED32: ProtoAdapter
    @JvmField val INT64: ProtoAdapter
    /**
     * Like INT64, but negative longs are interpreted as large positive values, and encoded that way
     * in JSON.
     */
    @JvmField val UINT64: ProtoAdapter
    @JvmField val SINT64: ProtoAdapter
    @JvmField val FIXED64: ProtoAdapter
    @JvmField val SFIXED64: ProtoAdapter
    @JvmField val FLOAT: ProtoAdapter
    @JvmField val DOUBLE: ProtoAdapter
    @JvmField val BYTES: ProtoAdapter
    @JvmField val STRING: ProtoAdapter
    @JvmField val DURATION: ProtoAdapter
    @JvmField val INSTANT: ProtoAdapter
    @JvmField val EMPTY: ProtoAdapter
    @JvmField val STRUCT_MAP: ProtoAdapter?>
    @JvmField val STRUCT_LIST: ProtoAdapter?>
    @JvmField val STRUCT_NULL: ProtoAdapter
    @JvmField val STRUCT_VALUE: ProtoAdapter
    @JvmField val DOUBLE_VALUE: ProtoAdapter
    @JvmField val FLOAT_VALUE: ProtoAdapter
    @JvmField val INT64_VALUE: ProtoAdapter
    @JvmField val UINT64_VALUE: ProtoAdapter
    @JvmField val INT32_VALUE: ProtoAdapter
    @JvmField val UINT32_VALUE: ProtoAdapter
    @JvmField val BOOL_VALUE: ProtoAdapter
    @JvmField val STRING_VALUE: ProtoAdapter
    @JvmField val BYTES_VALUE: ProtoAdapter
  }
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncodedSizeWithTag(tag: Int, value: E?): Int {
  if (value == null) return 0
  var size = encodedSize(value)
  if (fieldEncoding == LENGTH_DELIMITED) {
    size += varint32Size(size)
  }
  return size + tagSize(tag)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.delegateEncode(
  writer: ReverseProtoWriter,
  value: E
) {
  writer.writeForward { forwardWriter ->
    encode(forwardWriter, value)
  }
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncodeWithTag(
  writer: ProtoWriter,
  tag: Int,
  value: E?
) {
  if (value == null) return
  writer.writeTag(tag, fieldEncoding)
  if (fieldEncoding == LENGTH_DELIMITED) {
    writer.writeVarint32(encodedSize(value))
  }
  encode(writer, value)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncodeWithTag(
  writer: ReverseProtoWriter,
  tag: Int,
  value: E?
) {
  if (value == null) return
  if (fieldEncoding == LENGTH_DELIMITED) {
    val byteCountBefore = writer.byteCount
    encode(writer, value)
    writer.writeVarint32(writer.byteCount - byteCountBefore)
  } else {
    encode(writer, value)
  }
  writer.writeTag(tag, fieldEncoding)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncode(sink: BufferedSink, value: E) {
  val writer = ReverseProtoWriter()
  encode(writer, value)
  writer.writeTo(sink)
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncode(value: E): ByteArray {
  val buffer = Buffer()
  encode(buffer, value)
  return buffer.readByteArray()
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonEncodeByteString(value: E): ByteString {
  val buffer = Buffer()
  encode(buffer, value)
  return buffer.readByteString()
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonDecode(bytes: ByteArray): E {
  return decode(Buffer().write(bytes))
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonDecode(bytes: ByteString): E {
  return decode(Buffer().write(bytes))
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonDecode(source: BufferedSource): E {
  return decode(ProtoReader(source))
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  commonToString(value: E): String = value.toString()

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonWithLabel(label: WireField.Label): ProtoAdapter<*> {
  if (label.isRepeated) {
    return if (label.isPacked) asPacked() else asRepeated()
  }
  return this
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonCreatePacked(): ProtoAdapter> {
  require(fieldEncoding != LENGTH_DELIMITED) {
    "Unable to pack a length-delimited type."
  }
  return PackedProtoAdapter(originalAdapter = this)
}

internal class PackedProtoAdapter(
  private val originalAdapter: ProtoAdapter
) : ProtoAdapter>(
    LENGTH_DELIMITED,
    List::class,
    null,
    originalAdapter.syntax,
    listOf()
) {
  @Throws(IOException::class)
  override fun encodeWithTag(writer: ProtoWriter, tag: Int, value: List?) {
    if (value != null && value.isNotEmpty()) {
      super.encodeWithTag(writer, tag, value)
    }
  }

  @Throws(IOException::class)
  override fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: List?) {
    if (value != null && value.isNotEmpty()) {
      super.encodeWithTag(writer, tag, value)
    }
  }

  override fun encodedSize(value: List): Int {
    var size = 0
    for (i in 0 until value.size) {
      size += originalAdapter.encodedSize(value[i])
    }
    return size
  }

  override fun encodedSizeWithTag(tag: Int, value: List?): Int {
    return if (value == null || value.isEmpty()) 0 else super.encodedSizeWithTag(tag, value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: List) {
    for (i in 0 until value.size) {
      originalAdapter.encode(writer, value[i])
    }
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: List) {
    for (i in (value.size - 1) downTo 0) {
      originalAdapter.encode(writer, value[i])
    }
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): List = listOf(originalAdapter.decode(reader))

  override fun redact(value: List): List = emptyList()
}

@Suppress("NOTHING_TO_INLINE")
internal inline fun  ProtoAdapter.commonCreateRepeated(): ProtoAdapter> {
  return RepeatedProtoAdapter(originalAdapter = this)
}

internal class RepeatedProtoAdapter(
  private val originalAdapter: ProtoAdapter
) : ProtoAdapter>(
    originalAdapter.fieldEncoding,
    List::class,
    null,
    originalAdapter.syntax,
    listOf()
) {
  override fun encodedSize(value: List): Int {
    throw UnsupportedOperationException("Repeated values can only be sized with a tag.")
  }

  override fun encodedSizeWithTag(tag: Int, value: List?): Int {
    if (value == null) return 0
    var size = 0
    for (i in 0 until value.size) {
      size += originalAdapter.encodedSizeWithTag(tag, value[i])
    }
    return size
  }

  override fun encode(writer: ProtoWriter, value: List) {
    throw UnsupportedOperationException("Repeated values can only be encoded with a tag.")
  }

  override fun encode(writer: ReverseProtoWriter, value: List) {
    throw UnsupportedOperationException("Repeated values can only be encoded with a tag.")
  }

  @Throws(IOException::class)
  override fun encodeWithTag(writer: ProtoWriter, tag: Int, value: List?) {
    if (value == null) return
    for (i in 0 until value.size) {
      originalAdapter.encodeWithTag(writer, tag, value[i])
    }
  }

  @Throws(IOException::class)
  override fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: List?) {
    if (value == null) return
    for (i in (value.size - 1) downTo 0) {
      originalAdapter.encodeWithTag(writer, tag, value[i])
    }
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): List = listOf(originalAdapter.decode(reader))

  override fun redact(value: List): List = emptyList()
}

internal class MapProtoAdapter internal constructor(
  keyAdapter: ProtoAdapter,
  valueAdapter: ProtoAdapter
) : ProtoAdapter>(
    LENGTH_DELIMITED,
    Map::class,
    null,
    valueAdapter.syntax,
    mapOf()
) {
  private val entryAdapter = MapEntryProtoAdapter(keyAdapter, valueAdapter)

  override fun encodedSize(value: Map): Int {
    throw UnsupportedOperationException("Repeated values can only be sized with a tag.")
  }

  override fun encodedSizeWithTag(tag: Int, value: Map?): Int {
    if (value == null) return 0
    var size = 0
    for (entry in value.entries) {
      size += entryAdapter.encodedSizeWithTag(tag, entry)
    }
    return size
  }

  override fun encode(writer: ProtoWriter, value: Map) {
    throw UnsupportedOperationException("Repeated values can only be encoded with a tag.")
  }

  override fun encode(writer: ReverseProtoWriter, value: Map) {
    throw UnsupportedOperationException("Repeated values can only be encoded with a tag.")
  }

  @Throws(IOException::class)
  override fun encodeWithTag(writer: ProtoWriter, tag: Int, value: Map?) {
    if (value == null) return
    for (entry in value.entries) {
      entryAdapter.encodeWithTag(writer, tag, entry)
    }
  }

  @Throws(IOException::class)
  override fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: Map?) {
    if (value == null) return
    for (entry in value.entries.toTypedArray().apply { reverse() }) {
      entryAdapter.encodeWithTag(writer, tag, entry)
    }
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Map {
    var key: K? = null
    var value: V? = null

    val token = reader.beginMessage()
    while (true) {
      val tag = reader.nextTag()
      if (tag == -1) break
      when (tag) {
        1 -> key = entryAdapter.keyAdapter.decode(reader)
        2 -> value = entryAdapter.valueAdapter.decode(reader)
        // Ignore unknown tags in map entries.
      }
    }
    reader.endMessageAndGetUnknownFields(token)

    check(key != null) { "Map entry with null key" }
    check(value != null) { "Map entry with null value" }
    return mapOf(key to value)
  }

  override fun redact(value: Map): Map = emptyMap()
}

private class MapEntryProtoAdapter internal constructor(
  internal val keyAdapter: ProtoAdapter,
  internal val valueAdapter: ProtoAdapter
) : ProtoAdapter>(
    LENGTH_DELIMITED,
    Map.Entry::class,
    null,
    valueAdapter.syntax
) {

  override fun encodedSize(value: Map.Entry): Int {
    return keyAdapter.encodedSizeWithTag(1, value.key) +
        valueAdapter.encodedSizeWithTag(2, value.value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Map.Entry) {
    keyAdapter.encodeWithTag(writer, 1, value.key)
    valueAdapter.encodeWithTag(writer, 2, value.value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Map.Entry) {
    valueAdapter.encodeWithTag(writer, 2, value.value)
    keyAdapter.encodeWithTag(writer, 1, value.key)
  }

  override fun decode(reader: ProtoReader): Map.Entry {
    throw UnsupportedOperationException()
  }

  override fun redact(value: Map.Entry): Map.Entry {
    throw UnsupportedOperationException()
  }
}

private const val FIXED_BOOL_SIZE = 1
private const val FIXED_32_SIZE = 4
private const val FIXED_64_SIZE = 8

@Suppress("NOTHING_TO_INLINE")
internal inline fun  commonNewMapAdapter(
  keyAdapter: ProtoAdapter,
  valueAdapter: ProtoAdapter
): ProtoAdapter> {
  return MapProtoAdapter(keyAdapter, valueAdapter)
}

internal fun commonBool(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Boolean::class,
    null,
    Syntax.PROTO_2,
    false
) {
  override fun encodedSize(value: Boolean): Int = FIXED_BOOL_SIZE

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Boolean) {
    writer.writeVarint32(if (value) 1 else 0)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Boolean) {
    writer.writeVarint32(if (value) 1 else 0)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Boolean = when (reader.readVarint32()) {
    0 -> false
    // We are lenient to match protoc behavior.
    else -> true
  }

  override fun redact(value: Boolean): Boolean = throw UnsupportedOperationException()
}

internal fun commonInt32(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Int::class,
    null,
    Syntax.PROTO_2,
    0
) {
  override fun encodedSize(value: Int): Int = int32Size(value)

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Int) {
    writer.writeSignedVarint32(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Int) {
    writer.writeSignedVarint32(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Int = reader.readVarint32()

  override fun redact(value: Int): Int = throw UnsupportedOperationException()
}

internal fun commonUint32(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Int::class,
    null,
    Syntax.PROTO_2,
    0
) {
  override fun encodedSize(value: Int): Int = varint32Size(value)

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Int) {
    writer.writeVarint32(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Int) {
    writer.writeVarint32(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Int = reader.readVarint32()

  override fun redact(value: Int): Int = throw UnsupportedOperationException()
}

internal fun commonSint32(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Int::class,
    null,
    Syntax.PROTO_2,
    0
) {
  override fun encodedSize(value: Int): Int = varint32Size(encodeZigZag32(value))

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Int) {
    writer.writeVarint32(encodeZigZag32(value))
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Int) {
    writer.writeVarint32(encodeZigZag32(value))
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Int = decodeZigZag32(reader.readVarint32())

  override fun redact(value: Int): Int = throw UnsupportedOperationException()
}

internal fun commonFixed32(): ProtoAdapter = object : ProtoAdapter(
    FieldEncoding.FIXED32,
    Int::class,
    null,
    Syntax.PROTO_2,
    0
) {
  override fun encodedSize(value: Int): Int = FIXED_32_SIZE

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Int) {
    writer.writeFixed32(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Int) {
    writer.writeFixed32(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Int = reader.readFixed32()

  override fun redact(value: Int): Int = throw UnsupportedOperationException()
}

internal fun commonSfixed32() = commonFixed32()
internal fun commonInt64(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Long::class,
    null,
    Syntax.PROTO_2,
    0L
) {
  override fun encodedSize(value: Long): Int = varint64Size(value)

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Long) {
    writer.writeVarint64(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Long) {
    writer.writeVarint64(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Long = reader.readVarint64()

  override fun redact(value: Long): Long = throw UnsupportedOperationException()
}

/**
 * Like INT64, but negative longs are interpreted as large positive values, and encoded that way
 * in JSON.
 */
internal fun commonUint64(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Long::class,
    null,
    Syntax.PROTO_2,
    0L
) {
  override fun encodedSize(value: Long): Int = varint64Size(value)

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Long) {
    writer.writeVarint64(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Long) {
    writer.writeVarint64(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Long = reader.readVarint64()

  override fun redact(value: Long): Long = throw UnsupportedOperationException()
}

internal fun commonSint64(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Long::class,
    null,
    Syntax.PROTO_2,
    0L
) {
  override fun encodedSize(value: Long): Int = varint64Size(encodeZigZag64(value))

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Long) {
    writer.writeVarint64(encodeZigZag64(value))
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Long) {
    writer.writeVarint64(encodeZigZag64(value))
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Long = decodeZigZag64(reader.readVarint64())

  override fun redact(value: Long): Long = throw UnsupportedOperationException()
}

internal fun commonFixed64(): ProtoAdapter = object : ProtoAdapter(
    FieldEncoding.FIXED64,
    Long::class,
    null,
    Syntax.PROTO_2,
    0L
) {
  override fun encodedSize(value: Long): Int = FIXED_64_SIZE

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Long) {
    writer.writeFixed64(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Long) {
    writer.writeFixed64(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Long = reader.readFixed64()

  override fun redact(value: Long): Long = throw UnsupportedOperationException()
}

internal fun commonSfixed64() = commonFixed64()
internal fun commonFloat(): ProtoAdapter = object : ProtoAdapter(
    FieldEncoding.FIXED32,
    Float::class,
    null,
    Syntax.PROTO_2,
    0.0f
) {
  override fun encodedSize(value: Float): Int = FIXED_32_SIZE

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Float) {
    writer.writeFixed32(value.toBits())
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Float) {
    writer.writeFixed32(value.toBits())
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Float {
    return Float.fromBits(reader.readFixed32())
  }

  override fun redact(value: Float): Float = throw UnsupportedOperationException()
}

internal fun commonDouble(): ProtoAdapter = object : ProtoAdapter(
    FieldEncoding.FIXED64,
    Double::class,
    null,
    Syntax.PROTO_2,
    0.0
) {
  override fun encodedSize(value: Double): Int = FIXED_64_SIZE

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: Double) {
    writer.writeFixed64(value.toBits())
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: Double) {
    writer.writeFixed64(value.toBits())
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): Double {
    return Double.fromBits(reader.readFixed64())
  }

  override fun redact(value: Double): Double = throw UnsupportedOperationException()
}

internal fun commonString(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    String::class,
    null,
    Syntax.PROTO_2,
    ""
) {
  override fun encodedSize(value: String): Int = value.utf8Size().toInt()

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: String) {
    writer.writeString(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: String) {
    writer.writeString(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): String = reader.readString()

  override fun redact(value: String): String = throw UnsupportedOperationException()
}

internal fun commonBytes(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    ByteString::class,
    null,
    Syntax.PROTO_2,
    ByteString.EMPTY
) {
  override fun encodedSize(value: ByteString): Int = value.size

  @Throws(IOException::class)
  override fun encode(writer: ProtoWriter, value: ByteString) {
    writer.writeBytes(value)
  }

  @Throws(IOException::class)
  override fun encode(writer: ReverseProtoWriter, value: ByteString) {
    writer.writeBytes(value)
  }

  @Throws(IOException::class)
  override fun decode(reader: ProtoReader): ByteString = reader.readBytes()

  override fun redact(value: ByteString): ByteString = throw UnsupportedOperationException()
}

internal fun commonDuration(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    Duration::class,
    "type.googleapis.com/google.protobuf.Duration",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Duration): Int {
    var result = 0
    val seconds = value.sameSignSeconds
    if (seconds != 0L) result += INT64.encodedSizeWithTag(1, seconds)
    val nanos = value.sameSignNanos
    if (nanos != 0) result += INT32.encodedSizeWithTag(2, nanos)
    return result
  }

  override fun encode(writer: ProtoWriter, value: Duration) {
    val seconds = value.sameSignSeconds
    if (seconds != 0L) INT64.encodeWithTag(writer, 1, seconds)
    val nanos = value.sameSignNanos
    if (nanos != 0) INT32.encodeWithTag(writer, 2, nanos)
  }

  override fun encode(writer: ReverseProtoWriter, value: Duration) {
    val nanos = value.sameSignNanos
    if (nanos != 0) INT32.encodeWithTag(writer, 2, nanos)
    val seconds = value.sameSignSeconds
    if (seconds != 0L) INT64.encodeWithTag(writer, 1, seconds)
  }

  override fun decode(reader: ProtoReader): Duration {
    var seconds = 0L
    var nanos = 0
    reader.forEachTag { tag ->
      when (tag) {
        1 -> seconds = INT64.decode(reader)
        2 -> nanos = INT32.decode(reader)
        else -> reader.readUnknownField(tag)
      }
    }
    return durationOfSeconds(seconds, nanos.toLong())
  }

  override fun redact(value: Duration): Duration = value

  /**
   * Returns a value like 1 for 1.200s and -1 for -1.200s. This is different from the Duration
   * seconds field which is always the integer floor when seconds is negative.
   */
  private val Duration.sameSignSeconds: Long
    get() {
      return when {
        getSeconds() < 0L && getNano() != 0 -> getSeconds() + 1L
        else -> getSeconds()
      }
    }

  /**
   * Returns a value like 200_000_000 for 1.200s and -200_000_000 for -1.200s. This is different
   * from the Duration nanos field which can be positive when seconds is negative.
   */
  private val Duration.sameSignNanos: Int
    get() {
      return when {
        getSeconds() < 0L && getNano() != 0 -> getNano() - 1_000_000_000
        else -> getNano()
      }
    }
}

internal fun commonInstant(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    Instant::class,
    "type.googleapis.com/google.protobuf.Timestamp",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Instant): Int {
    var result = 0
    val seconds = value.getEpochSecond()
    if (seconds != 0L) result += INT64.encodedSizeWithTag(1, seconds)
    val nanos = value.getNano()
    if (nanos != 0) result += INT32.encodedSizeWithTag(2, nanos)
    return result
  }

  override fun encode(writer: ProtoWriter, value: Instant) {
    val seconds = value.getEpochSecond()
    if (seconds != 0L) INT64.encodeWithTag(writer, 1, seconds)
    val nanos = value.getNano()
    if (nanos != 0) INT32.encodeWithTag(writer, 2, nanos)
  }

  override fun encode(writer: ReverseProtoWriter, value: Instant) {
    val nanos = value.getNano()
    if (nanos != 0) INT32.encodeWithTag(writer, 2, nanos)
    val seconds = value.getEpochSecond()
    if (seconds != 0L) INT64.encodeWithTag(writer, 1, seconds)
  }

  override fun decode(reader: ProtoReader): Instant {
    var seconds = 0L
    var nanos = 0
    reader.forEachTag { tag ->
      when (tag) {
        1 -> seconds = INT64.decode(reader)
        2 -> nanos = INT32.decode(reader)
        else -> reader.readUnknownField(tag)
      }
    }
    return ofEpochSecond(seconds, nanos.toLong())
  }

  override fun redact(value: Instant): Instant = value
}

internal fun commonEmpty(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    Unit::class,
    "type.googleapis.com/google.protobuf.Empty",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Unit): Int = 0

  override fun encode(writer: ProtoWriter, value: Unit) = Unit

  override fun encode(writer: ReverseProtoWriter, value: Unit) = Unit

  override fun decode(reader: ProtoReader) {
    reader.forEachTag { tag -> reader.readUnknownField(tag) }
  }

  override fun redact(value: Unit): Unit = value
}

internal fun commonStructMap(): ProtoAdapter?> = object : ProtoAdapter?>(
    LENGTH_DELIMITED,
    Map::class,
    "type.googleapis.com/google.protobuf.Struct",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Map?): Int {
    if (value == null) return 0

    var size = 0
    for ((k, v) in value) {
      val entrySize = STRING.encodedSizeWithTag(1, k) + STRUCT_VALUE.encodedSizeWithTag(2, v)
      size += tagSize(1) + varint32Size(entrySize) + entrySize
    }
    return size
  }

  override fun encode(writer: ProtoWriter, value: Map?) {
    if (value == null) return

    for ((k, v) in value) {
      val entrySize = STRING.encodedSizeWithTag(1, k) + STRUCT_VALUE.encodedSizeWithTag(2, v)
      writer.writeTag(1, LENGTH_DELIMITED)
      writer.writeVarint32(entrySize)
      STRING.encodeWithTag(writer, 1, k)
      STRUCT_VALUE.encodeWithTag(writer, 2, v)
    }
  }

  override fun encode(
    writer: ReverseProtoWriter,
    value: Map?
  ) {
    if (value == null) return

    for ((k, v) in value.entries.toTypedArray().apply { reverse() }) {
      val byteCountBefore = writer.byteCount
      STRUCT_VALUE.encodeWithTag(writer, 2, v)
      STRING.encodeWithTag(writer, 1, k)
      writer.writeVarint32(writer.byteCount - byteCountBefore)
      writer.writeTag(1, LENGTH_DELIMITED)
    }
  }

  override fun decode(reader: ProtoReader): Map? {
    val result = mutableMapOf()
    reader.forEachTag { entryTag ->
      if (entryTag != 1) return@forEachTag reader.skip()

      var key: String? = null
      var value: Any? = null
      reader.forEachTag { tag ->
        when (tag) {
          1 -> key = STRING.decode(reader)
          2 -> value = STRUCT_VALUE.decode(reader)
          else -> reader.readUnknownField(tag)
        }
      }
      if (key != null) result[key!!] = value
    }
    return result
  }

  override fun redact(value: Map?) = value?.mapValues { STRUCT_VALUE.redact(it) }
}

internal fun commonStructList(): ProtoAdapter?> = object : ProtoAdapter?>(
    LENGTH_DELIMITED,
    Map::class,
    "type.googleapis.com/google.protobuf.ListValue",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: List<*>?): Int {
    if (value == null) return 0

    var result = 0
    for (v in value) {
      result += STRUCT_VALUE.encodedSizeWithTag(1, v)
    }
    return result
  }

  override fun encode(writer: ProtoWriter, value: List<*>?) {
    if (value == null) return
    for (v in value) {
      STRUCT_VALUE.encodeWithTag(writer, 1, v)
    }
  }

  override fun encode(writer: ReverseProtoWriter, value: List<*>?) {
    if (value == null) return
    for (v in (value.size - 1) downTo 0) {
      STRUCT_VALUE.encodeWithTag(writer, 1, value[v])
    }
  }

  override fun decode(reader: ProtoReader): List<*>? {
    val result = mutableListOf()
    reader.forEachTag { entryTag ->
      if (entryTag != 1) return@forEachTag reader.skip()
      result.add(STRUCT_VALUE.decode(reader))
    }
    return result
  }

  override fun redact(value: List<*>?) = value?.map { STRUCT_VALUE.redact(it) }
}

internal fun commonStructNull(): ProtoAdapter = object : ProtoAdapter(
    VARINT,
    Nothing::class,
    "type.googleapis.com/google.protobuf.NullValue",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Nothing?): Int = varint32Size(0)

  override fun encodedSizeWithTag(tag: Int, value: Nothing?): Int {
    val size = encodedSize(value)
    return tagSize(tag) + varint32Size(size)
  }

  override fun encode(writer: ProtoWriter, value: Nothing?) {
    writer.writeVarint32(0)
  }

  override fun encode(writer: ReverseProtoWriter, value: Nothing?) {
    writer.writeVarint32(0)
  }

  override fun encodeWithTag(writer: ProtoWriter, tag: Int, value: Nothing?) {
    writer.writeTag(tag, fieldEncoding)
    encode(writer, value)
  }

  override fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: Nothing?) {
    encode(writer, value)
    writer.writeTag(tag, fieldEncoding)
  }

  override fun decode(reader: ProtoReader): Nothing? {
    val value = reader.readVarint32()
    if (value != 0) throw IOException("expected 0 but was $value")
    return null
  }

  override fun redact(value: Nothing?): Nothing? = null
}

internal fun commonStructValue(): ProtoAdapter = object : ProtoAdapter(
    LENGTH_DELIMITED,
    Any::class,
    "type.googleapis.com/google.protobuf.Value",
    Syntax.PROTO_3
) {
  override fun encodedSize(value: Any?): Int {
    @Suppress("UNCHECKED_CAST") // Assume map keys are strings.
    return when (value) {
      null -> STRUCT_NULL.encodedSizeWithTag(1, value)
      is Number -> DOUBLE.encodedSizeWithTag(2, value.toDouble())
      is String -> STRING.encodedSizeWithTag(3, value)
      is Boolean -> BOOL.encodedSizeWithTag(4, value)
      is Map<*, *> -> STRUCT_MAP.encodedSizeWithTag(5, value as Map)
      is List<*> -> STRUCT_LIST.encodedSizeWithTag(6, value)
      else -> throw IllegalArgumentException("unexpected struct value: $value")
    }
  }

  override fun encodedSizeWithTag(tag: Int, value: Any?): Int {
    if (value == null) {
      val size = encodedSize(value)
      return tagSize(tag) + varint32Size(size) + size
    } else {
      return super.encodedSizeWithTag(tag, value)
    }
  }

  override fun encode(writer: ProtoWriter, value: Any?) {
    @Suppress("UNCHECKED_CAST") // Assume map keys are strings.
    return when (value) {
      null -> STRUCT_NULL.encodeWithTag(writer, 1, value)
      is Number -> DOUBLE.encodeWithTag(writer, 2, value.toDouble())
      is String -> STRING.encodeWithTag(writer, 3, value)
      is Boolean -> BOOL.encodeWithTag(writer, 4, value)
      is Map<*, *> -> STRUCT_MAP.encodeWithTag(writer, 5, value as Map)
      is List<*> -> STRUCT_LIST.encodeWithTag(writer, 6, value)
      else -> throw IllegalArgumentException("unexpected struct value: $value")
    }
  }

  override fun encode(writer: ReverseProtoWriter, value: Any?) {
    @Suppress("UNCHECKED_CAST") // Assume map keys are strings.
    return when (value) {
      null -> STRUCT_NULL.encodeWithTag(writer, 1, value)
      is Number -> DOUBLE.encodeWithTag(writer, 2, value.toDouble())
      is String -> STRING.encodeWithTag(writer, 3, value)
      is Boolean -> BOOL.encodeWithTag(writer, 4, value)
      is Map<*, *> -> STRUCT_MAP.encodeWithTag(writer, 5, value as Map)
      is List<*> -> STRUCT_LIST.encodeWithTag(writer, 6, value)
      else -> throw IllegalArgumentException("unexpected struct value: $value")
    }
  }

  override fun encodeWithTag(writer: ProtoWriter, tag: Int, value: Any?) {
    if (value == null) {
      writer.writeTag(tag, fieldEncoding)
      writer.writeVarint32(encodedSize(value))
      encode(writer, value)
    } else {
      super.encodeWithTag(writer, tag, value)
    }
  }

  override fun encodeWithTag(writer: ReverseProtoWriter, tag: Int, value: Any?) {
    if (value == null) {
      val byteCountBefore = writer.byteCount
      encode(writer, value)
      writer.writeVarint32(writer.byteCount - byteCountBefore)
      writer.writeTag(tag, fieldEncoding)
    } else {
      super.encodeWithTag(writer, tag, value)
    }
  }

  override fun decode(reader: ProtoReader): Any? {
    var result: Any? = null
    reader.forEachTag { tag ->
      when (tag) {
        1 -> result = STRUCT_NULL.decode(reader)
        2 -> result = DOUBLE.decode(reader)
        3 -> result = STRING.decode(reader)
        4 -> result = BOOL.decode(reader)
        5 -> result = STRUCT_MAP.decode(reader)
        6 -> result = STRUCT_LIST.decode(reader)
        else -> reader.skip()
      }
    }
    return result
  }

  override fun redact(value: Any?): Any? {
    @Suppress("UNCHECKED_CAST") // Assume map keys are strings.
    return when (value) {
      null -> STRUCT_NULL.redact(value)
      is Number -> value
      is String -> null
      is Boolean -> value
      is Map<*, *> -> STRUCT_MAP.redact(value as Map)
      is List<*> -> STRUCT_LIST.redact(value)
      else -> throw IllegalArgumentException("unexpected struct value: $value")
    }
  }
}

internal fun  commonWrapper(delegate: ProtoAdapter, typeUrl: String): ProtoAdapter {
  return object : ProtoAdapter(
      LENGTH_DELIMITED,
      delegate.type,
      typeUrl,
      Syntax.PROTO_3,
      null
  ) {
    override fun encodedSize(value: T?): Int {
      if (value == null) return 0
      return delegate.encodedSizeWithTag(1, value)
    }

    override fun encode(writer: ProtoWriter, value: T?) {
      if (value != null) {
        delegate.encodeWithTag(writer, 1, value)
      }
    }

    override fun encode(writer: ReverseProtoWriter, value: T?) {
      if (value != null) {
        delegate.encodeWithTag(writer, 1, value)
      }
    }

    override fun decode(reader: ProtoReader): T? {
      var result: T? = null
      reader.forEachTag { tag ->
        when (tag) {
          1 -> result = delegate.decode(reader)
          else -> reader.readUnknownField(tag)
        }
      }
      return result
    }

    override fun redact(value: T?): T? {
      if (value == null) return null
      return delegate.redact(value)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy