@@ -4,7 +4,9 @@ import kotlin.coroutines.Continuation
4
4
import kotlin.coroutines.CoroutineContext
5
5
import kotlin.coroutines.EmptyCoroutineContext
6
6
import kotlin.coroutines.startCoroutine
7
- import kotlin.coroutines.suspendCoroutine
7
+ import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
8
+ import kotlin.coroutines.intrinsics.intercepted
9
+ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
8
10
9
11
sealed class RaceTriple <A , B , C > {
10
12
data class First <A , B , C >(val winner : A , val fiberB : Fiber <B >, val fiberC : Fiber <C >) : RaceTriple<A, B, C>()
@@ -60,79 +62,83 @@ suspend fun <A, B, C> raceTriple(
60
62
fa : suspend () -> A ,
61
63
fb : suspend () -> B ,
62
64
fc : suspend () -> C
63
- ): RaceTriple <A , B , C > = suspendCoroutine { cont ->
64
- val conn = cont.context.connection()
65
- val active = AtomicBooleanW (true )
66
-
67
- // Cancellable connection for the left value
68
- val connA = SuspendConnection ()
69
- val promiseA = UnsafePromise <A >()
70
-
71
- // Cancellable connection for the right value
72
- val connB = SuspendConnection ()
73
- val promiseB = UnsafePromise <B >()
74
-
75
- // Cancellable connection for the right value
76
- val connC = SuspendConnection ()
77
- val promiseC = UnsafePromise <C >()
78
-
79
- conn.push(listOf (connA.cancelToken(), connB.cancelToken(), connC.cancelToken()))
80
-
81
- fun <A > onError (
82
- error : Throwable ,
83
- connB : SuspendConnection ,
84
- connC : SuspendConnection ,
85
- promise : UnsafePromise <A >
86
- ): Unit {
87
- if (active.getAndSet(false )) { // if an error finishes first, stop the race.
88
- connB.cancelToken().cancel.startCoroutine(Continuation (EmptyCoroutineContext ) { r2 ->
89
- connC.cancelToken().cancel.startCoroutine(Continuation (EmptyCoroutineContext ) { r3 ->
90
- conn.pop()
65
+ ): RaceTriple <A , B , C > =
66
+ suspendCoroutineUninterceptedOrReturn { cont ->
67
+ val conn = cont.context.connection()
68
+ val cont = cont.intercepted()
69
+ val active = AtomicBooleanW (true )
91
70
92
- val errorResult = r2.fold({
93
- r3.fold({ error }, { e3 -> Platform .composeErrors(error, e3) })
94
- }, { e2 ->
95
- r3.fold({ Platform .composeErrors(error, e2) }, { e3 -> Platform .composeErrors(error, e2, e3) })
96
- })
71
+ // Cancellable connection for the left value
72
+ val connA = SuspendConnection ()
73
+ val promiseA = UnsafePromise <A >()
97
74
98
- cont.resumeWith(Result .failure(errorResult))
99
- })
100
- })
101
- } else {
102
- promise.complete(Result .failure(error))
103
- }
104
- }
75
+ // Cancellable connection for the right value
76
+ val connB = SuspendConnection ()
77
+ val promiseB = UnsafePromise <B >()
105
78
106
- fa.startCoroutineCancellable(CancellableContinuation (ctx, connA) { result ->
107
- result.fold({ a ->
108
- if (active.getAndSet(false )) {
109
- conn.pop()
110
- cont.resumeWith(Result .success(RaceTriple .First (a, Fiber (promiseB, connB), Fiber (promiseC, connC))))
111
- } else {
112
- promiseA.complete(Result .success(a))
113
- }
114
- }, { error -> onError(error, connB, connC, promiseA) })
115
- })
116
-
117
- fb.startCoroutineCancellable(CancellableContinuation (ctx, connB) { result ->
118
- result.fold({ b ->
119
- if (active.getAndSet(false )) {
120
- conn.pop()
121
- cont.resumeWith(Result .success(RaceTriple .Second (Fiber (promiseA, connA), b, Fiber (promiseC, connC))))
122
- } else {
123
- promiseB.complete(Result .success(b))
124
- }
125
- }, { error -> onError(error, connA, connC, promiseB) })
126
- })
127
-
128
- fc.startCoroutineCancellable(CancellableContinuation (ctx, connC) { result ->
129
- result.fold({ c ->
130
- if (active.getAndSet(false )) {
131
- conn.pop()
132
- cont.resumeWith(Result .success(RaceTriple .Third (Fiber (promiseA, connA), Fiber (promiseB, connB), c)))
79
+ // Cancellable connection for the right value
80
+ val connC = SuspendConnection ()
81
+ val promiseC = UnsafePromise <C >()
82
+
83
+ conn.push(listOf (connA.cancelToken(), connB.cancelToken(), connC.cancelToken()))
84
+
85
+ fun <A > onError (
86
+ error : Throwable ,
87
+ connB : SuspendConnection ,
88
+ connC : SuspendConnection ,
89
+ promise : UnsafePromise <A >
90
+ ): Unit {
91
+ if (active.getAndSet(false )) { // if an error finishes first, stop the race.
92
+ connB.cancelToken().cancel.startCoroutine(Continuation (EmptyCoroutineContext ) { r2 ->
93
+ connC.cancelToken().cancel.startCoroutine(Continuation (EmptyCoroutineContext ) { r3 ->
94
+ conn.pop()
95
+
96
+ val errorResult = r2.fold({
97
+ r3.fold({ error }, { e3 -> Platform .composeErrors(error, e3) })
98
+ }, { e2 ->
99
+ r3.fold({ Platform .composeErrors(error, e2) }, { e3 -> Platform .composeErrors(error, e2, e3) })
100
+ })
101
+
102
+ cont.resumeWith(Result .failure(errorResult))
103
+ })
104
+ })
133
105
} else {
134
- promiseC .complete(Result .success(c ))
106
+ promise .complete(Result .failure(error ))
135
107
}
136
- }, { error -> onError(error, connA, connB, promiseC) })
137
- })
138
- }
108
+ }
109
+
110
+ fa.startCoroutineCancellable(CancellableContinuation (ctx, connA) { result ->
111
+ result.fold({ a ->
112
+ if (active.getAndSet(false )) {
113
+ conn.pop()
114
+ cont.resumeWith(Result .success(RaceTriple .First (a, Fiber (promiseB, connB), Fiber (promiseC, connC))))
115
+ } else {
116
+ promiseA.complete(Result .success(a))
117
+ }
118
+ }, { error -> onError(error, connB, connC, promiseA) })
119
+ })
120
+
121
+ fb.startCoroutineCancellable(CancellableContinuation (ctx, connB) { result ->
122
+ result.fold({ b ->
123
+ if (active.getAndSet(false )) {
124
+ conn.pop()
125
+ cont.resumeWith(Result .success(RaceTriple .Second (Fiber (promiseA, connA), b, Fiber (promiseC, connC))))
126
+ } else {
127
+ promiseB.complete(Result .success(b))
128
+ }
129
+ }, { error -> onError(error, connA, connC, promiseB) })
130
+ })
131
+
132
+ fc.startCoroutineCancellable(CancellableContinuation (ctx, connC) { result ->
133
+ result.fold({ c ->
134
+ if (active.getAndSet(false )) {
135
+ conn.pop()
136
+ cont.resumeWith(Result .success(RaceTriple .Third (Fiber (promiseA, connA), Fiber (promiseB, connB), c)))
137
+ } else {
138
+ promiseC.complete(Result .success(c))
139
+ }
140
+ }, { error -> onError(error, connA, connB, promiseC) })
141
+ })
142
+
143
+ COROUTINE_SUSPENDED
144
+ }
0 commit comments