From a0219276a0aa9bd22c2c07d43869acc8ddea9af8 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Tue, 10 Sep 2024 10:07:24 +0200 Subject: [PATCH] Move `autoClose` for `Resource` to `common` (#3483) --- .../arrow-autoclose/api/arrow-autoclose.api | 4 -- .../core/arrow-autoclose/knit.code.include | 1 - .../kotlin/arrow/AutoCloseableExtensions.kt | 7 --- .../examples/example-autocloseable-01.kt | 1 - .../examples/example-autocloseable-02.kt | 1 - .../api/arrow-fx-coroutines.api | 8 ++-- .../api/arrow-fx-coroutines.klib.api | 2 + .../fx/arrow-fx-coroutines/build.gradle.kts | 1 + .../kotlin/arrow/fx/coroutines/Resource.kt | 44 ++++++++++++++++--- .../fx/coroutines/ResourceAutoCloseTest.kt | 43 ++++++++++++++++++ .../arrow/fx/coroutines/ResourceExtensions.kt | 6 +++ .../arrow/fx/coroutines/ResourceExtensions.kt | 36 ++------------- .../arrow/fx/coroutines/ResourceTestJvm.kt | 12 +++-- .../kotlin/examples/example-resource-10.kt | 13 ++++++ .../examples/example-resourceextensions-03.kt | 17 +++---- .../examples/example-resourceextensions-04.kt | 6 +-- .../examples/example-resourceextensions-05.kt | 14 ------ .../arrow/fx/coroutines/ResourceExtensions.kt | 7 +++ .../arrow/fx/coroutines/ResourceExtensions.kt | 6 +++ 19 files changed, 140 insertions(+), 89 deletions(-) delete mode 100644 arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/AutoCloseableExtensions.kt create mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceAutoCloseTest.kt create mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/jsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt create mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-10.kt delete mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-05.kt create mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/nativeMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt create mode 100644 arrow-libs/fx/arrow-fx-coroutines/src/wasmJsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt diff --git a/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api b/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api index 76d49898115..9c383d2ef2e 100644 --- a/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api +++ b/arrow-libs/core/arrow-autoclose/api/arrow-autoclose.api @@ -11,10 +11,6 @@ public final class arrow/AutoCloseScopeKt { public static final fun autoCloseScope (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object; } -public final class arrow/AutoCloseableExtensionsKt { - public static final fun install (Larrow/AutoCloseScope;Ljava/lang/AutoCloseable;)Ljava/lang/AutoCloseable; -} - public final class arrow/DefaultAutoCloseScope : arrow/AutoCloseScope { public fun ()V public fun autoClose (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; diff --git a/arrow-libs/core/arrow-autoclose/knit.code.include b/arrow-libs/core/arrow-autoclose/knit.code.include index ad6f7cd7937..9aba59e0907 100644 --- a/arrow-libs/core/arrow-autoclose/knit.code.include +++ b/arrow-libs/core/arrow-autoclose/knit.code.include @@ -4,7 +4,6 @@ package ${knit.package}.${knit.name} import arrow.AutoCloseScope import arrow.autoCloseScope -import arrow.install public class Scanner( private val path: String, diff --git a/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/AutoCloseableExtensions.kt b/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/AutoCloseableExtensions.kt deleted file mode 100644 index b642a1b0be7..00000000000 --- a/arrow-libs/core/arrow-autoclose/src/jvmMain/kotlin/arrow/AutoCloseableExtensions.kt +++ /dev/null @@ -1,7 +0,0 @@ -package arrow - -public fun AutoCloseScope.install(autoCloseable: A): A = - autoClose({ autoCloseable }) { a, errorOrNull -> - a.close() - errorOrNull?.let { throw it } - } diff --git a/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-01.kt b/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-01.kt index c6d4ed089e1..c31f45e3e20 100644 --- a/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-01.kt +++ b/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-01.kt @@ -4,7 +4,6 @@ package arrow.autocloseable.examples.exampleAutocloseable01 import arrow.AutoCloseScope import arrow.autoCloseScope -import arrow.install public class Scanner( private val path: String, diff --git a/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-02.kt b/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-02.kt index a4be1d517bd..a944072c24e 100644 --- a/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-02.kt +++ b/arrow-libs/core/arrow-autoclose/src/jvmTest/kotlin/examples/example-autocloseable-02.kt @@ -4,7 +4,6 @@ package arrow.autocloseable.examples.exampleAutocloseable02 import arrow.AutoCloseScope import arrow.autoCloseScope -import arrow.install public class Scanner( private val path: String, diff --git a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api index 315aa8734d7..905e32fc239 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api +++ b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.api @@ -217,10 +217,6 @@ public abstract interface annotation class arrow/fx/coroutines/ResourceDSL : jav } public final class arrow/fx/coroutines/ResourceExtensionsKt { - public static final fun autoCloseable (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static final fun autoCloseable (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function2; - public static synthetic fun autoCloseable$default (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; - public static synthetic fun autoCloseable$default (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/jvm/functions/Function2; public static final fun closeable (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun closeable (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function2; public static synthetic fun closeable$default (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; @@ -238,6 +234,10 @@ public final class arrow/fx/coroutines/ResourceExtensionsKt { public final class arrow/fx/coroutines/ResourceKt { public static final fun allocated (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static final fun asFlow (Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow; + public static final fun autoCloseable (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public static final fun autoCloseable (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;)Lkotlin/jvm/functions/Function2; + public static synthetic fun autoCloseable$default (Larrow/fx/coroutines/ResourceScope;Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun autoCloseable$default (Lkotlinx/coroutines/CoroutineDispatcher;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/jvm/functions/Function2; public static final fun resource (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function3;)Lkotlin/jvm/functions/Function2; public static final fun resource (Lkotlin/jvm/functions/Function2;)Lkotlin/jvm/functions/Function2; public static final fun resourceScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; diff --git a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.klib.api b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.klib.api index fffa018c578..63e5fc3e47f 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.klib.api +++ b/arrow-libs/fx/arrow-fx-coroutines/api/arrow-fx-coroutines.klib.api @@ -147,6 +147,7 @@ final fun <#A: kotlin/Any?> (kotlinx.coroutines.flow/Flow<#A>).arrow.fx.coroutin final fun <#A: kotlin/Any?> (kotlinx.coroutines.flow/Flow<#A>).arrow.fx.coroutines/repeat(): kotlinx.coroutines.flow/Flow<#A> // arrow.fx.coroutines/repeat|repeat@kotlinx.coroutines.flow.Flow<0:0>(){0§}[0] final fun <#A: kotlin/Any?> arrow.fx.coroutines/resource(kotlin.coroutines/SuspendFunction0<#A>, kotlin.coroutines/SuspendFunction2<#A, arrow.fx.coroutines/ExitCase, kotlin/Unit>): kotlin.coroutines/SuspendFunction1 // arrow.fx.coroutines/resource|resource(kotlin.coroutines.SuspendFunction0<0:0>;kotlin.coroutines.SuspendFunction2<0:0,arrow.fx.coroutines.ExitCase,kotlin.Unit>){0§}[0] final fun <#A: kotlin/Any?> arrow.fx.coroutines/resource(kotlin.coroutines/SuspendFunction1): kotlin.coroutines/SuspendFunction1 // arrow.fx.coroutines/resource|resource(kotlin.coroutines.SuspendFunction1){0§}[0] +final fun <#A: kotlin/AutoCloseable> arrow.fx.coroutines/autoCloseable(kotlinx.coroutines/CoroutineDispatcher = ..., kotlin.coroutines/SuspendFunction0<#A>): kotlin.coroutines/SuspendFunction1 // arrow.fx.coroutines/autoCloseable|autoCloseable(kotlinx.coroutines.CoroutineDispatcher;kotlin.coroutines.SuspendFunction0<0:0>){0§}[0] final fun arrow.fx.coroutines/fixedRate(kotlin.time/Duration, kotlin/Boolean = ..., kotlin/Function0 = ...): kotlinx.coroutines.flow/Flow // arrow.fx.coroutines/fixedRate|fixedRate(kotlin.time.Duration;kotlin.Boolean;kotlin.Function0){}[0] final fun arrow.fx.coroutines/fixedRate(kotlin/Long, kotlin/Boolean = ..., kotlin/Function0 = ...): kotlinx.coroutines.flow/Flow // arrow.fx.coroutines/fixedRate|fixedRate(kotlin.Long;kotlin.Boolean;kotlin.Function0){}[0] final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (kotlinx.coroutines.flow/Flow<#A>).arrow.fx.coroutines/mapIndexed(crossinline kotlin.coroutines/SuspendFunction2): kotlinx.coroutines.flow/Flow<#B> // arrow.fx.coroutines/mapIndexed|mapIndexed@kotlinx.coroutines.flow.Flow<0:0>(kotlin.coroutines.SuspendFunction2){0§;1§}[0] @@ -166,6 +167,7 @@ final suspend fun <#A: kotlin/Any?> (kotlin.coroutines/SuspendFunction1 (kotlinx.coroutines/CoroutineScope).arrow.fx.coroutines.await/awaitAll(kotlin.coroutines/SuspendFunction1): #A // arrow.fx.coroutines.await/awaitAll|awaitAll@kotlinx.coroutines.CoroutineScope(kotlin.coroutines.SuspendFunction1){0§}[0] final suspend fun <#A: kotlin/Any?> arrow.fx.coroutines.await/awaitAll(kotlin.coroutines/SuspendFunction1): #A // arrow.fx.coroutines.await/awaitAll|awaitAll(kotlin.coroutines.SuspendFunction1){0§}[0] final suspend fun <#A: kotlin/Any?> arrow.fx.coroutines/resourceScope(kotlin.coroutines/SuspendFunction1): #A // arrow.fx.coroutines/resourceScope|resourceScope(kotlin.coroutines.SuspendFunction1){0§}[0] +final suspend fun <#A: kotlin/AutoCloseable> (arrow.fx.coroutines/ResourceScope).arrow.fx.coroutines/autoCloseable(kotlinx.coroutines/CoroutineDispatcher = ..., kotlin.coroutines/SuspendFunction0<#A>): #A // arrow.fx.coroutines/autoCloseable|autoCloseable@arrow.fx.coroutines.ResourceScope(kotlinx.coroutines.CoroutineDispatcher;kotlin.coroutines.SuspendFunction0<0:0>){0§}[0] final suspend fun arrow.fx.coroutines/cancelAndCompose(kotlinx.coroutines/Deferred<*>, kotlinx.coroutines/Deferred<*>) // arrow.fx.coroutines/cancelAndCompose|cancelAndCompose(kotlinx.coroutines.Deferred<*>;kotlinx.coroutines.Deferred<*>){}[0] final suspend inline fun <#A: kotlin/Any?, #B: kotlin/Any?, #C: kotlin/Any?, #D: kotlin/Any?, #E: kotlin/Any?, #F: kotlin/Any?, #G: kotlin/Any?, #H: kotlin/Any?, #I: kotlin/Any?, #J: kotlin/Any?, #K: kotlin/Any?> (arrow.core.raise/Raise<#A>).arrow.fx.coroutines/parZipOrAccumulate(crossinline kotlin/Function2<#A, #A, #A>, crossinline kotlin.coroutines/SuspendFunction1, #B>, crossinline kotlin.coroutines/SuspendFunction1, #C>, crossinline kotlin.coroutines/SuspendFunction1, #D>, crossinline kotlin.coroutines/SuspendFunction1, #E>, crossinline kotlin.coroutines/SuspendFunction1, #F>, crossinline kotlin.coroutines/SuspendFunction1, #G>, crossinline kotlin.coroutines/SuspendFunction1, #H>, crossinline kotlin.coroutines/SuspendFunction1, #I>, crossinline kotlin.coroutines/SuspendFunction1, #J>, crossinline kotlin.coroutines/SuspendFunction10): #K // arrow.fx.coroutines/parZipOrAccumulate|parZipOrAccumulate@arrow.core.raise.Raise<0:0>(kotlin.Function2<0:0,0:0,0:0>;kotlin.coroutines.SuspendFunction1,0:1>;kotlin.coroutines.SuspendFunction1,0:2>;kotlin.coroutines.SuspendFunction1,0:3>;kotlin.coroutines.SuspendFunction1,0:4>;kotlin.coroutines.SuspendFunction1,0:5>;kotlin.coroutines.SuspendFunction1,0:6>;kotlin.coroutines.SuspendFunction1,0:7>;kotlin.coroutines.SuspendFunction1,0:8>;kotlin.coroutines.SuspendFunction1,0:9>;kotlin.coroutines.SuspendFunction10){0§;1§;2§;3§;4§;5§;6§;7§;8§;9§;10§}[0] final suspend inline fun <#A: kotlin/Any?, #B: kotlin/Any?, #C: kotlin/Any?, #D: kotlin/Any?, #E: kotlin/Any?, #F: kotlin/Any?, #G: kotlin/Any?, #H: kotlin/Any?, #I: kotlin/Any?, #J: kotlin/Any?, #K: kotlin/Any?> (arrow.core.raise/Raise<#A>).arrow.fx.coroutines/parZipOrAccumulate(kotlin.coroutines/CoroutineContext, crossinline kotlin/Function2<#A, #A, #A>, crossinline kotlin.coroutines/SuspendFunction1, #B>, crossinline kotlin.coroutines/SuspendFunction1, #C>, crossinline kotlin.coroutines/SuspendFunction1, #D>, crossinline kotlin.coroutines/SuspendFunction1, #E>, crossinline kotlin.coroutines/SuspendFunction1, #F>, crossinline kotlin.coroutines/SuspendFunction1, #G>, crossinline kotlin.coroutines/SuspendFunction1, #H>, crossinline kotlin.coroutines/SuspendFunction1, #I>, crossinline kotlin.coroutines/SuspendFunction1, #J>, crossinline kotlin.coroutines/SuspendFunction10): #K // arrow.fx.coroutines/parZipOrAccumulate|parZipOrAccumulate@arrow.core.raise.Raise<0:0>(kotlin.coroutines.CoroutineContext;kotlin.Function2<0:0,0:0,0:0>;kotlin.coroutines.SuspendFunction1,0:1>;kotlin.coroutines.SuspendFunction1,0:2>;kotlin.coroutines.SuspendFunction1,0:3>;kotlin.coroutines.SuspendFunction1,0:4>;kotlin.coroutines.SuspendFunction1,0:5>;kotlin.coroutines.SuspendFunction1,0:6>;kotlin.coroutines.SuspendFunction1,0:7>;kotlin.coroutines.SuspendFunction1,0:8>;kotlin.coroutines.SuspendFunction1,0:9>;kotlin.coroutines.SuspendFunction10){0§;1§;2§;3§;4§;5§;6§;7§;8§;9§;10§}[0] diff --git a/arrow-libs/fx/arrow-fx-coroutines/build.gradle.kts b/arrow-libs/fx/arrow-fx-coroutines/build.gradle.kts index 57aa3c3d677..0289ac1dc07 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/build.gradle.kts +++ b/arrow-libs/fx/arrow-fx-coroutines/build.gradle.kts @@ -33,6 +33,7 @@ kotlin { commonTest { dependencies { implementation(projects.arrowCore) + implementation(projects.arrowAtomic) implementation(libs.kotlin.test) implementation(libs.coroutines.test) implementation(libs.kotest.assertionsCore) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt index 98e266b4fa7..5a92a363815 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/Resource.kt @@ -6,11 +6,8 @@ import arrow.atomic.Atomic import arrow.atomic.value import arrow.core.identity import arrow.core.prependTo -import arrow.fx.coroutines.ExitCase.Cancelled -import arrow.fx.coroutines.ExitCase.Companion.ExitCase -import arrow.fx.coroutines.ExitCase.Completed -import arrow.fx.coroutines.ExitCase.Failure import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.Flow @@ -517,9 +514,9 @@ private value class ResourceScopeImpl( acquire().also { a -> val finalizer: suspend (ExitCase) -> Unit = { exitCase -> val errorOrNull = when (exitCase) { - Completed -> null - is Cancelled -> exitCase.exception - is Failure -> exitCase.failure + ExitCase.Completed -> null + is ExitCase.Cancelled -> exitCase.exception + is ExitCase.Failure -> exitCase.failure } release(a, errorOrNull) } @@ -536,3 +533,36 @@ private value class ResourceScopeImpl( } ?: acc } } + +/** Platform-dependent IO [CoroutineDispatcher] **/ +internal expect val IODispatcher: CoroutineDispatcher + +/** + * Creates a [Resource] from an [AutoCloseable], which uses [AutoCloseable.close] for releasing. + * + * ```kotlin + * import arrow.fx.coroutines.resourceScope + * import arrow.fx.coroutines.autoCloseable + * import java.io.FileInputStream + * + * suspend fun copyFile(src: String, dest: String): Unit = + * resourceScope { + * val a: FileInputStream = autoCloseable { FileInputStream(src) } + * val b: FileInputStream = autoCloseable { FileInputStream(dest) } + * /** read from [a] and write to [b]. **/ + * } // Both resources will be closed accordingly to their #close methods + * ``` + * + */ +@ResourceDSL +public suspend fun ResourceScope.autoCloseable( + closingDispatcher: CoroutineDispatcher = IODispatcher, + autoCloseable: suspend () -> A, +): A = install({ autoCloseable() } ) { s: A, _: ExitCase -> withContext(closingDispatcher) { s.close() } } + +public fun autoCloseable( + closingDispatcher: CoroutineDispatcher = IODispatcher, + autoCloseable: suspend () -> A, +): Resource = resource { + autoCloseable(closingDispatcher, autoCloseable) +} diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceAutoCloseTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceAutoCloseTest.kt new file mode 100644 index 00000000000..9494bc00416 --- /dev/null +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/ResourceAutoCloseTest.kt @@ -0,0 +1,43 @@ +package arrow.fx.coroutines + +import arrow.atomic.AtomicBoolean +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.matchers.shouldBe +import io.kotest.property.Arb +import io.kotest.property.checkAll +import kotlinx.coroutines.test.runTest +import kotlin.test.Test + +class ResourceAutoCloseTest { + + class AutoCloseableTest : AutoCloseable { + val didClose = AtomicBoolean(false) + override fun close() = didClose.set(true) + } + + @Test + fun autoCloseableCloses() = runTest { + val t = AutoCloseableTest() + resourceScope { + autoCloseable { t } + } + + t.didClose.get() shouldBe true + } + + @Test + fun autoCloseableClosesOnError() = runTest { + checkAll(10, Arb.throwable()) { throwable -> + val t = AutoCloseableTest() + + shouldThrow { + resourceScope { + autoCloseable { t } + throw throwable + } + } shouldBe throwable + + t.didClose.get() shouldBe true + } + } +} diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt new file mode 100644 index 00000000000..79d11ad184d --- /dev/null +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt @@ -0,0 +1,6 @@ +package arrow.fx.coroutines + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +internal actual val IODispatcher: CoroutineDispatcher = Dispatchers.Main diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt index b36b6e8bf3e..aa606861ff1 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt @@ -16,6 +16,8 @@ import java.util.concurrent.TimeUnit import kotlin.coroutines.CoroutineContext import kotlin.time.Duration +internal actual val IODispatcher: CoroutineDispatcher = Dispatchers.IO + /** * Creates a single threaded [CoroutineContext] as a [Resource]. * Upon release an orderly shutdown of the [ExecutorService] takes place in which previously submitted @@ -99,36 +101,6 @@ public fun closeable( closeable(closingDispatcher, closeable) } -/** - * Creates a [Resource] from an [AutoCloseable], which uses [AutoCloseable.close] for releasing. - * - * ```kotlin - * import arrow.fx.coroutines.resourceScope - * import arrow.fx.coroutines.autoCloseable - * import java.io.FileInputStream - * - * suspend fun copyFile(src: String, dest: String): Unit = - * resourceScope { - * val a: FileInputStream = autoCloseable { FileInputStream(src) } - * val b: FileInputStream = autoCloseable { FileInputStream(dest) } - * /** read from [a] and write to [b]. **/ - * } // Both resources will be closed accordingly to their #close methods - * ``` - * - */ -@ResourceDSL -public suspend fun ResourceScope.autoCloseable( - closingDispatcher: CoroutineDispatcher = Dispatchers.IO, - autoCloseable: suspend () -> A, -): A = install({ autoCloseable() } ) { s: A, _: ExitCase -> withContext(closingDispatcher) { s.close() } } - -public fun autoCloseable( - closingDispatcher: CoroutineDispatcher = Dispatchers.IO, - autoCloseable: suspend () -> A, -): Resource = resource { - autoCloseable(closingDispatcher, autoCloseable) -} - /** * Creates a single threaded [CoroutineContext] as a [Resource]. * Upon release an orderly shutdown of the [ExecutorService] takes place in which previously submitted @@ -150,7 +122,7 @@ public fun autoCloseable( * ```text * I am running on single * ``` - * + * */ @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class) @ResourceDSL @@ -181,7 +153,7 @@ public fun singleThreadContext(name: String): Resource + * */ @OptIn(DelicateCoroutinesApi::class) @ResourceDSL diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/ResourceTestJvm.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/ResourceTestJvm.kt index f71f670ba07..e16df010762 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/ResourceTestJvm.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/ResourceTestJvm.kt @@ -2,20 +2,18 @@ package arrow.fx.coroutines import io.kotest.assertions.throwables.shouldThrow import io.kotest.matchers.shouldBe -import io.kotest.matchers.types.shouldBeTypeOf import java.util.concurrent.atomic.AtomicBoolean import java.lang.AutoCloseable import java.io.Closeable import io.kotest.property.Arb import io.kotest.property.checkAll -import kotlinx.coroutines.CompletableDeferred import kotlin.test.DefaultAsserter.fail import kotlinx.coroutines.test.runTest import kotlin.test.Test class ResourceTestJvm { - class AutoCloseableTest : AutoCloseable { + class AutoCloseableJvmTest : AutoCloseable { val didClose = AtomicBoolean(false) override fun close() = didClose.set(true) } @@ -25,8 +23,8 @@ class ResourceTestJvm { override fun close() = didClose.set(true) } - @Test fun autoCloseableCloses() = runTest { - val t = AutoCloseableTest() + @Test fun autoCloseableJvmCloses() = runTest { + val t = AutoCloseableJvmTest() resourceScope { autoCloseable { t } } @@ -34,9 +32,9 @@ class ResourceTestJvm { t.didClose.get() shouldBe true } - @Test fun autoCloseableClosesOnError() = runTest { + @Test fun autoCloseableJvmClosesOnError() = runTest { checkAll(10, Arb.throwable()) { throwable -> - val t = AutoCloseableTest() + val t = AutoCloseableJvmTest() shouldThrow { resourceScope { diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-10.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-10.kt new file mode 100644 index 00000000000..b6307a6cd44 --- /dev/null +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resource-10.kt @@ -0,0 +1,13 @@ +// This file was automatically generated from Resource.kt by Knit tool. Do not edit. +package arrow.fx.coroutines.examples.exampleResource10 + +import arrow.fx.coroutines.resourceScope +import arrow.fx.coroutines.autoCloseable +import java.io.FileInputStream + +suspend fun copyFile(src: String, dest: String): Unit = + resourceScope { + val a: FileInputStream = autoCloseable { FileInputStream(src) } + val b: FileInputStream = autoCloseable { FileInputStream(dest) } + /** read from [a] and write to [b]. **/ + } // Both resources will be closed accordingly to their #close methods diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-03.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-03.kt index cbdf566e457..673f6814b01 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-03.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-03.kt @@ -2,12 +2,13 @@ package arrow.fx.coroutines.examples.exampleResourceextensions03 import arrow.fx.coroutines.resourceScope -import arrow.fx.coroutines.autoCloseable -import java.io.FileInputStream +import arrow.fx.coroutines.singleThreadContext +import kotlinx.coroutines.withContext +import kotlinx.coroutines.ExecutorCoroutineDispatcher -suspend fun copyFile(src: String, dest: String): Unit = - resourceScope { - val a: FileInputStream = autoCloseable { FileInputStream(src) } - val b: FileInputStream = autoCloseable { FileInputStream(dest) } - /** read from [a] and write to [b]. **/ - } // Both resources will be closed accordingly to their #close methods +suspend fun main(): Unit = resourceScope { + val single: ExecutorCoroutineDispatcher = singleThreadContext("single") + withContext(single) { + println("I am running on ${Thread.currentThread().name}") + } +} diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-04.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-04.kt index 82a7d7c1ae0..56f0737fa64 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-04.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-04.kt @@ -1,14 +1,14 @@ // This file was automatically generated from ResourceExtensions.kt by Knit tool. Do not edit. package arrow.fx.coroutines.examples.exampleResourceextensions04 +import arrow.fx.coroutines.fixedThreadPoolContext import arrow.fx.coroutines.resourceScope -import arrow.fx.coroutines.singleThreadContext import kotlinx.coroutines.withContext import kotlinx.coroutines.ExecutorCoroutineDispatcher suspend fun main(): Unit = resourceScope { - val single: ExecutorCoroutineDispatcher = singleThreadContext("single") - withContext(single) { + val pool: ExecutorCoroutineDispatcher = fixedThreadPoolContext(8, "custom-pool") + withContext(pool) { println("I am running on ${Thread.currentThread().name}") } } diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-05.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-05.kt deleted file mode 100644 index 9b7080d25a3..00000000000 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/examples/example-resourceextensions-05.kt +++ /dev/null @@ -1,14 +0,0 @@ -// This file was automatically generated from ResourceExtensions.kt by Knit tool. Do not edit. -package arrow.fx.coroutines.examples.exampleResourceextensions05 - -import arrow.fx.coroutines.fixedThreadPoolContext -import arrow.fx.coroutines.resourceScope -import kotlinx.coroutines.withContext -import kotlinx.coroutines.ExecutorCoroutineDispatcher - -suspend fun main(): Unit = resourceScope { - val pool: ExecutorCoroutineDispatcher = fixedThreadPoolContext(8, "custom-pool") - withContext(pool) { - println("I am running on ${Thread.currentThread().name}") - } -} diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/nativeMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt b/arrow-libs/fx/arrow-fx-coroutines/src/nativeMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt new file mode 100644 index 00000000000..5541891a4fa --- /dev/null +++ b/arrow-libs/fx/arrow-fx-coroutines/src/nativeMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt @@ -0,0 +1,7 @@ +package arrow.fx.coroutines + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO + +internal actual val IODispatcher: CoroutineDispatcher = Dispatchers.IO diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/wasmJsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt b/arrow-libs/fx/arrow-fx-coroutines/src/wasmJsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt new file mode 100644 index 00000000000..79d11ad184d --- /dev/null +++ b/arrow-libs/fx/arrow-fx-coroutines/src/wasmJsMain/kotlin/arrow/fx/coroutines/ResourceExtensions.kt @@ -0,0 +1,6 @@ +package arrow.fx.coroutines + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers + +internal actual val IODispatcher: CoroutineDispatcher = Dispatchers.Main