Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion kotlinx-coroutines-core/api/kotlinx-coroutines-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,9 @@ public final class kotlinx/coroutines/channels/ChannelsKt {
public static synthetic fun takeWhile$default (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/CoroutineContext;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlinx/coroutines/channels/ReceiveChannel;
public static final fun toChannel (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlinx/coroutines/channels/SendChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun toCollection (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/util/Collection;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun toList (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun toList (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final synthetic fun toList (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun toList$default (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/util/List;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun toMap (Lkotlinx/coroutines/channels/ReceiveChannel;Ljava/util/Map;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final synthetic fun toMap (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final synthetic fun toMutableList (Lkotlinx/coroutines/channels/ReceiveChannel;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,7 @@ final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/single(): #A // kotlinx.coroutines.channels/single|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/singleOrNull(): #A? // kotlinx.coroutines.channels/singleOrNull|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/toList(): kotlin.collections/List<#A> // kotlinx.coroutines.channels/toList|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/toList(kotlin.collections/MutableList<#A> = ...): kotlin.collections/List<#A> // kotlinx.coroutines.channels/toList|[email protected]<0:0>(kotlin.collections.MutableList<0:0>){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/toMutableList(): kotlin.collections/MutableList<#A> // kotlinx.coroutines.channels/toMutableList|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/toMutableSet(): kotlin.collections/MutableSet<#A> // kotlinx.coroutines.channels/toMutableSet|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
final suspend fun <#A: kotlin/Any?> (kotlinx.coroutines.channels/ReceiveChannel<#A>).kotlinx.coroutines.channels/toSet(): kotlin.collections/Set<#A> // kotlinx.coroutines.channels/toSet|[email protected]<0:0>(){0§<kotlin.Any?>}[0]
Expand Down
14 changes: 8 additions & 6 deletions kotlinx-coroutines-core/common/src/channels/Channels.common.kt
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ public suspend inline fun <E> ReceiveChannel<E>.consumeEach(action: (E) -> Unit)
}

/**
* Returns a [List] containing all the elements sent to this channel, preserving their order.
* [Consumes][consume] the elements of this channel into the given [destination] mutable list.
* If none is provided, a new [ArrayList] will be created.
*
* This function will attempt to receive elements and put them into the list until the channel is
* [closed][SendChannel.close].
Expand All @@ -172,6 +173,8 @@ public suspend inline fun <E> ReceiveChannel<E>.consumeEach(action: (E) -> Unit)
* 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].
Expand All @@ -188,11 +191,8 @@ public suspend inline fun <E> ReceiveChannel<E>.consumeEach(action: (E) -> Unit)
* check(channel.toList() == values)
* ```
*/
public suspend fun <E> ReceiveChannel<E>.toList(): List<E> = buildList {
consumeEach {
add(it)
}
}
public suspend fun <T> ReceiveChannel<T>.toList(destination: MutableList<T> = ArrayList()): List<T> =
consumeEach(destination::add).let { destination }

@PublishedApi
internal fun ReceiveChannel<*>.cancelConsumed(cause: Throwable?) {
Expand All @@ -201,3 +201,5 @@ internal fun ReceiveChannel<*>.cancelConsumed(cause: Throwable?) {
})
}

@Deprecated("Preserving binary compatibility, was stable", level = DeprecationLevel.HIDDEN)
public suspend fun <T> ReceiveChannel<T>.toList(): List<T> = toList(ArrayList())
36 changes: 34 additions & 2 deletions kotlinx-coroutines-core/common/test/channels/ChannelsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,13 @@ class ChannelsTest: TestBase() {
}

@Test
fun testEmptyList() = runTest {
fun testEmptyToList() = runTest {
assertTrue(emptyList<Nothing>().asReceiveChannel().toList().isEmpty())
}

@Test
fun testToList() = runTest {
assertEquals(testList, testList.asReceiveChannel().toList())

}

@Test
Expand All @@ -104,6 +103,39 @@ class ChannelsTest: TestBase() {
}
}

@Test
fun testEmptyToListWithDestination() = runTest {
val initialList = listOf(-1, -2, -3)
val destination = initialList.toMutableList()
emptyList<Nothing>().asReceiveChannel().toList(destination)
assertEquals(initialList, destination)
}

@Test
fun testToListWithDestination() = runTest {
val initialList = listOf(-1, -2, -3)
val destination = initialList.toMutableList()
testList.asReceiveChannel().toList(destination)
assertEquals(initialList + testList, destination)
}

@Test
fun testToListWithDestinationOnFailedChannel() = runTest {
val initialList = listOf(-1, -2, -3)
val destination = initialList.toMutableList()
val channel = Channel<Int>(10)
val elementsToSend = (1..5).toList()
elementsToSend.forEach {
val result = channel.trySend(it)
assertTrue(result.isSuccess)
}
channel.close(TestException())
assertFailsWith<TestException> {
channel.toList(destination)
}
assertEquals(initialList + elementsToSend, destination)
}

private fun <E> Iterable<E>.asReceiveChannel(context: CoroutineContext = Dispatchers.Unconfined): ReceiveChannel<E> =
GlobalScope.produce(context) {
for (element in this@asReceiveChannel)
Expand Down