Repository: ktorio/ktor
File: ktor-io/jvm/src/io/ktor/utils/io/ByteReadChannelOperations.jvm.kt (Kotlin)

Code before:

public suspend fun ByteReadChannel.skipDelimiter(delimiter: ByteBuffer) {
    skipDelimiter(ByteString(delimiter))
}

public suspend fun ByteReadChannel.skipDelimiter(delimiter: ByteString) {
    for (i in 0 until delimiter.size) {
        val byte = readByte()
        if (byte != delimiter[i]) {
            throw IllegalStateException("Delimiter is not found")
        }
    }
}

@OptIn(InternalAPI::class)
public suspend fun ByteReadChannel.readFully(buffer: ByteBuffer) {
    while (buffer.hasRemaining()) {
        if (availableForRead == 0) {
            if(!awaitContent()) {
                throw EOFException("Not enough bytes available: expected ${buffer.remaining()} more bytes")
            }
        }
        readBuffer.readAtMostTo(buffer)
    }
}

/**
 * Invokes [block] if it is possible to read at least [min] byte
 * providing byte buffer to it so lambda can read from the buffer
 * up to [ByteBuffer.available] bytes. If there are no [min] bytes available then the invocation returns 0.
 *
 * Warning: it is not guaranteed that all of available bytes will be represented as a single byte buffer
 * eg: it could be 4 bytes available for read but the provided byte buffer could have only 2 available bytes:
 * in this case you have to invoke read again (with decreased [min] accordingly).
 *
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.utils.io.readAvailable)
 *
 * @param min amount of bytes available for read, should be positive
 * @param block to be invoked when at least [min] bytes available
 *
 * @return number of consumed bytes or -1 if the block wasn't executed.
 */
@OptIn(InternalAPI::class, UnsafeIoApi::class, InternalIoApi::class)
public fun ByteReadChannel.readAvailable(block: (ByteBuffer) -> Int): Int {
    if (isClosedForRead || readBuffer.exhausted()) return -1

    var result = 0
    UnsafeBufferOperations.readFromHead(readBuffer.buffer) { array, start, endExclusive ->
        val buffer = ByteBuffer.wrap(array, start, endExclusive - start)
        result = block(buffer)

Review comment (suggestion):
You can remove the outer if here since the read buffer is checked in `awaitContent` as well.

So:
```
while (buffer.hasRemaining()) {
    if (!awaitContent()) {
        throw EOFException("Not enough bytes available: expected ${buffer.remaining()} more bytes")
    }
    ...
}
```

Code after:

public suspend fun ByteReadChannel.skipDelimiter(delimiter: ByteBuffer) {
    skipDelimiter(ByteString(delimiter))
}

public suspend fun ByteReadChannel.skipDelimiter(delimiter: ByteString) {
    for (i in 0 until delimiter.size) {
        val byte = readByte()
        if (byte != delimiter[i]) {
            throw IllegalStateException("Delimiter is not found")
        }
    }
}

/**
 * Reads data from the [ByteReadChannel] into the provided [buffer] until the buffer is fully filled or EOF is reached.
 *
 * @param buffer the [ByteBuffer] into which bytes are read from the channel.
 * @throws EOFException if the channel is closed or there are not enough bytes available to fill the [buffer].
 */
@OptIn(InternalAPI::class)
public suspend fun ByteReadChannel.readFully(buffer: ByteBuffer) {
    while (buffer.hasRemaining()) {
        if (!awaitContent()) {
            throw EOFException("Not enough bytes available: expected ${buffer.remaining()} more bytes")
        }
        readBuffer.readAtMostTo(buffer)
    }
}

/**
 * Invokes [block] if it is possible to read at least [min] byte
 * providing byte buffer to it so lambda can read from the buffer
 * up to [ByteBuffer.available] bytes. If there are no [min] bytes available then the invocation returns 0.
 *
 * Warning: it is not guaranteed that all of available bytes will be represented as a single byte buffer
 * eg: it could be 4 bytes available for read but the provided byte buffer could have only 2 available bytes:
 * in this case you have to invoke read again (with decreased [min] accordingly).
 *
 *
 * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.utils.io.readAvailable)
 *
 * @param min amount of bytes available for read, should be positive
 * @param block to be invoked when at least [min] bytes available
 *
 * @return number of consumed bytes or -1 if the block wasn't executed.
 */
@OptIn(InternalAPI::class, UnsafeIoApi::class, InternalIoApi::class)
public fun ByteReadChannel.readAvailable(block: (ByteBuffer) -> Int): Int {
    if (isClosedForRead || readBuffer.exhausted()) return -1