From 3af04ea5bb40bc1a9f722d7472b32aff141b378a Mon Sep 17 00:00:00 2001 From: 0marperez Date: Wed, 29 Oct 2025 22:51:39 -0400 Subject: [PATCH 1/3] feat: sdk source readRemaining --- runtime/runtime-core/api/runtime-core.api | 1 + .../src/aws/smithy/kotlin/runtime/io/SdkSource.kt | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index 0e8f85de3a..61628e31f9 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -1097,6 +1097,7 @@ public abstract interface class aws/smithy/kotlin/runtime/io/SdkSource : java/io public final class aws/smithy/kotlin/runtime/io/SdkSourceKt { public static final fun readFully (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/io/SdkBuffer;J)V + public static final fun readRemaining (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/io/SdkBuffer;)V public static final fun readToByteArray (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun toSdkByteReadChannel (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlinx/coroutines/CoroutineScope;)Laws/smithy/kotlin/runtime/io/SdkByteReadChannel; public static synthetic fun toSdkByteReadChannel$default (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlinx/coroutines/CoroutineScope;ILjava/lang/Object;)Laws/smithy/kotlin/runtime/io/SdkByteReadChannel; diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt index aefb75dc08..cf26af62a7 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt @@ -110,3 +110,18 @@ public fun SdkSource.readFully(sink: SdkBuffer, byteCount: Long) { totalBytesRead += rc } } + +/** + * **Caution** Reads the entire contents of the source into [sink]. + * This function will read until the source is exhausted and no bytes remain + * + * @param sink the buffer that data read from the source will be appended to + */ +@InternalApi +public fun SdkSource.readRemaining(sink: SdkBuffer) { + var readBytes: Long + do { + // ensure any errors are propagated by attempting to read at least once + readBytes = read(sink, Long.MAX_VALUE) + } while (readBytes != -1L) +} From 6958bfcdf9ccc3ec8ff1f6c3d85a8cb5112db314 Mon Sep 17 00:00:00 2001 From: 0marperez Date: Thu, 30 Oct 2025 11:31:35 -0400 Subject: [PATCH 2/3] feedback --- runtime/runtime-core/api/runtime-core.api | 2 +- .../common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index 61628e31f9..e488735251 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -1097,7 +1097,7 @@ public abstract interface class aws/smithy/kotlin/runtime/io/SdkSource : java/io public final class aws/smithy/kotlin/runtime/io/SdkSourceKt { public static final fun readFully (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/io/SdkBuffer;J)V - public static final fun readRemaining (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/io/SdkBuffer;)V + public static final fun readRemaining (Laws/smithy/kotlin/runtime/io/SdkSource;Laws/smithy/kotlin/runtime/io/SdkBuffer;)J public static final fun readToByteArray (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun toSdkByteReadChannel (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlinx/coroutines/CoroutineScope;)Laws/smithy/kotlin/runtime/io/SdkByteReadChannel; public static synthetic fun toSdkByteReadChannel$default (Laws/smithy/kotlin/runtime/io/SdkSource;Lkotlinx/coroutines/CoroutineScope;ILjava/lang/Object;)Laws/smithy/kotlin/runtime/io/SdkByteReadChannel; diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt index cf26af62a7..4aa8e9fc4c 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt @@ -118,10 +118,15 @@ public fun SdkSource.readFully(sink: SdkBuffer, byteCount: Long) { * @param sink the buffer that data read from the source will be appended to */ @InternalApi -public fun SdkSource.readRemaining(sink: SdkBuffer) { +public fun SdkSource.readRemaining(sink: SdkBuffer): Long { + var totalReadBytes: Long = 0 var readBytes: Long + do { // ensure any errors are propagated by attempting to read at least once readBytes = read(sink, Long.MAX_VALUE) + totalReadBytes += readBytes } while (readBytes != -1L) + + return totalReadBytes + 1L // Account for last -1 read } From d51e9a865c68d5eb268f7929377fce57fd9b302c Mon Sep 17 00:00:00 2001 From: 0marperez Date: Mon, 24 Nov 2025 16:09:59 -0500 Subject: [PATCH 3/3] feedback --- .../aws/smithy/kotlin/runtime/io/SdkSource.kt | 15 +++-- .../smithy/kotlin/runtime/io/SdkSourceTest.kt | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/io/SdkSourceTest.kt diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt index 4aa8e9fc4c..061e2afaf2 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/io/SdkSource.kt @@ -119,14 +119,13 @@ public fun SdkSource.readFully(sink: SdkBuffer, byteCount: Long) { */ @InternalApi public fun SdkSource.readRemaining(sink: SdkBuffer): Long { - var totalReadBytes: Long = 0 - var readBytes: Long + var totalBytesRead: Long = 0 + var bytesRead = read(sink, Long.MAX_VALUE) - do { - // ensure any errors are propagated by attempting to read at least once - readBytes = read(sink, Long.MAX_VALUE) - totalReadBytes += readBytes - } while (readBytes != -1L) + while (bytesRead != -1L) { + totalBytesRead += bytesRead + bytesRead = read(sink, Long.MAX_VALUE) + } - return totalReadBytes + 1L // Account for last -1 read + return totalBytesRead } diff --git a/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/io/SdkSourceTest.kt b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/io/SdkSourceTest.kt new file mode 100644 index 0000000000..14146676f7 --- /dev/null +++ b/runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/io/SdkSourceTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package aws.smithy.kotlin.runtime.io + +import kotlin.test.Test +import kotlin.test.assertEquals + +class SdkSourceTest { + @Test + fun readRemaining() { + val data = "Hello world" + val dataLength = data.length.toLong() + val readCycles = 100 + val totalDataLength = dataLength * readCycles + + // Manual and readRemaining + val source = createTestSource(data, dataLength, readCycles) + val buffer = SdkBuffer() + val manualReads = 10 + repeat(manualReads) { + source.read(buffer, dataLength) + } + var readByReadRemaining = source.readRemaining(buffer) + assertEquals(readByReadRemaining, totalDataLength - manualReads * dataLength) + assertEquals(buffer.size, totalDataLength) + + // Only readRemaining + buffer.skip(totalDataLength) + readByReadRemaining = createTestSource(data, dataLength, readCycles).readRemaining(buffer) + assertEquals(readByReadRemaining, totalDataLength) + assertEquals(buffer.size, totalDataLength) + } +} + +private fun createTestSource( + data: String, + dataLength: Long, + readCycles: Int, +) = + object : SdkSource { + var remainingReadCycles = readCycles + + override fun read(sink: SdkBuffer, limit: Long): Long { + if (remainingReadCycles == 0) { + return -1L + } + + sink.writeUtf8(data) + remainingReadCycles-- + return dataLength + } + + override fun close() {} + }