Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

platform bytes class #204

Merged
merged 7 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package protokt.v1

import com.google.auto.service.AutoService
import protokt.v1.JvmBytes.asReadOnlyBuffer
import protokt.v1.SizeCodecs.sizeOf
import java.nio.ByteBuffer
import java.util.UUID
Expand Down
30 changes: 15 additions & 15 deletions protokt-runtime/api/protokt-runtime.api
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,16 @@ public final class com/toasttab/protokt/rt/VarintVal : com/toasttab/protokt/rt/U
public fun toString ()Ljava/lang/String;
}

public abstract class protokt/v1/AbstractBytes {
public final fun equals (Ljava/lang/Object;)Z
public final fun getBytes ()[B
public final fun hashCode ()I
public final fun isEmpty ()Z
public final fun isNotEmpty ()Z
public final fun toBytesSlice ()Lprotokt/v1/BytesSlice;
public final fun toString ()Ljava/lang/String;
}

public abstract class protokt/v1/AbstractKtDeserializer : protokt/v1/KtDeserializer {
public fun <init> ()V
public synthetic fun deserialize (Lcom/google/protobuf/CodedInputStream;)Lcom/toasttab/protokt/rt/KtMessage;
Expand Down Expand Up @@ -483,22 +493,19 @@ public abstract class protokt/v1/AbstractKtMessage : protokt/v1/KtMessage {
public fun serialize (Ljava/io/OutputStream;)V
}

public final class protokt/v1/Bytes {
public final class protokt/v1/Bytes : protokt/v1/AbstractBytes {
public static final field Companion Lprotokt/v1/Bytes$Companion;
public final fun asReadOnlyBuffer ()Ljava/nio/ByteBuffer;
public static final fun empty ()Lprotokt/v1/Bytes;
public fun equals (Ljava/lang/Object;)Z
public static final fun from (Ljava/io/InputStream;)Lprotokt/v1/Bytes;
public static final fun from (Lprotokt/v1/KtMessage;)Lprotokt/v1/Bytes;
public static final fun from ([B)Lprotokt/v1/Bytes;
public final fun getBytes ()[B
public fun hashCode ()I
public final fun isEmpty ()Z
public final fun isNotEmpty ()Z
public final fun toBytesSlice ()Lprotokt/v1/BytesSlice;
public fun toString ()Ljava/lang/String;
public final fun inputStream ()Ljava/io/InputStream;
}

public final class protokt/v1/Bytes$Companion {
public final fun empty ()Lprotokt/v1/Bytes;
public final fun from (Ljava/io/InputStream;)Lprotokt/v1/Bytes;
public final fun from (Lprotokt/v1/KtMessage;)Lprotokt/v1/Bytes;
public final fun from ([B)Lprotokt/v1/Bytes;
}
Expand Down Expand Up @@ -561,13 +568,6 @@ public final class protokt/v1/Fixed64Val : protokt/v1/UnknownValue {
public final synthetic fun unbox-impl ()J
}

public final class protokt/v1/JvmBytes {
public static final field INSTANCE Lprotokt/v1/JvmBytes;
public static final fun asReadOnlyBuffer (Lprotokt/v1/Bytes;)Ljava/nio/ByteBuffer;
public static final fun from (Lprotokt/v1/Bytes$Companion;Ljava/io/InputStream;)Lprotokt/v1/Bytes;
public static final fun inputStream (Lprotokt/v1/Bytes;)Ljava/io/InputStream;
}

public abstract interface annotation class protokt/v1/KtBuilderDsl : java/lang/annotation/Annotation {
}

Expand Down
54 changes: 54 additions & 0 deletions protokt-runtime/src/commonMain/kotlin/protokt/v1/AbstractBytes.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2023 Toast, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package protokt.v1

abstract class AbstractBytes internal constructor(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be the only way to share this code.

internal val value: ByteArray
) {
val bytes
get() = clone(value)

fun isNotEmpty() =
value.isNotEmpty()

fun isEmpty() =
value.isEmpty()

fun toBytesSlice() =
BytesSlice(value)

final override fun equals(other: Any?) =
other is Bytes && value.contentEquals(other.value)

final override fun hashCode() =
value.contentHashCode()

final override fun toString() =
value.contentToString()

internal companion object {
Copy link
Collaborator Author

@andrewparmet andrewparmet Oct 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used to hold common code in implementation companions rather than exposing a new public class. The same could be done with AbstractBytes but then the implementation would have to call into this object rather than inheriting the correct behavior. This pattern is already used in AbstractKtMessage and AbstractKtDeserializer, so it feels OK to be consistent with those.

private val EMPTY = Bytes(ByteArray(0))

fun empty() =
EMPTY

fun from(bytes: ByteArray) =
Bytes(clone(bytes))

fun from(message: KtMessage) =
Bytes(message.serialize())
}
}
38 changes: 6 additions & 32 deletions protokt-runtime/src/commonMain/kotlin/protokt/v1/Bytes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,18 @@ package protokt.v1

import kotlin.jvm.JvmStatic

class Bytes internal constructor(
internal val value: ByteArray
) {
val bytes
get() = clone(value)

fun isNotEmpty() =
value.isNotEmpty()

fun isEmpty() =
value.isEmpty()

fun toBytesSlice() =
BytesSlice(value)

override fun equals(other: Any?) =
other is Bytes && value.contentEquals(other.value)

override fun hashCode() =
value.contentHashCode()

override fun toString() =
value.contentToString()

expect class Bytes internal constructor(
value: ByteArray
) : AbstractBytes {
companion object {
private val EMPTY = Bytes(ByteArray(0))

@JvmStatic
fun empty() =
EMPTY
fun empty(): Bytes

@JvmStatic
fun from(bytes: ByteArray) =
Bytes(clone(bytes))
fun from(bytes: ByteArray): Bytes

@JvmStatic
fun from(message: KtMessage) =
Bytes(message.serialize())
fun from(message: KtMessage): Bytes
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Toast, Inc.
* Copyright (c) 2023 Toast, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,5 +15,18 @@

package protokt.v1

actual class Bytes internal actual constructor(value: ByteArray) : AbstractBytes(value) {
actual companion object {
actual fun empty() =
AbstractBytes.empty()

actual fun from(bytes: ByteArray) =
AbstractBytes.from(bytes)

actual fun from(message: KtMessage) =
AbstractBytes.from(message)
}
}

internal actual fun clone(bytes: ByteArray) =
bytes.copyOf()
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Toast, Inc.
* Copyright (c) 2023 Toast, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,20 +17,33 @@ package protokt.v1

import java.io.InputStream
import java.nio.ByteBuffer
import kotlin.jvm.JvmStatic

internal actual fun clone(bytes: ByteArray) =
bytes.clone()

object JvmBytes {
@JvmStatic
fun Bytes.asReadOnlyBuffer(): ByteBuffer =
actual class Bytes internal actual constructor(value: ByteArray) : AbstractBytes(value) {
fun asReadOnlyBuffer(): ByteBuffer =
ByteBuffer.wrap(value).asReadOnlyBuffer()

@JvmStatic
fun Bytes.inputStream(): InputStream =
fun inputStream(): InputStream =
value.inputStream()

@JvmStatic
fun Bytes.Companion.from(stream: InputStream) =
Bytes(stream.readBytes())
actual companion object {
@JvmStatic
actual fun empty() =
AbstractBytes.empty()

@JvmStatic
actual fun from(bytes: ByteArray) =
AbstractBytes.from(bytes)

@JvmStatic
actual fun from(message: KtMessage) =
AbstractBytes.from(message)

@JvmStatic
fun from(stream: InputStream) =
AbstractBytes.from(stream.readBytes())
}
}

internal actual fun clone(bytes: ByteArray) =
bytes.clone()
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package protokt.v1.testing
import com.google.auto.service.AutoService
import protokt.v1.Bytes
import protokt.v1.Converter
import protokt.v1.JvmBytes.from

data class Id(val value: String)

Expand Down