Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/common/src/channels/Channels.common.kt (Kotlin)

Code before:
 * // sends elements to it, and closes it
 * // once the coroutine's body finishes
 * val channel = produce {
 *     values.forEach { send(it) }
 * }
 * check(channel.toList() == values)
 * ```
 */
public suspend fun <E> ReceiveChannel<E>.toList(): List<E> = buildList {
    consumeEach {
        add(it)
    }
}

/**
 * Consumes the elements of this channel into the given [destination] mutable list.
 *
 * This function will attempt to receive elements and put them into the list until the channel is
 * [closed][SendChannel.close].
 * Calling [toList] on channels that are not eventually closed is always incorrect:
 * - It will suspend indefinitely if the channel is not closed, but no new elements arrive.
 * - If new elements do arrive and the channel is not eventually closed, [toList] will use more and more memory
 *   until exhausting it.
 *
 * If the channel is [closed][SendChannel.close] with a cause, [toList] will rethrow that cause.
 * However, the [destination] list is left in a consistent state containing all the elements received from the channel
 * up to that point.
 *
 * The operation is _terminal_.
 * This function [consumes][ReceiveChannel.consume] all elements of the original [ReceiveChannel].
 *
 * Example:
 * ```
 * val values = listOf(1, 5, 2, 9, 3, 3, 1)
 * // start a new coroutine that creates a channel,
 * // sends elements to it, and closes it
 * // once the coroutine's body finishes
 * val channel = produce {
 *    values.forEach { send(it) }
 * }
 * val destination = mutableListOf<Int>()
 * channel.toList(destination)
 * check(destination == values)
 * ```
 */
public suspend inline fun <T> ReceiveChannel<T>.toList(destination: MutableList<T>) {
    consumeEach {
        destination.add(it)
    }
}


Review comment (suggestion):
Since there's little difference between toList(List) and toList(), shall we reference one in the other instead of copy-pasting?

> **Similar to toList(), however, this overload** consumes the elements of this channel into the given [destination] mutable list.
> If the channel is [closed][SendChannel.close] with a cause, [toList] will rethrow that cause, **same as toList**.
> However, **in contrast to toList**, the [destination] list is left in a consistent state containing all the elements received from the channel

And keep both usage examples, of course.

Code after:
 * or if [MutableList.add] fails with an exception.
 * In both cases, the exception will be used for cancelling the channel and then rethrown.
 *
 * Example:
 * ```
 * val values = listOf(1, 5, 2, 9, 3, 3, 1)
 * // start a new coroutine that creates a channel,
 * // sends elements to it, and closes it
 * // once the coroutine's body finishes
 * val channel = produce {
 *     values.forEach { send(it) }
 * }
 * check(channel.toList() == values)
 * ```
 */
public suspend fun <E> ReceiveChannel<E>.toList(): List<E> = buildList {
    consumeEach(::add)
}

/**
 * [Consumes][consume] the elements of this channel into the provided mutable collection.
 *
 * This is a convenience function equivalent to calling [consumeAsFlow]
 * followed by [kotlinx.coroutines.flow.toCollection].
 * Please use [consumeAsFlow] directly in scenarios where elements should undergo additional transformations
 * before being added to the resulting collection.
 *
 * [consumeTo] attempts to receive elements and put them into the collection until the channel is
 * [closed][SendChannel.close].
 *
 * If the channel is [closed][SendChannel.close] with a cause, [consumeTo] will rethrow that cause.
 * However, the elements already received up to that point will remain in the collection.
 *
 * Since this function is implemented using [consume], it is _terminal_,
 * meaning that [consumeTo] will [cancel][ReceiveChannel.cancel] the channel before exiting.
 * A [consumeTo] call can finish before the sender closes the channel
 * if it gets cancelled while waiting for the next element,
 * or if [MutableCollection.add] fails with an exception.
 * In both cases, the exception will be used for cancelling the channel and then rethrown.
 *
 * The intended use case for this function is collecting the remaining elements of a closed channel
 * and processing them in a single batch.
 *
 * Example:
 * ```
 * val doContinue = AtomicBoolean(true)
 *
 * // Start the sender
 * val channel = produce {
 *     var i = 0
 *     while (doContinue.load()) {