Skip to content

Commit fbaedc4

Browse files
committed
Replace kotlinx.coroutines.reactive.FlowKt and kotlinx.coroutines.reactor.FlowKt with properly named files
Otherwise, it leads to a weird classname clash and forces to write FQ imports
1 parent 6ca6ed5 commit fbaedc4

File tree

7 files changed

+159
-121
lines changed

7 files changed

+159
-121
lines changed

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactive.txt

+5
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,8 @@ public final class kotlinx/coroutines/reactive/PublisherCoroutine : kotlinx/coro
6262
public fun send (Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
6363
}
6464

65+
public final class kotlinx/coroutines/reactive/ReactiveFlowKt {
66+
public static final fun asFlow (Lorg/reactivestreams/Publisher;)Lkotlinx/coroutines/flow/Flow;
67+
public static final fun asPublisher (Lkotlinx/coroutines/flow/Flow;)Lorg/reactivestreams/Publisher;
68+
}
69+

binary-compatibility-validator/reference-public-api/kotlinx-coroutines-reactor.txt

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public final class kotlinx/coroutines/reactor/ReactorContextKt {
3636
public static final fun asCoroutineContext (Lreactor/util/context/Context;)Lkotlinx/coroutines/reactor/ReactorContext;
3737
}
3838

39+
public final class kotlinx/coroutines/reactor/ReactorFlowKt {
40+
public static final fun asFlux (Lkotlinx/coroutines/flow/Flow;)Lreactor/core/publisher/Flux;
41+
}
42+
3943
public final class kotlinx/coroutines/reactor/SchedulerCoroutineDispatcher : kotlinx/coroutines/CoroutineDispatcher, kotlinx/coroutines/Delay {
4044
public fun <init> (Lreactor/core/scheduler/Scheduler;)V
4145
public fun delay (JLkotlin/coroutines/Continuation;)Ljava/lang/Object;

reactive/kotlinx-coroutines-reactive/src/FlowAsPublisher.kt

-109
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:JvmMultifileClass
6+
@file:JvmName("FlowKt")
7+
8+
package kotlinx.coroutines.reactive
9+
10+
import kotlinx.coroutines.*
11+
import kotlinx.coroutines.flow.*
12+
import org.reactivestreams.*
13+
14+
// Binary compatibility with Spring 5.2 RC
15+
@Deprecated(
16+
message = "Replaced in favor of ReactiveFlow extension, please import kotlinx.coroutines.reactive.* instead of kotlinx.coroutines.reactive.FlowKt",
17+
level = DeprecationLevel.ERROR
18+
)
19+
@JvmName("asFlow")
20+
public fun <T : Any> Publisher<T>.asFlowDeprecated(): Flow<T> = asFlow()
21+
22+
// Binary compatibility with Spring 5.2 RC
23+
@Deprecated(
24+
message = "Replaced in favor of ReactiveFlow extension, please import kotlinx.coroutines.reactive.* instead of kotlinx.coroutines.reactive.FlowKt",
25+
level = DeprecationLevel.ERROR
26+
)
27+
@JvmName("asPublisher")
28+
public fun <T : Any> Flow<T>.asPublisherDeprecated(): Publisher<T> = asPublisher()
29+
30+
@FlowPreview
31+
@Deprecated(
32+
message = "batchSize parameter is deprecated, use .buffer() instead to control the backpressure",
33+
level = DeprecationLevel.ERROR,
34+
replaceWith = ReplaceWith("asFlow().buffer(batchSize)", imports = ["kotlinx.coroutines.flow.*"])
35+
)
36+
public fun <T : Any> Publisher<T>.asFlow(batchSize: Int): Flow<T> = asFlow().buffer(batchSize)

reactive/kotlinx-coroutines-reactive/src/PublisherAsFlow.kt renamed to reactive/kotlinx-coroutines-reactive/src/ReactiveFlow.kt

+98-11
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5-
@file:JvmMultifileClass
6-
@file:JvmName("FlowKt")
7-
85
package kotlinx.coroutines.reactive
96

7+
import kotlinx.atomicfu.*
108
import kotlinx.coroutines.*
119
import kotlinx.coroutines.channels.*
1210
import kotlinx.coroutines.flow.*
1311
import kotlinx.coroutines.flow.internal.*
12+
import kotlinx.coroutines.intrinsics.*
1413
import org.reactivestreams.*
1514
import java.util.*
1615
import kotlin.coroutines.*
@@ -28,13 +27,11 @@ import kotlin.coroutines.*
2827
public fun <T : Any> Publisher<T>.asFlow(): Flow<T> =
2928
PublisherAsFlow(this, 1)
3029

31-
@FlowPreview
32-
@Deprecated(
33-
message = "batchSize parameter is deprecated, use .buffer() instead to control the backpressure",
34-
level = DeprecationLevel.ERROR,
35-
replaceWith = ReplaceWith("asFlow().buffer(batchSize)", imports = ["kotlinx.coroutines.flow.*"])
36-
)
37-
public fun <T : Any> Publisher<T>.asFlow(batchSize: Int): Flow<T> = asFlow().buffer(batchSize)
30+
/**
31+
* Transforms the given flow to a spec-compliant [Publisher].
32+
*/
33+
@ExperimentalCoroutinesApi
34+
public fun <T : Any> Flow<T>.asPublisher(): Publisher<T> = FlowAsPublisher(this)
3835

3936
private class PublisherAsFlow<T : Any>(
4037
private val publisher: Publisher<T>,
@@ -137,4 +134,94 @@ private val contextInjectors: List<ContextInjector> =
137134
ServiceLoader.load(ContextInjector::class.java, ContextInjector::class.java.classLoader).toList()
138135

139136
private fun <T> Publisher<T>.injectCoroutineContext(coroutineContext: CoroutineContext) =
140-
contextInjectors.fold(this) { pub, contextInjector -> contextInjector.injectCoroutineContext(pub, coroutineContext) }
137+
contextInjectors.fold(this) { pub, contextInjector -> contextInjector.injectCoroutineContext(pub, coroutineContext) }
138+
139+
140+
/**
141+
* Adapter that transforms [Flow] into TCK-complaint [Publisher].
142+
* [cancel] invocation cancels the original flow.
143+
*/
144+
@Suppress("PublisherImplementation")
145+
private class FlowAsPublisher<T : Any>(private val flow: Flow<T>) : Publisher<T> {
146+
override fun subscribe(subscriber: Subscriber<in T>?) {
147+
if (subscriber == null) throw NullPointerException()
148+
subscriber.onSubscribe(FlowSubscription(flow, subscriber))
149+
}
150+
}
151+
152+
/** @suppress */
153+
@InternalCoroutinesApi
154+
public class FlowSubscription<T>(
155+
@JvmField val flow: Flow<T>,
156+
@JvmField val subscriber: Subscriber<in T>
157+
) : Subscription, AbstractCoroutine<Unit>(Dispatchers.Unconfined, false) {
158+
private val requested = atomic(0L)
159+
private val producer = atomic<CancellableContinuation<Unit>?>(null)
160+
161+
override fun onStart() {
162+
::flowProcessing.startCoroutineCancellable(this)
163+
}
164+
165+
private suspend fun flowProcessing() {
166+
try {
167+
consumeFlow()
168+
subscriber.onComplete()
169+
} catch (e: Throwable) {
170+
try {
171+
if (e is CancellationException) {
172+
subscriber.onComplete()
173+
} else {
174+
subscriber.onError(e)
175+
}
176+
} catch (e: Throwable) {
177+
// Last ditch report
178+
handleCoroutineException(coroutineContext, e)
179+
}
180+
}
181+
}
182+
183+
/*
184+
* This method has at most one caller at any time (triggered from the `request` method)
185+
*/
186+
private suspend fun consumeFlow() {
187+
flow.collect { value ->
188+
/*
189+
* Flow is scopeless, thus if it's not active, its subscription was cancelled.
190+
* No intermediate "child failed, but flow coroutine is not" states are allowed.
191+
*/
192+
coroutineContext.ensureActive()
193+
if (requested.value <= 0L) {
194+
suspendCancellableCoroutine<Unit> {
195+
producer.value = it
196+
if (requested.value != 0L) it.resumeSafely()
197+
}
198+
}
199+
requested.decrementAndGet()
200+
subscriber.onNext(value)
201+
}
202+
}
203+
204+
override fun cancel() {
205+
cancel(null)
206+
}
207+
208+
override fun request(n: Long) {
209+
if (n <= 0) {
210+
return
211+
}
212+
start()
213+
requested.update { value ->
214+
val newValue = value + n
215+
if (newValue <= 0L) Long.MAX_VALUE else newValue
216+
}
217+
val producer = producer.getAndSet(null) ?: return
218+
producer.resumeSafely()
219+
}
220+
221+
private fun CancellableContinuation<Unit>.resumeSafely() {
222+
val token = tryResume(Unit)
223+
if (token != null) {
224+
completeResume(token)
225+
}
226+
}
227+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@file:JvmName("FlowKt")
2+
3+
package kotlinx.coroutines.reactor
4+
5+
import kotlinx.coroutines.flow.*
6+
import reactor.core.publisher.*
7+
8+
@Deprecated(
9+
message = "Replaced in favor of ReactiveFlow extension, please import kotlinx.coroutines.reactor.* instead of kotlinx.coroutines.reactor.FlowKt",
10+
level = DeprecationLevel.ERROR
11+
)
12+
@JvmName("asFlux")
13+
public fun <T : Any> Flow<T>.asFluxDeprecated(): Flux<T> = asFlux()

reactive/kotlinx-coroutines-reactor/src/FlowAsFlux.kt renamed to reactive/kotlinx-coroutines-reactor/src/ReactorFlow.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
@file:JvmName("FlowKt")
1+
/*
2+
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
24

35
package kotlinx.coroutines.reactor
46

0 commit comments

Comments
 (0)