Skip to content

Commit 4619565

Browse files
authored
feat: Add partition() and contains() collection operators (#39)
1 parent 6f6c635 commit 4619565

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Copyright 2026 Nacho Lopez
2+
// SPDX-License-Identifier: MIT
3+
@file:Suppress("NOTHING_TO_INLINE")
4+
5+
package io.nlopez.asyncresult
6+
7+
/** Returns true if this [AsyncResult] is a [Success] containing the given [value]. */
8+
public inline fun <T> AsyncResult<T>.contains(value: T): Boolean = isSuccessAnd { it == value }

asyncresult/src/commonMain/kotlin/io/nlopez/asyncresult/AsyncResult.iterable.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,36 @@ public inline fun <T> List<AsyncResult<T>>.sequence(): AsyncResult<List<T>> = co
193193
* @return A single [AsyncResult] containing the list of all success values, or the first error
194194
*/
195195
public fun <T> Sequence<AsyncResult<T>>.combine(): AsyncResult<List<T>> = toList().combine()
196+
197+
/**
198+
* Partitions a collection of [AsyncResult] items into successful values and errors.
199+
*
200+
* Incomplete items ([Loading] and [NotStarted]) are ignored.
201+
*
202+
* @return A [Pair] where the first element is a list of success values and the second is a list of
203+
* errors
204+
*/
205+
public inline fun <T> Iterable<AsyncResult<T>>.partition(): Pair<List<T>, List<Error>> =
206+
successes() to errors()
207+
208+
/**
209+
* Partitions a sequence of [AsyncResult] items into successful values and errors.
210+
*
211+
* Incomplete items ([Loading] and [NotStarted]) are ignored.
212+
*
213+
* @return A [Pair] where the first element is a list of success values and the second is a list of
214+
* errors
215+
*/
216+
public inline fun <T> Sequence<AsyncResult<T>>.partition(): Pair<List<T>, List<Error>> =
217+
successes() to errors()
218+
219+
/**
220+
* Partitions an array of [AsyncResult] items into successful values and errors.
221+
*
222+
* Incomplete items ([Loading] and [NotStarted]) are ignored.
223+
*
224+
* @return A [Pair] where the first element is a list of success values and the second is a list of
225+
* errors
226+
*/
227+
public inline fun <T> Array<out AsyncResult<T>>.partition(): Pair<List<T>, List<Error>> =
228+
successes() to errors()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2026 Nacho Lopez
2+
// SPDX-License-Identifier: MIT
3+
package io.nlopez.asyncresult
4+
5+
import assertk.assertThat
6+
import assertk.assertions.isFalse
7+
import assertk.assertions.isTrue
8+
import kotlin.test.Test
9+
10+
class AsyncResultContainsTest {
11+
@Test
12+
fun `contains returns true for Success with matching value`() {
13+
val result: AsyncResult<Int> = Success(42)
14+
assertThat(result.contains(42)).isTrue()
15+
}
16+
17+
@Test
18+
fun `contains returns false for Success with different value`() {
19+
val result: AsyncResult<Int> = Success(42)
20+
assertThat(result.contains(99)).isFalse()
21+
}
22+
23+
@Test
24+
fun `contains returns false for Error`() {
25+
val result: AsyncResult<Int> = Error()
26+
assertThat(result.contains(42)).isFalse()
27+
}
28+
29+
@Test
30+
fun `contains returns false for Loading`() {
31+
val result: AsyncResult<Int> = Loading
32+
assertThat(result.contains(42)).isFalse()
33+
}
34+
35+
@Test
36+
fun `contains returns false for NotStarted`() {
37+
val result: AsyncResult<Int> = NotStarted
38+
assertThat(result.contains(42)).isFalse()
39+
}
40+
41+
@Test
42+
fun `contains works with nullable values`() {
43+
val result: AsyncResult<Int?> = Success(null)
44+
assertThat(result.contains(null)).isTrue()
45+
assertThat(result.contains(42)).isFalse()
46+
}
47+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2026 Nacho Lopez
2+
// SPDX-License-Identifier: MIT
3+
package io.nlopez.asyncresult
4+
5+
import assertk.assertThat
6+
import assertk.assertions.containsExactly
7+
import assertk.assertions.isEmpty
8+
import kotlin.test.Test
9+
10+
class AsyncResultPartitionTest {
11+
@Test
12+
fun `partition separates successes and errors`() {
13+
val error = Error()
14+
val items: List<AsyncResult<Int>> = listOf(Success(1), error, Success(3))
15+
val (successes, errors) = items.partition()
16+
17+
assertThat(successes).containsExactly(1, 3)
18+
assertThat(errors).containsExactly(error)
19+
}
20+
21+
@Test
22+
fun `partition ignores Loading and NotStarted`() {
23+
val items: List<AsyncResult<Int>> = listOf(Success(1), Loading, NotStarted, Success(2))
24+
val (successes, errors) = items.partition()
25+
26+
assertThat(successes).containsExactly(1, 2)
27+
assertThat(errors).isEmpty()
28+
}
29+
30+
@Test
31+
fun `partition on empty list returns empty pairs`() {
32+
val items: List<AsyncResult<Int>> = emptyList()
33+
val (successes, errors) = items.partition()
34+
35+
assertThat(successes).isEmpty()
36+
assertThat(errors).isEmpty()
37+
}
38+
39+
@Test
40+
fun `partition works on sequences`() {
41+
val error = Error()
42+
val items = sequenceOf<AsyncResult<Int>>(Success(1), error, Loading)
43+
val (successes, errors) = items.partition()
44+
45+
assertThat(successes).containsExactly(1)
46+
assertThat(errors).containsExactly(error)
47+
}
48+
49+
@Test
50+
fun `partition works on arrays`() {
51+
val error = Error()
52+
val items: Array<AsyncResult<Int>> = arrayOf(Success(1), error, Success(3))
53+
val (successes, errors) = items.partition()
54+
55+
assertThat(successes).containsExactly(1, 3)
56+
assertThat(errors).containsExactly(error)
57+
}
58+
}

0 commit comments

Comments
 (0)