Skip to content

Implement ByteReadChannel.readTo util - #5216

Merged
Pantus Oleh (zibet27) merged 2 commits into
mainfrom
zibet27/byte-read-channel-read-to
Nov 28, 2025
Merged

Implement ByteReadChannel.readTo util#5216
Pantus Oleh (zibet27) merged 2 commits into
mainfrom
zibet27/byte-read-channel-read-to

Conversation

@zibet27

@zibet27 Pantus Oleh (zibet27) commented Nov 25, 2025

Copy link
Copy Markdown
Collaborator

Subsystem
Shared

Motivation
Github Issue

Solution
Reuse some existing code, but make the interface more general

Update:
Unifying ByteReadChannel.readTo(sink: RawSink, limit: Long) with ByteReadChannel.copyTo(channel: ByteWriteChannel, limit: Long) breaks some internal logic. Although we could try making ByteReadChannel implement the RawSink interface, it is still somewhat different.
So, returning to code duplication.

@coderabbitai

coderabbitai Bot commented Nov 25, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a new suspend function ByteReadChannel.readTo(sink: RawSink, limit: Long = Long.MAX_VALUE): Long and a bounded overload ByteReadChannel.copyTo(channel: ByteWriteChannel, limit: Long): Long; updates copy loop behavior to perform per-iteration flushes and error handling; adds tests for full, partial, and cancelled reads.

Changes

Cohort / File(s) Summary
Channel I/O operations
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
Added public suspend fun ByteReadChannel.readTo(sink: RawSink, limit: Long = Long.MAX_VALUE): Long. Added public suspend fun ByteReadChannel.copyTo(channel: ByteWriteChannel, limit: Long): Long (bounded overload). Both implement per-iteration chunked transfers, flush-on-iteration, cancel/close-on-error, and return consumed byte count.
Tests
ktor-io/common/test/ByteReadChannelOperationsTest.kt
Added tests: testReadToSinkAll, testReadToSinkPartial, testReadToFromCancelled and required imports verifying full reads, partial/limited reads, and cancellation/error behavior.
Public API descriptors
ktor-io/api/ktor-io.api, ktor-io/api/ktor-io.klib.api
Updated API/ABI records to expose the new readTo function and its JVM default-method synthetic readTo$default; added Klib ABI entries for the suspend readTo signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to focus:
    • Correctness of per-iteration flush and buffer management in both new readTo and copyTo(limit) implementations.
    • Error paths: ensure sinks are closed and channels cancelled consistently, and exceptions are propagated as intended.
    • API surface: verify overload coexistence (existing no-limit copyTo remains) and ABI/JVM default method signatures in api files.
    • Tests: ensure they cover boundary limits (0, Long.MAX_VALUE) and concurrency/cancellation semantics.

Suggested reviewers

  • Stexxe
  • marychatte

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: implementing a new ByteReadChannel.readTo utility function, which is the primary objective of the PR.
Description check ✅ Passed The description follows the template with all required sections (Subsystem, Motivation, Solution) filled in, providing context about the GitHub issue and explaining the implementation approach.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch zibet27/byte-read-channel-read-to

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0ec75b and f1b9bfe.

📒 Files selected for processing (4)
  • ktor-io/api/ktor-io.api (1 hunks)
  • ktor-io/api/ktor-io.klib.api (1 hunks)
  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1 hunks)
  • ktor-io/common/test/ByteReadChannelOperationsTest.kt (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • ktor-io/api/ktor-io.klib.api
🚧 Files skipped from review as they are similar to previous changes (1)
  • ktor-io/common/test/ByteReadChannelOperationsTest.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.kt: Follow Kotlin official style guide (https://kotlinlang.org/docs/coding-conventions.html)
Use star imports for io.ktor.* packages
Document all public APIs including parameters, return types, and exceptions
Mark internal APIs with @InternalAPI annotation
Run ./gradlew lintKotlin and fix all linting issues before giving control back to the user
Use ./gradlew formatKotlin to automatically fix formatting issues
Run ./gradlew updateLegacyAbi after making ABI changes to update ABI signature files
Binary compatibility is enforced - all public API changes must be tracked in the /api/ directories
Validate ABI with ./gradlew checkLegacyAbi and update with ./gradlew updateLegacyAbi
API changes must be intentional and well-documented
Error handling follows Kotlin conventions with specific Ktor exceptions

Files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
🧠 Learnings (5)
📓 Common learnings
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.
📚 Learning: 2025-09-05T12:46:14.074Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.

Applied to files:

  • ktor-io/api/ktor-io.api
  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-11-25T09:38:19.393Z
Learnt from: CR
Repo: ktorio/ktor PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:38:19.393Z
Learning: Applies to **/*.kt : API changes must be intentional and well-documented

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-11-25T09:38:19.393Z
Learnt from: CR
Repo: ktorio/ktor PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:38:19.393Z
Learning: Applies to **/*.kt : Binary compatibility is enforced - all public API changes must be tracked in the `/api/` directories

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-09-05T12:47:49.016Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:35-52
Timestamp: 2025-09-05T12:47:49.016Z
Learning: JettyWebsocketConnection in ktor-server-jetty-jakarta implements Closeable interface (has close() method), so connection.use { } is valid Kotlin syntax and will compile correctly.

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
🧬 Code graph analysis (1)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (5)
ktor-io/common/src/io/ktor/utils/io/ByteChannel.kt (2)
  • awaitContent (69-80)
  • cancel (136-144)
ktor-io/common/src/io/ktor/utils/io/CountedByteReadChannel.kt (2)
  • awaitContent (43-53)
  • cancel (62-65)
ktor-io/jvm/src/io/ktor/utils/io/jvm/javaio/Reading.kt (2)
  • awaitContent (66-87)
  • cancel (89-94)
ktor-io/common/src/io/ktor/utils/io/ByteWriteChannelOperations.kt (1)
  • cancel (162-162)
ktor-io/common/src/io/ktor/utils/io/SinkByteWriteChannel.kt (1)
  • cancel (64-67)
🔇 Additional comments (2)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1)

185-213: ByteReadChannel.readTo implementation looks correct and consistent with existing patterns.

The loop, error handling (cancel + sink.close()), and final rethrowCloseCauseIfNeeded() align with how copyAndClose / readRemaining behave, and the KDoc accurately reflects the semantics of the new public API.

ktor-io/api/ktor-io.api (1)

93-94: ABI entry for readTo matches the Kotlin implementation.

The new readTo and its $default synthetic are correctly added to ByteReadChannelOperationsKt, so the ABI now reflects the new public API.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (2)

186-203: Add KDoc documentation for this new public API.

Per coding guidelines, all public APIs must be documented including parameters, return types, and exceptions. This function is missing documentation.

Also, unlike the unbounded copyTo(channel: ByteWriteChannel) at line 179 which has a finally { channel.flush() } block, this function relies solely on in-loop flushes. If the loop exits normally (channel closed for read with remaining > 0), the last write was already flushed inside the loop, so this should be fine—but please verify this is intentional.

Consider adding documentation similar to:

/**
 * Reads up to [limit] bytes from this channel and writes them to the [sink].
 *
 * @param sink the destination to write bytes to
 * @param limit the maximum number of bytes to read
 * @return the number of bytes actually read and written
 */

205-213: Add KDoc documentation for this public API overload.

This new overload should be documented to explain the bounded copy behavior, parameters, and return value.

Consider adding documentation:

/**
 * Copies up to [limit] bytes from this channel to the specified [channel].
 *
 * @param channel the destination channel to copy bytes to
 * @param limit the maximum number of bytes to copy
 * @return the number of bytes actually copied
 */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 18a6e97 and aa6049c.

📒 Files selected for processing (1)
  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.kt: Follow Kotlin official style guide (https://kotlinlang.org/docs/coding-conventions.html)
Use star imports for io.ktor.* packages
Document all public APIs including parameters, return types, and exceptions
Mark internal APIs with @InternalAPI annotation
Run ./gradlew lintKotlin and fix all linting issues before giving control back to the user
Use ./gradlew formatKotlin to automatically fix formatting issues
Run ./gradlew updateLegacyAbi after making ABI changes to update ABI signature files
Binary compatibility is enforced - all public API changes must be tracked in the /api/ directories
Validate ABI with ./gradlew checkLegacyAbi and update with ./gradlew updateLegacyAbi
API changes must be intentional and well-documented
Error handling follows Kotlin conventions with specific Ktor exceptions

Files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
🧠 Learnings (2)
📓 Common learnings
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.
📚 Learning: 2025-09-05T12:46:14.074Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt

Comment thread ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt Outdated
@zibet27
Pantus Oleh (zibet27) force-pushed the zibet27/byte-read-channel-read-to branch from aa6049c to a703283 Compare November 25, 2025 11:00

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1)

185-202: Add KDoc documentation for this new public API.

As per coding guidelines, all public APIs should be documented including parameters, return types, and exceptions. Consider adding documentation similar to other functions in this file.

+/**
+ * Reads bytes from the channel into the specified [sink] up to the given [limit].
+ *
+ * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.utils.io.readTo)
+ *
+ * @param sink the raw sink to write the bytes to
+ * @param limit the maximum number of bytes to read
+ * @return the number of bytes read
+ */
 @OptIn(InternalAPI::class)
 public suspend fun ByteReadChannel.readTo(sink: RawSink, limit: Long): Long {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa6049c and a703283.

📒 Files selected for processing (2)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (2 hunks)
  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.kt: Follow Kotlin official style guide (https://kotlinlang.org/docs/coding-conventions.html)
Use star imports for io.ktor.* packages
Document all public APIs including parameters, return types, and exceptions
Mark internal APIs with @InternalAPI annotation
Run ./gradlew lintKotlin and fix all linting issues before giving control back to the user
Use ./gradlew formatKotlin to automatically fix formatting issues
Run ./gradlew updateLegacyAbi after making ABI changes to update ABI signature files
Binary compatibility is enforced - all public API changes must be tracked in the /api/ directories
Validate ABI with ./gradlew checkLegacyAbi and update with ./gradlew updateLegacyAbi
API changes must be intentional and well-documented
Error handling follows Kotlin conventions with specific Ktor exceptions

Files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
**/test/**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

Follow test naming pattern: DescribeWhatIsBeingTested

Files:

  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
🧠 Learnings (6)
📓 Common learnings
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.
📚 Learning: 2025-09-05T12:46:14.074Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
📚 Learning: 2025-11-25T09:38:19.380Z
Learnt from: CR
Repo: ktorio/ktor PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:38:19.380Z
Learning: Applies to **/*.kt : API changes must be intentional and well-documented

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-11-25T09:38:19.380Z
Learnt from: CR
Repo: ktorio/ktor PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:38:19.380Z
Learning: Applies to **/*.kt : Binary compatibility is enforced - all public API changes must be tracked in the `/api/` directories

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-05-30T06:45:52.309Z
Learnt from: rururux
Repo: ktorio/ktor PR: 4896
File: ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt:1-12
Timestamp: 2025-05-30T06:45:52.309Z
Learning: In Ktor test files, particularly in the ktor-client/ktor-client-core/jvm/test/ directory, test files follow the convention of not including explicit package declarations. This is consistent across test files like CachingCacheStorageTest.kt and should be maintained for consistency.

Applied to files:

  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
📚 Learning: 2025-10-22T07:21:51.263Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 5139
File: ktor-server/ktor-server-plugins/ktor-server-di/common/src/io/ktor/server/plugins/di/DependencyInjection.kt:11-11
Timestamp: 2025-10-22T07:21:51.263Z
Learning: In Ktor, `io.ktor.utils.io.CancellationException` is a typealias for `kotlinx.coroutines.CancellationException`, which is a supertype of `JobCancellationException`. Therefore, checking `e !is io.ktor.utils.io.CancellationException` is sufficient to exclude all coroutine cancellation exceptions.

Applied to files:

  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
🔇 Additional comments (3)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (2)

24-24: LGTM!

Import added for the new Buffer usage in the test.


140-147: Good test coverage for the new readTo utility.

The test properly exercises the new ByteReadChannel.readTo(sink, limit) function by:

  1. Reading response via channel instead of direct ByteArray
  2. Verifying the returned byte count matches expected content size
  3. Verifying the actual buffer content matches the original payload
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1)

204-224: LGTM!

The bounded copyTo implementation correctly handles chunked reads with proper exception handling and flushing. The pattern is consistent with the new readTo function.

@bjhham Bruce Hamilton (bjhham) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is kinda related to https://youtrack.jetbrains.com/issue/KTOR-7848/ByteChannel-Files-I-O-Improvements would be good to log it as a sub-issue and mark it as fixed for 3.4.0.

Comment thread ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt Outdated
@zibet27
Pantus Oleh (zibet27) force-pushed the zibet27/byte-read-channel-read-to branch from a703283 to 6dcd60c Compare November 25, 2025 15:10

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1)

185-202: Update ABI signature files and run Kotlin linting/formatting.

The new readTo(sink: RawSink, limit: Long) function is missing from the ABI signature file (ktor-io/api/ktor-io.api). Per binary compatibility enforcement, all public API changes must be tracked in the /api/ directories.

Run these commands locally to complete the changes:

./gradlew updateLegacyAbi
./gradlew lintKotlin
./gradlew formatKotlin
./gradlew checkLegacyAbi
🧹 Nitpick comments (1)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1)

185-202: Add finally block to ensure sink is flushed.

The copyTo function at lines 219-221 uses a finally block to ensure the channel is flushed even if an exception occurs. For consistency and robustness, readTo should similarly ensure the sink is flushed in a finally block.

Apply this diff:

 @OptIn(InternalAPI::class)
 public suspend fun ByteReadChannel.readTo(sink: RawSink, limit: Long = Long.MAX_VALUE): Long {
     var remaining = limit
     try {
         while (!isClosedForRead && remaining > 0) {
             if (readBuffer.exhausted()) awaitContent()
             val byteCount = minOf(remaining, readBuffer.remaining)
             readBuffer.readTo(sink, byteCount)
             remaining -= byteCount
             sink.flush()
         }
     } catch (cause: Throwable) {
         cancel(cause)
         throw cause
+    } finally {
+        sink.flush()
     }
 
     return limit - remaining
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a703283 and 6dcd60c.

📒 Files selected for processing (2)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt (2 hunks)
  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/ContentTest.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.kt: Follow Kotlin official style guide (https://kotlinlang.org/docs/coding-conventions.html)
Use star imports for io.ktor.* packages
Document all public APIs including parameters, return types, and exceptions
Mark internal APIs with @InternalAPI annotation
Run ./gradlew lintKotlin and fix all linting issues before giving control back to the user
Use ./gradlew formatKotlin to automatically fix formatting issues
Run ./gradlew updateLegacyAbi after making ABI changes to update ABI signature files
Binary compatibility is enforced - all public API changes must be tracked in the /api/ directories
Validate ABI with ./gradlew checkLegacyAbi and update with ./gradlew updateLegacyAbi
API changes must be intentional and well-documented
Error handling follows Kotlin conventions with specific Ktor exceptions

Files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
🧠 Learnings (3)
📓 Common learnings
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.
📚 Learning: 2025-09-05T12:46:14.074Z
Learnt from: bjhham
Repo: ktorio/ktor PR: 4887
File: ktor-server/ktor-server-jetty-jakarta/jvm/src/io/ktor/server/jetty/jakarta/JettyWebsocketConnection.kt:90-100
Timestamp: 2025-09-05T12:46:14.074Z
Learning: The ByteReadChannel.readAvailable(ByteBuffer) method in Ktor IO automatically calls awaitContent() internally when the read buffer is exhausted. When it returns 0, it has already suspended and waited for data to become available, so adding explicit awaitContent() calls is redundant and incorrect.

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
📚 Learning: 2025-11-25T09:38:19.380Z
Learnt from: CR
Repo: ktorio/ktor PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:38:19.380Z
Learning: Applies to **/*.kt : API changes must be intentional and well-documented

Applied to files:

  • ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt
🧬 Code graph analysis (1)
ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt (3)
ktor-io/common/src/io/ktor/utils/io/ByteChannel.kt (2)
  • awaitContent (69-80)
  • cancel (136-144)
ktor-io/common/src/io/ktor/utils/io/CountedByteReadChannel.kt (2)
  • awaitContent (43-53)
  • cancel (62-65)
ktor-io/jvm/src/io/ktor/utils/io/jvm/javaio/Reading.kt (2)
  • awaitContent (66-87)
  • cancel (89-94)

Comment thread ktor-io/common/src/io/ktor/utils/io/ByteReadChannelOperations.kt

@e5l Leonid Stashevsky (e5l) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hey Pantus Oleh (@zibet27), nice PR. Please check the comment before merging

)
)
}.body<ByteArray>()
}.bodyAsChannel()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we have tests for 2 separate receive types?

public suspend fun ByteReadChannel.readTo(sink: RawSink, limit: Long = Long.MAX_VALUE): Long {
var remaining = limit
try {
while (!isClosedForRead && remaining > 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would also have a test with cancellation

}

@OptIn(InternalAPI::class)
public suspend fun ByteReadChannel.readTo(sink: RawSink, limit: Long = Long.MAX_VALUE): Long {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please add KDoc

@zibet27
Pantus Oleh (zibet27) force-pushed the zibet27/byte-read-channel-read-to branch from e0ec75b to f1b9bfe Compare November 26, 2025 15:11
@zibet27
Pantus Oleh (zibet27) enabled auto-merge (squash) November 28, 2025 09:46
@zibet27
Pantus Oleh (zibet27) merged commit d681ea2 into main Nov 28, 2025
13 of 17 checks passed
@zibet27
Pantus Oleh (zibet27) deleted the zibet27/byte-read-channel-read-to branch November 28, 2025 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants