Skip to content

Commit b205cf2

Browse files
hoc081098michaelbull
authored andcommitted
Add parZip
Closes #122
1 parent 05a07e3 commit b205cf2

File tree

2 files changed

+465
-0
lines changed
  • kotlin-result-coroutines/src
    • commonMain/kotlin/com/github/michaelbull/result/coroutines
    • commonTest/kotlin/com.github.michaelbull.result.coroutines

2 files changed

+465
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package com.github.michaelbull.result.coroutines
2+
3+
import com.github.michaelbull.result.Err
4+
import com.github.michaelbull.result.Result
5+
import kotlinx.coroutines.CoroutineScope
6+
import kotlinx.coroutines.async
7+
import kotlinx.coroutines.awaitAll
8+
import kotlin.contracts.InvocationKind
9+
import kotlin.contracts.contract
10+
11+
private typealias Producer<T, E> = suspend CoroutineScope.() -> Result<T, E>
12+
13+
private suspend inline fun <T, E, V> parZipInternal(
14+
vararg producers: Producer<T, E>,
15+
crossinline transform: suspend CoroutineScope.(values: List<T>) -> V,
16+
): Result<V, E> {
17+
contract {
18+
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
19+
}
20+
21+
return coroutineBinding {
22+
val values = producers.map { producer ->
23+
async {
24+
producer().bind()
25+
}
26+
}
27+
28+
transform(values.awaitAll())
29+
}
30+
}
31+
32+
/**
33+
* Applies the given [transform] function to two [Results][Result] _in parallel_, returning early
34+
* with the first [Err] if a transformation fails.
35+
*
36+
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map2
37+
*/
38+
public suspend fun <T1, T2, E, V> parZip(
39+
producer1: Producer<T1, E>,
40+
producer2: Producer<T2, E>,
41+
transform: suspend CoroutineScope.(T1, T2) -> V,
42+
): Result<V, E> {
43+
contract {
44+
callsInPlace(producer1, InvocationKind.AT_MOST_ONCE)
45+
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
46+
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
47+
}
48+
49+
return parZipInternal(producer1, producer2) { values ->
50+
@Suppress("UNCHECKED_CAST")
51+
transform(
52+
values[0] as T1,
53+
values[1] as T2,
54+
)
55+
}
56+
}
57+
58+
/**
59+
* Applies the given [transform] function to three [Results][Result] _in parallel_, returning early
60+
* with the first [Err] if a transformation fails.
61+
*
62+
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map3
63+
*/
64+
public suspend fun <T1, T2, T3, E, V> parZip(
65+
producer1: Producer<T1, E>,
66+
producer2: Producer<T2, E>,
67+
producer3: Producer<T3, E>,
68+
transform: suspend CoroutineScope.(T1, T2, T3) -> V,
69+
): Result<V, E> {
70+
contract {
71+
callsInPlace(producer1, InvocationKind.AT_MOST_ONCE)
72+
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
73+
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
74+
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
75+
}
76+
77+
return parZipInternal(producer1, producer2, producer3) { values ->
78+
@Suppress("UNCHECKED_CAST")
79+
transform(
80+
values[0] as T1,
81+
values[1] as T2,
82+
values[2] as T3,
83+
)
84+
}
85+
}
86+
87+
/**
88+
* Applies the given [transform] function to four [Results][Result] _in parallel_, returning early
89+
* with the first [Err] if a transformation fails.
90+
*
91+
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map4
92+
*/
93+
public suspend fun <T1, T2, T3, T4, E, V> parZip(
94+
producer1: Producer<T1, E>,
95+
producer2: Producer<T2, E>,
96+
producer3: Producer<T3, E>,
97+
producer4: Producer<T4, E>,
98+
transform: suspend CoroutineScope.(T1, T2, T3, T4) -> V,
99+
): Result<V, E> {
100+
contract {
101+
callsInPlace(producer1, InvocationKind.AT_MOST_ONCE)
102+
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
103+
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
104+
callsInPlace(producer4, InvocationKind.AT_MOST_ONCE)
105+
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
106+
}
107+
108+
return parZipInternal(producer1, producer2, producer3, producer4) { values ->
109+
@Suppress("UNCHECKED_CAST")
110+
transform(
111+
values[0] as T1,
112+
values[1] as T2,
113+
values[2] as T3,
114+
values[3] as T4,
115+
)
116+
}
117+
}
118+
119+
/**
120+
* Applies the given [transform] function to five [Results][Result] _in parallel_, returning early
121+
* with the first [Err] if a transformation fails.
122+
*
123+
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map5
124+
*/
125+
public suspend fun <T1, T2, T3, T4, T5, E, V> parZip(
126+
producer1: Producer<T1, E>,
127+
producer2: Producer<T2, E>,
128+
producer3: Producer<T3, E>,
129+
producer4: Producer<T4, E>,
130+
producer5: Producer<T5, E>,
131+
transform: suspend CoroutineScope.(T1, T2, T3, T4, T5) -> V,
132+
): Result<V, E> {
133+
contract {
134+
callsInPlace(producer1, InvocationKind.AT_MOST_ONCE)
135+
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
136+
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
137+
callsInPlace(producer4, InvocationKind.AT_MOST_ONCE)
138+
callsInPlace(producer5, InvocationKind.AT_MOST_ONCE)
139+
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
140+
}
141+
142+
return parZipInternal(producer1, producer2, producer3, producer4, producer5) { values ->
143+
@Suppress("UNCHECKED_CAST")
144+
transform(
145+
values[0] as T1,
146+
values[1] as T2,
147+
values[2] as T3,
148+
values[3] as T4,
149+
values[4] as T5,
150+
)
151+
}
152+
}

0 commit comments

Comments
 (0)