diff --git a/bytestring/api/kotlinx-io-bytestring.api b/bytestring/api/kotlinx-io-bytestring.api index b51c6fc9c..e2adb277a 100644 --- a/bytestring/api/kotlinx-io-bytestring.api +++ b/bytestring/api/kotlinx-io-bytestring.api @@ -69,7 +69,9 @@ public final class kotlinx/io/bytestring/ByteStringJvmExtKt { } public final class kotlinx/io/bytestring/ByteStringKt { + public static final fun ByteString ()Lkotlinx/io/bytestring/ByteString; public static final fun ByteString ([B)Lkotlinx/io/bytestring/ByteString; + public static final fun ByteString-GBYM_sE ([B)Lkotlinx/io/bytestring/ByteString; public static final fun contentEquals (Lkotlinx/io/bytestring/ByteString;[B)Z public static final fun decodeToString (Lkotlinx/io/bytestring/ByteString;)Ljava/lang/String; public static final fun encodeToByteString (Ljava/lang/String;)Lkotlinx/io/bytestring/ByteString; diff --git a/bytestring/api/kotlinx-io-bytestring.klib.api b/bytestring/api/kotlinx-io-bytestring.klib.api index 7dd54088d..9dcca2ee0 100644 --- a/bytestring/api/kotlinx-io-bytestring.klib.api +++ b/bytestring/api/kotlinx-io-bytestring.klib.api @@ -80,5 +80,7 @@ final fun (kotlinx.io.bytestring/ByteStringBuilder).kotlinx.io.bytestring/append final fun (kotlinx.io.bytestring/ByteStringBuilder).kotlinx.io.bytestring/append(kotlin/UByte) // kotlinx.io.bytestring/append|append@kotlinx.io.bytestring.ByteStringBuilder(kotlin.UByte){}[0] final fun (kotlinx.io.bytestring/ByteStringBuilder).kotlinx.io.bytestring/append(kotlinx.io.bytestring/ByteString) // kotlinx.io.bytestring/append|append@kotlinx.io.bytestring.ByteStringBuilder(kotlinx.io.bytestring.ByteString){}[0] final fun <#A: kotlin.text/Appendable> (kotlin.io.encoding/Base64).kotlinx.io.bytestring/encodeToAppendable(kotlinx.io.bytestring/ByteString, #A, kotlin/Int = ..., kotlin/Int = ...): #A // kotlinx.io.bytestring/encodeToAppendable|encodeToAppendable@kotlin.io.encoding.Base64(kotlinx.io.bytestring.ByteString;0:0;kotlin.Int;kotlin.Int){0ยง}[0] +final fun kotlinx.io.bytestring/ByteString(): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteString|ByteString(){}[0] final fun kotlinx.io.bytestring/ByteString(kotlin/ByteArray...): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteString|ByteString(kotlin.ByteArray...){}[0] +final fun kotlinx.io.bytestring/ByteString(kotlin/UByteArray...): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/ByteString|ByteString(kotlin.UByteArray...){}[0] final inline fun kotlinx.io.bytestring/buildByteString(kotlin/Int = ..., kotlin/Function1): kotlinx.io.bytestring/ByteString // kotlinx.io.bytestring/buildByteString|buildByteString(kotlin.Int;kotlin.Function1){}[0] diff --git a/bytestring/common/src/ByteString.kt b/bytestring/common/src/ByteString.kt index 19ecef0d8..29820b880 100644 --- a/bytestring/common/src/ByteString.kt +++ b/bytestring/common/src/ByteString.kt @@ -21,6 +21,7 @@ package kotlinx.io.bytestring +import kotlin.js.JsName import kotlin.math.max import kotlin.math.min @@ -37,6 +38,26 @@ public fun ByteString(vararg bytes: Byte): ByteString = if (bytes.isEmpty()) { ByteString.wrap(bytes) } +/** + * Wraps given [bytes] into a byte string. + * + * Internally, [bytes] will be stored as [ByteArray], and accesses to individual + * [ByteString]'s bytes will return a signed [Byte] as if someone call `bytes[i].toByte()`. + * + * @param bytes a sequence of bytes to be wrapped. + * + * @sample kotlinx.io.bytestring.samples.ByteStringSamples.constructionFromUBytesSample + */ +@OptIn(ExperimentalUnsignedTypes::class) +public fun ByteString(vararg bytes: UByte): ByteString = if (bytes.isEmpty()) { + ByteString.EMPTY +} else { + ByteString.wrap(bytes.asByteArray()) +} + +@JsName("EmptyByteString") +public fun ByteString(): ByteString = ByteString.EMPTY + /** * An immutable wrapper around a byte sequence providing [String] like functionality. * diff --git a/bytestring/common/test/ByteStringTest.kt b/bytestring/common/test/ByteStringTest.kt index 3fe4733c5..5aefaf5f5 100644 --- a/bytestring/common/test/ByteStringTest.kt +++ b/bytestring/common/test/ByteStringTest.kt @@ -410,4 +410,14 @@ class ByteStringTest { assertFalse(ByteString(1, 2, 3, 4, 5).contentEquals(byteArrayOf(1, 2, 3, 4, 5, 6))) assertFalse(ByteString(1, 2, 3, 4, 5, 6).contentEquals(byteArrayOf(1, 2, 3, 4, 5))) } + + @OptIn(ExperimentalUnsignedTypes::class) + @Test + fun fromUBytes() { + val str = ByteString(0xDEu, 0xADu, 0xC0u, 0xDEu) + assertContentEquals( + byteArrayOf(0xDE.toByte(), 0xAD.toByte(), 0xC0u.toByte(), 0xDEu.toByte()), + str.toByteArray() + ) + } } diff --git a/bytestring/common/test/samples/samples.kt b/bytestring/common/test/samples/samples.kt index 2d0162e12..06fe8079c 100644 --- a/bytestring/common/test/samples/samples.kt +++ b/bytestring/common/test/samples/samples.kt @@ -199,6 +199,14 @@ class ByteStringSamples { assertEquals(3, byteStringFromBytes.size) } + @OptIn(ExperimentalUnsignedTypes::class) + @Test + fun constructionFromUBytesSample() { + val byteStringFromBytes = ByteString(0xCAu, 0xFEu) + assertFalse(byteStringFromBytes.isEmpty()) + assertEquals(2, byteStringFromBytes.size) + } + @Test fun encodeAndDecodeUtf8String() { val helloAsByteString = "hello".encodeToByteString()