Skip to content

Commit

Permalink
fix #232 (#235)
Browse files Browse the repository at this point in the history
* fix #232

* fix #232
  • Loading branch information
hoc081098 committed Feb 16, 2024
1 parent bf1f2cf commit cf453d3
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 12 deletions.
22 changes: 22 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ kotlin {
androidNativeX86()
androidNativeX64()

applyDefaultHierarchyTemplate()

sourceSets {
commonMain {
dependencies {
Expand All @@ -116,16 +118,36 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
}
}

jvmTest {
dependencies {
implementation(kotlin("test-junit"))
}
}

val nonJvmMain by creating {
dependsOn(commonMain.get())
}
val nonJvmTest by creating {
dependsOn(commonTest.get())
}

jsMain {
dependsOn(nonJvmMain)
}
jsTest {
dependsOn(nonJvmTest)
dependencies {
implementation(kotlin("test-js"))
}
}

nativeMain {
dependsOn(nonJvmMain)
}
nativeTest {
dependsOn(nonJvmTest)
}
}

// enable running ios tests on a background thread as well
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@

package com.hoc081098.flowext.internal

import kotlinx.coroutines.flow.FlowCollector
// Reference: https://github.com/Kotlin/kotlinx.coroutines/blob/8c516f5ab1fcc39629d2838489598135eedd7b80/kotlinx-coroutines-core/common/src/flow/internal/FlowExceptions.common.kt
// Change: We don't inherit from `kotlinx.coroutines.CancellationException`.

/**
* This exception is thrown when operator need no more elements from the flow.
* This exception should never escape outside of operator's implementation.
* This exception can be safely ignored by non-terminal flow operator if and only if it was caught by its owner
* (see usages of [checkOwnership]).
* This exception is thrown when an operator needs no more elements from the flow.
*
* The operator should never allow this exception to be thrown past its own boundary.
* This exception can be safely ignored by non-terminal flow operator
* if and only if it was caught by its owner (see usages of [checkOwnership]).
*
* Therefore, the [owner] parameter must be unique for every invocation of every operator.
*/
internal class ClosedException(val owner: FlowCollector<*>) :
Exception("Flow was aborted, no more elements needed")
internal expect class ClosedException(owner: Any) : Exception {
val owner: Any
}

internal fun ClosedException.checkOwnership(owner: FlowCollector<*>) {
internal fun ClosedException.checkOwnership(owner: Any) {
if (this.owner !== owner) throw this
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@ public fun <T> Flow<T>.materialize(): Flow<Event<T>> = map<T, Event<T>> { Event.
* Converts a [Flow] of [Event] objects into the emissions that they represent.
*/
public fun <T> Flow<Event<T>>.dematerialize(): Flow<T> = flow {
val ownershipMarker = Any()

try {
collect {
when (it) {
Event.Complete -> throw ClosedException(this)
Event.Complete -> throw ClosedException(ownershipMarker)
is Event.Error -> throw it.error
is Event.Value -> emit(it.value)
}
}
} catch (e: ClosedException) {
e.checkOwnership(this@flow)
e.checkOwnership(owner = ownershipMarker)
}
}
6 changes: 4 additions & 2 deletions src/commonMain/kotlin/com/hoc081098/flowext/takeUntil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,19 @@ import kotlinx.coroutines.launch
* will cause the output [Flow] of [takeUntil] to stop emitting values from the source [Flow].
*/
public fun <T> Flow<T>.takeUntil(notifier: Flow<Any?>): Flow<T> = flow {
val ownershipMarker = Any()

try {
coroutineScope {
val job = launch(start = CoroutineStart.UNDISPATCHED) {
notifier.take(1).collect()
throw ClosedException(this@flow)
throw ClosedException(ownershipMarker)
}

collect { emit(it) }
job.cancel()
}
} catch (e: ClosedException) {
e.checkOwnership(this@flow)
e.checkOwnership(owner = ownershipMarker)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* MIT License
*
* Copyright (c) 2021-2024 Petrus Nguyễn Thái Học
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package com.hoc081098.flowext.internal

internal actual class ClosedException actual constructor(
@JvmField @Transient actual val owner: Any,
) : Exception("Flow was aborted, no more elements needed")
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* MIT License
*
* Copyright (c) 2021-2024 Petrus Nguyễn Thái Học
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package com.hoc081098.flowext.internal

internal actual class ClosedException actual constructor(
actual val owner: Any,
) : Exception("Flow was aborted, no more elements needed")

0 comments on commit cf453d3

Please sign in to comment.