diff --git a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Cancellable.kt b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Cancellable.kt index 996318d1d..1eda75e0f 100644 --- a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Cancellable.kt +++ b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Cancellable.kt @@ -24,17 +24,17 @@ open class Cancellable { @Param("100") var size: Int = 0 - fun evalCancelable(n: Int): IO = - IO.concurrent().cancelable { cb -> + fun evalCancellable(n: Int): IO = + IO.concurrent().cancellable { cb -> cb(Right(n)) IO.unit }.fix() - fun cancelableLoop(i: Int): IO = - if (i < size) evalCancelable(i + 1).flatMap { cancelableLoop(it) } - else evalCancelable(i) + fun cancellableLoop(i: Int): IO = + if (i < size) evalCancellable(i + 1).flatMap { cancellableLoop(it) } + else evalCancellable(i) @Benchmark fun io(): Int = - cancelableLoop(0).unsafeRunSync() + cancellableLoop(0).unsafeRunSync() } diff --git a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Queue.kt b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Queue.kt index a03254c7b..2d0f4c01e 100644 --- a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Queue.kt +++ b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Queue.kt @@ -9,7 +9,7 @@ import arrow.fx.extensions.io.concurrent.concurrent import arrow.fx.extensions.io.functor.unit import arrow.fx.extensions.io.monad.flatMap import arrow.fx.fix -import arrow.fx.internal.CancelableQueue +import arrow.fx.internal.CancellableQueue import org.openjdk.jmh.annotations.Benchmark import org.openjdk.jmh.annotations.CompilerControl import org.openjdk.jmh.annotations.Fork @@ -39,7 +39,7 @@ open class Queue { @Setup(Level.Trial) fun createQueues(): Unit { ConcurQueue = ConcurrentQueue.empty(IO.concurrent()).fix().unsafeRunSync() - CancelQueue = CancelableQueue.empty(IO.concurrent()).fix().unsafeRunSync() + CancelQueue = CancellableQueue.empty(IO.concurrent()).fix().unsafeRunSync() } fun IOOf.repeat(n: Int): IO = @@ -54,5 +54,5 @@ open class Queue { fun concurrentQueue(): Unit = loop(ConcurQueue) @Benchmark - fun cancelableQueue(): Unit = loop(CancelQueue) + fun cancellableQueue(): Unit = loop(CancelQueue) } diff --git a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Uncancellable.kt b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Uncancellable.kt index 857185360..d3b1ae560 100644 --- a/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Uncancellable.kt +++ b/arrow-benchmarks-fx/src/jmh/kotlin/arrow/benchmarks/Uncancellable.kt @@ -21,10 +21,10 @@ open class Uncancellable { @Param("100") var size: Int = 0 - fun ioUncancelableLoop(i: Int): IO = - if (i < size) IO { i + 1 }.uncancelable().flatMap { ioUncancelableLoop(it) } + fun ioUncancellableLoop(i: Int): IO = + if (i < size) IO { i + 1 }.uncancellable().flatMap { ioUncancellableLoop(it) } else IO.just(i) @Benchmark - fun io(): Int = ioUncancelableLoop(0).unsafeRunSync() + fun io(): Int = ioUncancellableLoop(0).unsafeRunSync() } diff --git a/arrow-docs/docs/fiber/README.md b/arrow-docs/docs/fiber/README.md index 2ffa56ddc..188c6b251 100644 --- a/arrow-docs/docs/fiber/README.md +++ b/arrow-docs/docs/fiber/README.md @@ -8,11 +8,11 @@ permalink: /effects/fiber/ A `Fiber` is a concurrency primitive for describing parallel operations or multi-tasking. -Concurrently started tasks can either be joined or canceled, and these are the only two operators available on `Fiber`. +Concurrently started tasks can either be joined or cancelled, and these are the only two operators available on `Fiber`. Using `Fiber`, we can describe parallel operations such as `parallelMap` relatively easily. **Note** the operation written below does not support proper cancellation. -When the resulting `IO` is canceled, it does not propagate this cancellation back to the underlying `IO`. +When the resulting `IO` is cancelled, it does not propagate this cancellation back to the underlying `IO`. ```kotlin:ank import arrow.fx.* diff --git a/arrow-docs/docs/fx/typeclasses/bracket/README.md b/arrow-docs/docs/fx/typeclasses/bracket/README.md index b57f6e6af..fd75c2f0a 100644 --- a/arrow-docs/docs/fx/typeclasses/bracket/README.md +++ b/arrow-docs/docs/fx/typeclasses/bracket/README.md @@ -253,7 +253,7 @@ println(safeComputation) #### bracketCase It's a generalized version of `bracket()` that uses `ExitCase` to distinguish between different exit cases when -releasing the acquired resource. `ExitCase` can take the values `Completed`, `Canceled`, or `Error(e)`. So, depending +releasing the acquired resource. `ExitCase` can take the values `Completed`, `Cancelled`, or `Error(e)`. So, depending how the `use` execution finalizes, the corresponding `ExitCase` value will be passed to the `release` lambda. It requires passing `release` and `use` lambdas. It ensures acquiring, using, and releasing the resource at the end. @@ -282,7 +282,7 @@ val safeComputation = openFile("data.json").bracketCase( release = { file, exitCase -> when (exitCase) { is ExitCase.Completed -> { /* do something */ } - is ExitCase.Canceled -> { /* do something */ } + is ExitCase.Cancelled -> { /* do something */ } is ExitCase.Error -> { /* do something */ } } closeFile(file) @@ -297,7 +297,7 @@ println(safeComputation) #### guarantee/guaranteeCase - onCancel/onError -Ignores the acquisition and focuses on using a resource and performing an action whenever it finishes in any way (completed, error, canceled). +Ignores the acquisition and focuses on using a resource and performing an action whenever it finishes in any way (completed, error, cancelled). Similarly as for `bracketCase`, `guaranteeCase` works in the same way as `guarantee` but uses `ExitCase` to distinguish between different exit cases when releasing the acquired resource. diff --git a/arrow-docs/docs/integrations/kotlinxcoroutines/README.md b/arrow-docs/docs/integrations/kotlinxcoroutines/README.md index 401b88f7d..4799663b2 100644 --- a/arrow-docs/docs/integrations/kotlinxcoroutines/README.md +++ b/arrow-docs/docs/integrations/kotlinxcoroutines/README.md @@ -32,7 +32,7 @@ If you'd like to introduce `IO` in your project, you might want to keep using th ### unsafeRunScoped & unsafeRunIO -`IO.unsafeRunScoped(scope, cb)` runs the specific `IO` with a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), so it will be automatically canceled when the scope does as well. +`IO.unsafeRunScoped(scope, cb)` runs the specific `IO` with a [CoroutineScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html), so it will be automatically cancelled when the scope does as well. Similarly, there's `scope.unsafeRunIO(IO, cb)`, which works in the same way with different syntax: diff --git a/arrow-docs/docs/promise/README.md b/arrow-docs/docs/promise/README.md index 3fd57f1d3..a18993279 100644 --- a/arrow-docs/docs/promise/README.md +++ b/arrow-docs/docs/promise/README.md @@ -14,7 +14,7 @@ A `Promise` guarantees (promises) `A` at some point in the future within the con ## Constructing a Promise -A promise can easily be made by calling `uncancelable`. +A promise can easily be made by calling `uncancellable`. Since the allocation of mutable state is not referentially transparent, this side-effect is contained within `F`. ```kotlin:ank:playground @@ -24,13 +24,13 @@ import arrow.fx.extensions.io.async.async fun main(args: Array) { //sampleStart val promise: IO> = - Promise.uncancelable(IO.async()).fix() + Promise.uncancellable(IO.async()).fix() //sampleEnd println(promise) } ``` -In case you want the side-effect to execute immediately and return the `Promise` instance, you can use the `unsafeUncancelable` function. +In case you want the side-effect to execute immediately and return the `Promise` instance, you can use the `unsafeUncancellable` function. ```kotlin:ank:playground import arrow.fx.* @@ -38,7 +38,7 @@ import arrow.fx.extensions.io.async.async fun main(args: Array) { //sampleStart -val unsafePromise: Promise = Promise.unsafeUncancelable(IO.async()) +val unsafePromise: Promise = Promise.unsafeUncancellable(IO.async()) //sampleEnd println(unsafePromise) } @@ -55,7 +55,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -Promise.uncancelable(IO.async()).flatMap { p -> +Promise.uncancellable(IO.async()).flatMap { p -> p.get() } //never ends because `get` keeps waiting for p to be fulfilled. //sampleEnd @@ -69,7 +69,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -val result = Promise.uncancelable(IO.async()).flatMap { p -> +val result = Promise.uncancellable(IO.async()).flatMap { p -> p.complete(1).flatMap { p.get() } @@ -90,7 +90,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -val result = Promise.uncancelable(IO.async()).flatMap { p -> +val result = Promise.uncancellable(IO.async()).flatMap { p -> p.complete(2).flatMap { p.get() } @@ -107,7 +107,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -val result = Promise.uncancelable(IO.async()).flatMap { p -> +val result = Promise.uncancellable(IO.async()).flatMap { p -> p.complete(1).flatMap { p.complete(2) } @@ -130,7 +130,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -val result = Promise.uncancelable(IO.async()).flatMap { p -> +val result = Promise.uncancellable(IO.async()).flatMap { p -> p.error(RuntimeException("Break promise")) } .attempt() @@ -147,7 +147,7 @@ import arrow.fx.extensions.io.monad.flatMap fun main(args: Array) { //sampleStart -val result = Promise.uncancelable(IO.async()).flatMap { p -> +val result = Promise.uncancellable(IO.async()).flatMap { p -> p.complete(1).flatMap { p.error(RuntimeException("Break promise")) } diff --git a/arrow-fx-kotlinx-coroutines/src/test/kotlin/arrow/integrations/kotlinx/CoroutinesIntegrationTest.kt b/arrow-fx-kotlinx-coroutines/src/test/kotlin/arrow/integrations/kotlinx/CoroutinesIntegrationTest.kt index 5ae0c77da..e3bed9485 100644 --- a/arrow-fx-kotlinx-coroutines/src/test/kotlin/arrow/integrations/kotlinx/CoroutinesIntegrationTest.kt +++ b/arrow-fx-kotlinx-coroutines/src/test/kotlin/arrow/integrations/kotlinx/CoroutinesIntegrationTest.kt @@ -90,7 +90,7 @@ class CoroutinesIntegrationTest : UnitSpec() { val promise = !Promise() !effect { scope.launch { - IO.cancelable { promise.complete(i) }.suspendCancellable() + IO.cancellable { promise.complete(i) }.suspendCancellable() } } !effect { scope.cancel() } @@ -135,7 +135,7 @@ class CoroutinesIntegrationTest : UnitSpec() { val scope = TestCoroutineScope(Job() + TestCoroutineDispatcher()) val promise = !Promise() !effect { - IO.cancelable { promise.complete(i) }.unsafeRunScoped(scope) { } + IO.cancellable { promise.complete(i) }.unsafeRunScoped(scope) { } } !effect { scope.cancel() } !promise.get() diff --git a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxK.kt b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxK.kt index e8073f23f..190145b36 100644 --- a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxK.kt +++ b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxK.kt @@ -79,7 +79,7 @@ data class FluxK(val flux: Flux) : FluxKOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -94,13 +94,13 @@ data class FluxK(val flux: Flux) : FluxKOf { fun bracketCase(use: (A) -> FluxKOf, release: (A, ExitCase) -> FluxKOf): FluxK = FluxK(Flux.create { sink -> flux.subscribe({ a -> - if (sink.isCancelled) release(a, ExitCase.Canceled).fix().flux.subscribe({}, sink::error) + if (sink.isCancelled) release(a, ExitCase.Cancelled).fix().flux.subscribe({}, sink::error) else try { sink.onDispose(use(a).fix() .flatMap { b -> release(a, ExitCase.Completed).fix().map { b } } .handleErrorWith { e -> release(a, ExitCase.Error(e)).fix().flatMap { FluxK.raiseError(e) } } .flux - .doOnCancel { release(a, ExitCase.Canceled).fix().flux.subscribe({}, sink::error) } + .doOnCancel { release(a, ExitCase.Cancelled).fix().flux.subscribe({}, sink::error) } .subscribe({ sink.next(it) }, sink::error, { }, { sink.onRequest(it::request) }) @@ -208,8 +208,8 @@ data class FluxK(val flux: Flux) : FluxKOf { * ``` */ @Deprecated(message = - "For wrapping cancelable operations you should use cancelable instead.\n" + - "For wrapping uncancelable operations you can use the non-deprecated async") + "For wrapping cancellable operations you should use cancellable instead.\n" + + "For wrapping uncancellable operations you can use the non-deprecated async") fun async(fa: FluxKProc): FluxK = Flux.create { sink -> val conn = FluxKConnection() @@ -241,8 +241,8 @@ data class FluxK(val flux: Flux) : FluxKOf { }.k() @Deprecated(message = - "For wrapping cancelable operations you should use cancelableF instead.\n" + - "For wrapping uncancelable operations you can use the non-deprecated asyncF") + "For wrapping cancellable operations you should use cancellableF instead.\n" + + "For wrapping uncancellable operations you can use the non-deprecated asyncF") fun asyncF(fa: FluxKProcF): FluxK = Flux.create { sink: FluxSink -> val conn = FluxKConnection() @@ -273,7 +273,11 @@ data class FluxK(val flux: Flux) : FluxKOf { }.fix().flux.subscribe({}, sink::error) }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) fun cancelable(fa: ((Either) -> Unit) -> CancelToken): FluxK = + cancellable(fa) + + fun cancellable(fa: ((Either) -> Unit) -> CancelToken): FluxK = Flux.create { sink -> val token = fa { either: Either -> either.fold({ e -> @@ -286,7 +290,11 @@ data class FluxK(val flux: Flux) : FluxKOf { sink.onDispose { token.value().subscribe({}, sink::error) } }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> FluxKOf>): FluxK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> FluxKOf>): FluxK = Flux.create { sink -> val cb = { either: Either -> either.fold({ e -> diff --git a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxKConnection.kt b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxKConnection.kt index 342f32d17..4f0a8a90a 100644 --- a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxKConnection.kt +++ b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/FluxKConnection.kt @@ -5,9 +5,9 @@ import arrow.fx.KindConnection import arrow.fx.typeclasses.ExitCase import arrow.fx.typeclasses.MonadDefer -@Deprecated("Cancellation should be done with the cancelable combinator") +@Deprecated("Cancellation should be done with the cancellable combinator") typealias FluxKProc = (KindConnection, (Either) -> Unit) -> Unit -@Deprecated("Cancellation should be done with the cancelable combinator") +@Deprecated("Cancellation should be done with the cancellable combinator") typealias FluxKProcF = (KindConnection, (Either) -> Unit) -> FluxKOf /** @@ -22,7 +22,7 @@ typealias FluxKProcF = (KindConnection, (Either) -> U */ @Suppress("UNUSED_PARAMETER", "FunctionName") @Deprecated(message = "Cancelling operations through FluxKConnection will not be supported anymore." + - "In case you need to cancel multiple processes can do so by using cancelable and composing cancel operations using zipWith or other parallel operators") + "In case you need to cancel multiple processes can do so by using cancellable and composing cancel operations using zipWith or other parallel operators") fun FluxKConnection(dummy: Unit = Unit): KindConnection = KindConnection(object : MonadDefer { override fun defer(fa: () -> FluxKOf): FluxK = FluxK.defer(fa) diff --git a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoK.kt b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoK.kt index 21ae58a2c..f1f4b759b 100644 --- a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoK.kt +++ b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoK.kt @@ -85,7 +85,7 @@ data class MonoK(val mono: Mono) : MonoKOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -99,17 +99,17 @@ data class MonoK(val mono: Mono) : MonoKOf { */ fun bracketCase(use: (A) -> MonoKOf, release: (A, ExitCase) -> MonoKOf): MonoK = MonoK(Mono.create { sink -> - val isCanceled = AtomicBooleanW(false) - sink.onCancel { isCanceled.value = true } + val isCancelled = AtomicBooleanW(false) + sink.onCancel { isCancelled.value = true } val a: A? = mono.block() if (a != null) { - if (isCanceled.value) release(a, ExitCase.Canceled).fix().mono.subscribe({}, sink::error) + if (isCancelled.value) release(a, ExitCase.Cancelled).fix().mono.subscribe({}, sink::error) else try { sink.onDispose(use(a).fix() .flatMap { b -> release(a, ExitCase.Completed).fix().map { b } } .handleErrorWith { e -> release(a, ExitCase.Error(e)).fix().flatMap { MonoK.raiseError(e) } } .mono - .doOnCancel { release(a, ExitCase.Canceled).fix().mono.subscribe({}, sink::error) } + .doOnCancel { release(a, ExitCase.Cancelled).fix().mono.subscribe({}, sink::error) } .subscribe(sink::success, sink::error) ) } catch (e: Throwable) { @@ -162,8 +162,8 @@ data class MonoK(val mono: Mono) : MonoKOf { Mono.defer { fa().value() }.k() @Deprecated(message = - "For wrapping cancelable operations you should use cancelable instead.\n" + - "For wrapping uncancelable operations you can use the non-deprecated async") + "For wrapping cancellable operations you should use cancellable instead.\n" + + "For wrapping uncancellable operations you can use the non-deprecated async") fun async(fa: MonoKProc): MonoK = Mono.create { sink -> val conn = MonoKConnection() @@ -184,7 +184,7 @@ data class MonoK(val mono: Mono) : MonoKOf { }.k() /** - * Constructor for wrapping uncancelable async operations. + * Constructor for wrapping uncancellable async operations. * It's safe to wrap unsafe operations in this constructor * * ```kotlin:ank:playground @@ -222,8 +222,8 @@ data class MonoK(val mono: Mono) : MonoKOf { }.k() @Deprecated(message = - "For wrapping cancelable operations you should use cancelableF instead.\n" + - "For wrapping uncancelable operations you can use the non-deprecated asyncF") + "For wrapping cancellable operations you should use cancellableF instead.\n" + + "For wrapping uncancellable operations you can use the non-deprecated asyncF") fun asyncF(fa: MonoKProcF): MonoK = Mono.create { sink: MonoSink -> val conn = MonoKConnection() @@ -255,7 +255,7 @@ data class MonoK(val mono: Mono) : MonoKOf { }.k() /** - * Creates a [MonoK] that'll wraps/runs a cancelable operation. + * Creates a [MonoK] that'll wraps/runs a cancellable operation. * * ```kotlin:ank:playground * import arrow.core.* @@ -271,7 +271,7 @@ data class MonoK(val mono: Mono) : MonoKOf { * * fun main(args: Array) { * //sampleStart - * val result = SingleK.cancelable { cb: (Either) -> Unit -> + * val result = SingleK.cancellable { cb: (Either) -> Unit -> * val nw = NetworkApi() * val disposable = nw.async { result -> cb(Right(result)) } * SingleK { disposable.invoke() } @@ -281,7 +281,7 @@ data class MonoK(val mono: Mono) : MonoKOf { * } * ``` */ - fun cancelable(fa: ((Either) -> Unit) -> CancelToken): MonoK = + fun cancellable(fa: ((Either) -> Unit) -> CancelToken): MonoK = Mono.create { sink: MonoSink -> val cb = { either: Either -> either.fold(sink::error, sink::success) @@ -297,7 +297,15 @@ data class MonoK(val mono: Mono) : MonoKOf { sink.onDispose { token.value().subscribe({}, sink::error) } }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) + fun cancelable(fa: ((Either) -> Unit) -> CancelToken): MonoK = + cancellable(fa) + + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> MonoKOf>): MonoK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> MonoKOf>): MonoK = Mono.create { sink: MonoSink -> val cb = { either: Either -> either.fold(sink::error, sink::success) diff --git a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoKConnection.kt b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoKConnection.kt index d91f2cca8..3159ff732 100644 --- a/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoKConnection.kt +++ b/arrow-fx-reactor/src/main/kotlin/arrow/fx/reactor/MonoKConnection.kt @@ -5,9 +5,9 @@ import arrow.fx.KindConnection import arrow.fx.typeclasses.ExitCase import arrow.fx.typeclasses.MonadDefer -@Deprecated("Cancellation should be done with the cancelable combinator") +@Deprecated("Cancellation should be done with the cancellable combinator") typealias MonoKProc = (KindConnection, (Either) -> Unit) -> Unit -@Deprecated("Cancellation should be done with the cancelable combinator") +@Deprecated("Cancellation should be done with the cancellable combinator") typealias MonoKProcF = (KindConnection, (Either) -> Unit) -> MonoKOf /** @@ -22,7 +22,7 @@ typealias MonoKProcF = (KindConnection, (Either) -> U */ @Suppress("UNUSED_PARAMETER", "FunctionName") @Deprecated(message = "Cancelling operations through MonoKConnection will not be supported anymore." + -"In case you need to cancel multiple processes can do so by using cancelable and composing cancel operations using zipWith or other parallel operators") +"In case you need to cancel multiple processes can do so by using cancellable and composing cancel operations using zipWith or other parallel operators") fun MonoKConnection(dummy: Unit = Unit): KindConnection = KindConnection(object : MonadDefer { override fun defer(fa: () -> MonoKOf): MonoK = MonoK.defer(fa) diff --git a/arrow-fx-reactor/src/test/kotlin/arrow/fx/FluxKTest.kt b/arrow-fx-reactor/src/test/kotlin/arrow/fx/FluxKTest.kt index d8ab6c7fa..7363ca741 100644 --- a/arrow-fx-reactor/src/test/kotlin/arrow/fx/FluxKTest.kt +++ b/arrow-fx-reactor/src/test/kotlin/arrow/fx/FluxKTest.kt @@ -149,11 +149,11 @@ class FluxKTest : UnitSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "FluxK should cancel KindConnection on dispose" { - Promise.uncancelable(FluxK.async()).flatMap { latch -> + Promise.uncancellable(FluxK.async()).flatMap { latch -> FluxK { FluxK.async { conn, _ -> conn.push(latch.complete(Unit)) @@ -166,7 +166,7 @@ class FluxKTest : UnitSpec() { } "FluxK async should be cancellable" { - Promise.uncancelable(FluxK.async()) + Promise.uncancellable(FluxK.async()) .flatMap { latch -> FluxK { FluxK.async { _, _ -> } diff --git a/arrow-fx-reactor/src/test/kotlin/arrow/fx/MonoKTest.kt b/arrow-fx-reactor/src/test/kotlin/arrow/fx/MonoKTest.kt index 6e4564331..4961357e2 100644 --- a/arrow-fx-reactor/src/test/kotlin/arrow/fx/MonoKTest.kt +++ b/arrow-fx-reactor/src/test/kotlin/arrow/fx/MonoKTest.kt @@ -153,11 +153,11 @@ class MonoKTest : UnitSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "MonoK should cancel KindConnection on dispose" { - Promise.uncancelable(MonoK.async()).flatMap { latch -> + Promise.uncancellable(MonoK.async()).flatMap { latch -> MonoK { MonoK.async { conn, _ -> conn.push(latch.complete(Unit)) @@ -170,7 +170,7 @@ class MonoKTest : UnitSpec() { } "MonoK async should be cancellable" { - Promise.uncancelable(MonoK.async()) + Promise.uncancellable(MonoK.async()) .flatMap { latch -> MonoK { MonoK.async { _, _ -> } diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/FlowableK.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/FlowableK.kt index 59311ad10..2ce7aa73e 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/FlowableK.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/FlowableK.kt @@ -79,7 +79,7 @@ data class FlowableK(val flowable: Flowable) : FlowableKOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -98,7 +98,7 @@ data class FlowableK(val flowable: Flowable) : FlowableKOf { .value() .concatMap { a -> if (emitter.isCancelled) { - release(a, ExitCase.Canceled).value().subscribe({}, emitter::onError) + release(a, ExitCase.Cancelled).value().subscribe({}, emitter::onError) Flowable.never() } else { Flowable.defer { use(a).value() } @@ -107,7 +107,7 @@ data class FlowableK(val flowable: Flowable) : FlowableKOf { }.doOnComplete { Flowable.defer { release(a, ExitCase.Completed).value() }.subscribe({ emitter.onComplete() }, emitter::onError) }.doOnCancel { - Flowable.defer { release(a, ExitCase.Canceled).value() }.subscribe({}, {}) + Flowable.defer { release(a, ExitCase.Cancelled).value() }.subscribe({}, {}) } } }.subscribe(emitter::onNext, {}, {}) @@ -224,7 +224,11 @@ data class FlowableK(val flowable: Flowable) : FlowableKOf { emitter.setCancellable { dispose.dispose() } }, mode).k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) fun cancelable(fa: ((Either) -> Unit) -> CancelToken, mode: BackpressureStrategy = BackpressureStrategy.BUFFER): FlowableK = + cancellable(fa) + + fun cancellable(fa: ((Either) -> Unit) -> CancelToken, mode: BackpressureStrategy = BackpressureStrategy.BUFFER): FlowableK = Flowable.create({ emitter -> val token = fa { either: Either -> either.fold({ e -> @@ -237,7 +241,11 @@ data class FlowableK(val flowable: Flowable) : FlowableKOf { emitter.setCancellable { token.value().subscribe({}, { e -> emitter.tryOnError(e) }) } }, mode).k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> FlowableKOf>, mode: BackpressureStrategy = BackpressureStrategy.BUFFER): FlowableK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> FlowableKOf>, mode: BackpressureStrategy = BackpressureStrategy.BUFFER): FlowableK = Flowable.create({ emitter: FlowableEmitter -> val cb = { either: Either -> either.fold({ diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/MaybeK.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/MaybeK.kt index 625af0cf9..3aafe9f82 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/MaybeK.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/MaybeK.kt @@ -13,7 +13,7 @@ import arrow.core.nonFatalOrThrow import arrow.fx.internal.Platform import arrow.fx.typeclasses.CancelToken import arrow.fx.typeclasses.ExitCase -import arrow.fx.typeclasses.ExitCase.Canceled +import arrow.fx.typeclasses.ExitCase.Cancelled import arrow.fx.typeclasses.ExitCase.Completed import arrow.fx.typeclasses.ExitCase.Error import io.reactivex.Maybe @@ -86,7 +86,7 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -104,7 +104,7 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { handleErrorWith { t -> Maybe.fromCallable { emitter.onError(t) }.flatMap { Maybe.error(t) }.k() } .flatMap { a -> if (emitter.isDisposed) { - release(a, Canceled).fix().maybe.subscribe({}, emitter::onError) + release(a, Cancelled).fix().maybe.subscribe({}, emitter::onError) Maybe.never().k() } else { MaybeK.defer { use(a) } @@ -115,7 +115,7 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { MaybeK.defer { release(a, Completed) }.fix().value().subscribe({ emitter.onComplete() }, emitter::onError) } .doOnDispose { - MaybeK.defer { release(a, Canceled) }.value().subscribe({}, {}) + MaybeK.defer { release(a, Cancelled) }.value().subscribe({}, {}) } .k() } @@ -240,7 +240,7 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { * * fun main(args: Array) { * //sampleStart - * val result = MaybeK.cancelable { cb: (Either) -> Unit -> + * val result = MaybeK.cancellable { cb: (Either) -> Unit -> * val nw = NetworkApi() * val disposable = nw.async { result -> cb(Right(result)) } * MaybeK { disposable.invoke() } @@ -250,7 +250,7 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { * } * ``` */ - fun cancelable(fa: ((Either) -> Unit) -> CancelToken): MaybeK = + fun cancellable(fa: ((Either) -> Unit) -> CancelToken): MaybeK = Maybe.create { emitter: MaybeEmitter -> val cb = { either: Either -> either.fold({ @@ -271,7 +271,15 @@ data class MaybeK(val maybe: Maybe) : MaybeKOf { emitter.setCancellable { token.value().subscribe({}, { e -> emitter.tryOnError(e) }) } }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) + fun cancelable(fa: ((Either) -> Unit) -> CancelToken): MaybeK = + cancellable(fa) + + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> MaybeKOf>): MaybeK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> MaybeKOf>): MaybeK = Maybe.create { emitter: MaybeEmitter -> val cb = { either: Either -> either.fold({ diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/ObservableK.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/ObservableK.kt index 8bbfa6932..5afc5d986 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/ObservableK.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/ObservableK.kt @@ -78,7 +78,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -96,7 +96,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf handleErrorWith { t -> Observable.fromCallable { emitter.tryOnError(t) }.flatMap { Observable.error(t) }.k() } .concatMap { a -> if (emitter.isDisposed) { - release(a, ExitCase.Canceled).fix().observable.subscribe({}, { e -> emitter.tryOnError(e) }) + release(a, ExitCase.Cancelled).fix().observable.subscribe({}, { e -> emitter.tryOnError(e) }) Observable.never().k() } else { defer { use(a) } @@ -109,7 +109,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf }) } .doOnDispose { - defer { release(a, ExitCase.Canceled) }.value().subscribe({}, {}) + defer { release(a, ExitCase.Cancelled) }.value().subscribe({}, {}) } .k() } @@ -229,7 +229,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf }.k() /** - * Creates a [ObservableK] that'll run a cancelable operation. + * Creates a [ObservableK] that'll run a cancellable operation. * * ```kotlin:ank:playground * import arrow.core.* @@ -245,7 +245,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf * * fun main(args: Array) { * //sampleStart - * val result = ObservableK.cancelable { cb: (Either) -> Unit -> + * val result = ObservableK.cancellable { cb: (Either) -> Unit -> * val nw = NetworkApi() * val disposable = nw.async { result -> cb(Right(result)) } * ObservableK { disposable.invoke() } @@ -255,7 +255,7 @@ data class ObservableK(val observable: Observable) : ObservableKOf * } * ``` */ - fun cancelable(fa: ((Either) -> Unit) -> CancelToken): ObservableK = + fun cancellable(fa: ((Either) -> Unit) -> CancelToken): ObservableK = Observable.create { emitter -> val token = fa { either: Either -> either.fold({ e -> @@ -268,7 +268,15 @@ data class ObservableK(val observable: Observable) : ObservableKOf emitter.setCancellable { token.value().subscribe({}, { e -> emitter.tryOnError(e) }) } }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) + fun cancelable(fa: ((Either) -> Unit) -> CancelToken): ObservableK = + cancellable(fa) + + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> ObservableKOf>): ObservableK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> ObservableKOf>): ObservableK = Observable.create { emitter: ObservableEmitter -> val cb = { either: Either -> either.fold({ diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/SingleK.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/SingleK.kt index 6aa81b1cd..33d28807e 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/SingleK.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/SingleK.kt @@ -10,7 +10,7 @@ import arrow.fx.internal.Platform import arrow.fx.typeclasses.CancelToken import arrow.fx.typeclasses.Disposable import arrow.fx.typeclasses.ExitCase -import arrow.fx.typeclasses.ExitCase.Canceled +import arrow.fx.typeclasses.ExitCase.Cancelled import arrow.fx.typeclasses.ExitCase.Completed import arrow.fx.typeclasses.ExitCase.Error import io.reactivex.Single @@ -83,7 +83,7 @@ data class SingleK(val single: Single) : SingleKOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -101,7 +101,7 @@ data class SingleK(val single: Single) : SingleKOf { handleErrorWith { t -> Single.fromCallable { emitter.onError(t) }.flatMap { Single.error(t) }.k() } .flatMap { a -> if (emitter.isDisposed) { - release(a, Canceled).fix().single.subscribe({}, emitter::onError) + release(a, Cancelled).fix().single.subscribe({}, emitter::onError) Single.never().k() } else { SingleK.defer { use(a) } @@ -111,7 +111,7 @@ data class SingleK(val single: Single) : SingleKOf { }.doAfterSuccess { SingleK.defer { release(a, Completed) }.fix().value().subscribe({ }, emitter::onError) }.doOnDispose { - SingleK.defer { release(a, Canceled) }.value().subscribe({}, {}) + SingleK.defer { release(a, Cancelled) }.value().subscribe({}, {}) } .k() } @@ -202,7 +202,7 @@ data class SingleK(val single: Single) : SingleKOf { }.k() /** - * Creates a [SingleK] that'll run a cancelable operation. + * Creates a [SingleK] that'll run a cancellable operation. * * ```kotlin:ank:playground * import arrow.core.* @@ -218,7 +218,7 @@ data class SingleK(val single: Single) : SingleKOf { * * fun main(args: Array) { * //sampleStart - * val result = SingleK.cancelable { cb: (Either) -> Unit -> + * val result = SingleK.cancellable { cb: (Either) -> Unit -> * val nw = NetworkApi() * val disposable = nw.async { result -> cb(Right(result)) } * SingleK { disposable.invoke() } @@ -228,7 +228,7 @@ data class SingleK(val single: Single) : SingleKOf { * } * ``` */ - fun cancelable(fa: ((Either) -> Unit) -> CancelToken): SingleK = + fun cancellable(fa: ((Either) -> Unit) -> CancelToken): SingleK = Single.create { emitter: SingleEmitter -> val cb = { either: Either -> either.fold({ @@ -248,7 +248,15 @@ data class SingleK(val single: Single) : SingleKOf { emitter.setCancellable { token.value().subscribe({}, { e -> emitter.tryOnError(e) }) } }.k() + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(fa)")) + fun cancelable(fa: ((Either) -> Unit) -> CancelToken): SingleK = + cancellable(fa) + + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(fa)")) fun cancelableF(fa: ((Either) -> Unit) -> SingleKOf>): SingleK = + cancellableF(fa) + + fun cancellableF(fa: ((Either) -> Unit) -> SingleKOf>): SingleK = Single.create { emitter: SingleEmitter -> val cb = { either: Either -> either.fold({ diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/flowablek.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/flowablek.kt index e27d9d6e2..75ae38226 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/flowablek.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/flowablek.kt @@ -205,11 +205,11 @@ interface FlowableKConcurrent : Concurrent, FlowableKAsync { f(a, tuple.a, tuple.b) }).subscribeOn(asScheduler())) - override fun cancelable(k: ((Either) -> Unit) -> CancelToken): FlowableK = - FlowableK.cancelable(k, BS()) + override fun cancellable(k: ((Either) -> Unit) -> CancelToken): FlowableK = + FlowableK.cancellable(k, BS()) - override fun cancelableF(k: ((Either) -> Unit) -> FlowableKOf>): FlowableK = - FlowableK.cancelableF(k, BS()) + override fun cancellableF(k: ((Either) -> Unit) -> FlowableKOf>): FlowableK = + FlowableK.cancellableF(k, BS()) override fun CoroutineContext.racePair(fa: FlowableKOf, fb: FlowableKOf): FlowableK> = asScheduler().let { scheduler -> diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/maybek.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/maybek.kt index f74d62304..8f20015b8 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/maybek.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/maybek.kt @@ -13,7 +13,6 @@ import arrow.fx.rx2.ForMaybeK import arrow.fx.rx2.MaybeK import arrow.fx.rx2.MaybeKOf import arrow.fx.rx2.asScheduler -import arrow.fx.rx2.extensions.maybek.async.async import arrow.fx.rx2.extensions.maybek.dispatchers.dispatchers import arrow.fx.rx2.fix import arrow.fx.rx2.k @@ -193,11 +192,11 @@ interface MaybeKConcurrent : Concurrent, MaybeKAsync { f(a, tuple.a, tuple.b) }).subscribeOn(asScheduler())) - override fun cancelable(k: ((Either) -> Unit) -> CancelToken): MaybeK = - MaybeK.cancelable(k) + override fun cancellable(k: ((Either) -> Unit) -> CancelToken): MaybeK = + MaybeK.cancellable(k) - override fun cancelableF(k: ((Either) -> Unit) -> MaybeKOf>): MaybeK = - MaybeK.cancelableF(k) + override fun cancellableF(k: ((Either) -> Unit) -> MaybeKOf>): MaybeK = + MaybeK.cancellableF(k) override fun CoroutineContext.racePair(fa: MaybeKOf, fb: MaybeKOf): MaybeK> = asScheduler().let { scheduler -> diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/observablek.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/observablek.kt index e4243d79e..0c9ab8b2c 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/observablek.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/observablek.kt @@ -176,11 +176,11 @@ interface ObservableKConcurrent : Concurrent, ObservableKAsync { f(a, tuple.a, tuple.b) }).subscribeOn(asScheduler())) - override fun cancelable(k: ((Either) -> Unit) -> CancelToken): ObservableKOf = - ObservableK.cancelable(k) + override fun cancellable(k: ((Either) -> Unit) -> CancelToken): ObservableKOf = + ObservableK.cancellable(k) - override fun cancelableF(k: ((Either) -> Unit) -> ObservableKOf>): ObservableK = - ObservableK.cancelableF(k) + override fun cancellableF(k: ((Either) -> Unit) -> ObservableKOf>): ObservableK = + ObservableK.cancellableF(k) override fun CoroutineContext.racePair(fa: ObservableKOf, fb: ObservableKOf): ObservableK> = asScheduler().let { scheduler -> diff --git a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/singlek.kt b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/singlek.kt index 2f5d0d5e1..dfd7699ad 100644 --- a/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/singlek.kt +++ b/arrow-fx-rx2/src/main/kotlin/arrow/fx/rx2/extensions/singlek.kt @@ -11,7 +11,6 @@ import arrow.fx.Timer import arrow.fx.rx2.ForSingleK import arrow.fx.rx2.SingleK import arrow.fx.rx2.SingleKOf -import arrow.fx.rx2.extensions.singlek.async.async import arrow.fx.rx2.fix import arrow.fx.rx2.k import arrow.fx.rx2.value @@ -172,11 +171,11 @@ interface SingleKConcurrent : Concurrent, SingleKAsync { f(a, tuple.a, tuple.b) }).subscribeOn(asScheduler())) - override fun cancelable(k: ((Either) -> Unit) -> CancelToken): SingleK = - SingleK.cancelable(k) + override fun cancellable(k: ((Either) -> Unit) -> CancelToken): SingleK = + SingleK.cancellable(k) - override fun cancelableF(k: ((Either) -> Unit) -> SingleKOf>): SingleK = - SingleK.cancelableF(k) + override fun cancellableF(k: ((Either) -> Unit) -> SingleKOf>): SingleK = + SingleK.cancellableF(k) override fun CoroutineContext.racePair(fa: SingleKOf, fb: SingleKOf): SingleK> = asScheduler().let { scheduler -> diff --git a/arrow-fx-rx2/src/test/kotlin/arrow/fx/FlowableKTests.kt b/arrow-fx-rx2/src/test/kotlin/arrow/fx/FlowableKTests.kt index b5bea124f..05b37030d 100644 --- a/arrow-fx-rx2/src/test/kotlin/arrow/fx/FlowableKTests.kt +++ b/arrow-fx-rx2/src/test/kotlin/arrow/fx/FlowableKTests.kt @@ -148,13 +148,13 @@ class FlowableKTests : RxJavaSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "FlowableK should cancel KindConnection on dispose" { - Promise.uncancelable(FlowableK.async()).flatMap { latch -> + Promise.uncancellable(FlowableK.async()).flatMap { latch -> FlowableK { - FlowableK.cancelable(fa = { + FlowableK.cancellable(fa = { latch.complete(Unit) }).flowable.subscribe().dispose() }.flatMap { latch.get() } @@ -165,7 +165,7 @@ class FlowableKTests : RxJavaSpec() { } "FlowableK async should be cancellable" { - Promise.uncancelable(FlowableK.async()) + Promise.uncancellable(FlowableK.async()) .flatMap { latch -> FlowableK { FlowableK.async(fa = { }) diff --git a/arrow-fx-rx2/src/test/kotlin/arrow/fx/MaybeKTests.kt b/arrow-fx-rx2/src/test/kotlin/arrow/fx/MaybeKTests.kt index 68a278ceb..b9099232a 100644 --- a/arrow-fx-rx2/src/test/kotlin/arrow/fx/MaybeKTests.kt +++ b/arrow-fx-rx2/src/test/kotlin/arrow/fx/MaybeKTests.kt @@ -140,13 +140,13 @@ class MaybeKTests : RxJavaSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "MaybeK should cancel KindConnection on dispose" { - Promise.uncancelable(MaybeK.async()).flatMap { latch -> + Promise.uncancellable(MaybeK.async()).flatMap { latch -> MaybeK { - MaybeK.cancelable { + MaybeK.cancellable { latch.complete(Unit) }.maybe.subscribe().dispose() }.flatMap { latch.get() } @@ -157,7 +157,7 @@ class MaybeKTests : RxJavaSpec() { } "MaybeK async should be cancellable" { - Promise.uncancelable(MaybeK.async()) + Promise.uncancellable(MaybeK.async()) .flatMap { latch -> MaybeK { MaybeK.async { } diff --git a/arrow-fx-rx2/src/test/kotlin/arrow/fx/ObservableKTests.kt b/arrow-fx-rx2/src/test/kotlin/arrow/fx/ObservableKTests.kt index 0d5c1f382..4ffe31065 100644 --- a/arrow-fx-rx2/src/test/kotlin/arrow/fx/ObservableKTests.kt +++ b/arrow-fx-rx2/src/test/kotlin/arrow/fx/ObservableKTests.kt @@ -88,13 +88,13 @@ class ObservableKTests : RxJavaSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "ObservableK should cancel KindConnection on dispose" { - Promise.uncancelable(ObservableK.async()).flatMap { latch -> + Promise.uncancellable(ObservableK.async()).flatMap { latch -> ObservableK { - ObservableK.cancelable { + ObservableK.cancellable { latch.complete(Unit) }.observable.subscribe().dispose() }.flatMap { latch.get() } @@ -105,7 +105,7 @@ class ObservableKTests : RxJavaSpec() { } "ObservableK async should be cancellable" { - Promise.uncancelable(ObservableK.async()) + Promise.uncancellable(ObservableK.async()) .flatMap { latch -> ObservableK { ObservableK.async { } diff --git a/arrow-fx-rx2/src/test/kotlin/arrow/fx/SingleKTests.kt b/arrow-fx-rx2/src/test/kotlin/arrow/fx/SingleKTests.kt index 473c5549e..716925a07 100644 --- a/arrow-fx-rx2/src/test/kotlin/arrow/fx/SingleKTests.kt +++ b/arrow-fx-rx2/src/test/kotlin/arrow/fx/SingleKTests.kt @@ -129,13 +129,13 @@ class SingleKTests : RxJavaSpec() { .dispose() countDownLatch.await(100, TimeUnit.MILLISECONDS) - ec shouldBe ExitCase.Canceled + ec shouldBe ExitCase.Cancelled } "SingleK should cancel KindConnection on dispose" { - Promise.uncancelable(SingleK.async()).flatMap { latch -> + Promise.uncancellable(SingleK.async()).flatMap { latch -> SingleK { - SingleK.cancelable { + SingleK.cancellable { latch.complete(Unit) }.single.subscribe().dispose() }.flatMap { latch.get() } @@ -146,7 +146,7 @@ class SingleKTests : RxJavaSpec() { } "SingleK async should be cancellable" { - Promise.uncancelable(SingleK.async()) + Promise.uncancellable(SingleK.async()) .flatMap { latch -> SingleK { SingleK.async { } diff --git a/arrow-fx-test/src/main/kotlin/arrow/test/laws/AsyncLaws.kt b/arrow-fx-test/src/main/kotlin/arrow/test/laws/AsyncLaws.kt index 224547b80..25b11a669 100644 --- a/arrow-fx-test/src/main/kotlin/arrow/test/laws/AsyncLaws.kt +++ b/arrow-fx-test/src/main/kotlin/arrow/test/laws/AsyncLaws.kt @@ -128,7 +128,7 @@ object AsyncLaws { fun Async.bracketReleaseIscalledOnCompletedOrError(EQ: Eq>) { forAll(Gen.string().applicativeError(this), Gen.int()) { fa, b -> - Promise.uncancelable(this@bracketReleaseIscalledOnCompletedOrError).flatMap { promise -> + Promise.uncancellable(this@bracketReleaseIscalledOnCompletedOrError).flatMap { promise -> val br = later { promise }.bracketCase(use = { fa }, release = { r, exitCase -> when (exitCase) { is ExitCase.Completed -> r.complete(b) diff --git a/arrow-fx-test/src/main/kotlin/arrow/test/laws/BracketLaws.kt b/arrow-fx-test/src/main/kotlin/arrow/test/laws/BracketLaws.kt index 9aaf07908..c0ad18ed4 100644 --- a/arrow-fx-test/src/main/kotlin/arrow/test/laws/BracketLaws.kt +++ b/arrow-fx-test/src/main/kotlin/arrow/test/laws/BracketLaws.kt @@ -30,10 +30,10 @@ object BracketLaws { return listOf( Law("Bracket: bracketCase with just Unit is eqv to Map") { BF.bracketCaseWithJustUnitEqvMap(EQ) }, - Law("Bracket: bracketCase with just Unit is uncancelable") { BF.bracketCaseWithJustUnitIsUncancelable(EQ) }, + Law("Bracket: bracketCase with just Unit is uncancellable") { BF.bracketCaseWithJustUnitIsUncancellable(EQ) }, Law("Bracket: bracketCase failure in acquisition remains failure") { BF.bracketCaseFailureInAcquisitionRemainsFailure(EQ) }, - Law("Bracket: uncancelable prevents Canceled case") { BF.uncancelablePreventsCanceledCase(BF.just(Unit), BF.just(Unit), EQ) }, - Law("Bracket: acquire and release are uncancelable") { BF.acquireAndReleaseAreUncancelable({ BF.just(Unit) }, EQ) }, + Law("Bracket: uncancellable prevents Cancelled case") { BF.uncancellablePreventsCancelledCase(BF.just(Unit), BF.just(Unit), EQ) }, + Law("Bracket: acquire and release are uncancellable") { BF.acquireAndReleaseAreUncancellable({ BF.just(Unit) }, EQ) }, Law("Bracket: bracket propagates transformer effects") { BF.bracketPropagatesTransformerEffects(EQ) }, Law("Bracket: bracket must run release task on use error") { BF.bracketMustRunReleaseTaskOnUseError(EQ) }, Law("Bracket: bracket must not run release task on acquire error") { BF.bracketMustNotRunReleaseTaskOnAcquireError(EQ) }, @@ -80,11 +80,11 @@ object BracketLaws { fa.bracketCase(release = { _, _ -> just(Unit) }, use = { a -> just(f(a)) }).equalUnderTheLaw(fa.map(f), EQ) } - fun Bracket.bracketCaseWithJustUnitIsUncancelable( + fun Bracket.bracketCaseWithJustUnitIsUncancellable( EQ: Eq> ): Unit = forAll(Gen.int().applicativeError(this)) { fa: Kind -> - fa.bracketCase(release = { _, _ -> just(Unit) }, use = { just(it) }).equalUnderTheLaw(fa.uncancelable().flatMap { just(it) }, EQ) + fa.bracketCase(release = { _, _ -> just(Unit) }, use = { just(it) }).equalUnderTheLaw(fa.uncancellable().flatMap { just(it) }, EQ) } fun Bracket.bracketCaseFailureInAcquisitionRemainsFailure( @@ -101,23 +101,23 @@ object BracketLaws { fa.bracket(release = { just(Unit) }, use = { just(it) }).equalUnderTheLaw(fa.bracketCase(release = { _, _ -> just(Unit) }, use = { just(it) }), EQ) } - fun Bracket.uncancelablePreventsCanceledCase( + fun Bracket.uncancellablePreventsCancelledCase( onCancel: Kind, onFinish: Kind, EQ: Eq> ): Unit = forAll(Gen.int().applicativeError(this)) { fa: Kind -> just(Unit).bracketCase(use = { fa }, release = { _, b -> - if (b == ExitCase.Canceled) onCancel else onFinish - }).uncancelable().equalUnderTheLaw(fa.guarantee(onFinish), EQ) + if (b == ExitCase.Cancelled) onCancel else onFinish + }).uncancellable().equalUnderTheLaw(fa.guarantee(onFinish), EQ) } - fun Bracket.acquireAndReleaseAreUncancelable( + fun Bracket.acquireAndReleaseAreUncancellable( release: (Int) -> Kind, EQ: Eq> ): Unit = forAll(Gen.int().applicativeError(this)) { fa: Kind -> - fa.uncancelable().bracket({ a -> release(a).uncancelable() }) { just(it) }.equalUnderTheLaw(fa.bracket(release) { just(it) }, EQ) + fa.uncancellable().bracket({ a -> release(a).uncancellable() }) { just(it) }.equalUnderTheLaw(fa.bracket(release) { just(it) }, EQ) } fun Bracket.guaranteeIsDerivedFromBracket( diff --git a/arrow-fx-test/src/main/kotlin/arrow/test/laws/ConcurrentLaws.kt b/arrow-fx-test/src/main/kotlin/arrow/test/laws/ConcurrentLaws.kt index 671ced570..0828ad7f6 100644 --- a/arrow-fx-test/src/main/kotlin/arrow/test/laws/ConcurrentLaws.kt +++ b/arrow-fx-test/src/main/kotlin/arrow/test/laws/ConcurrentLaws.kt @@ -53,20 +53,20 @@ object ConcurrentLaws { return listOf( Law("Concurrent Laws: cancel on bracket releases") { CF.cancelOnBracketReleases(EQ, ctx) }, - Law("Concurrent Laws: acquire is not cancelable") { CF.acquireBracketIsNotCancelable(EQ, ctx) }, - Law("Concurrent Laws: release is not cancelable") { CF.releaseBracketIsNotCancelable(EQ, ctx) }, + Law("Concurrent Laws: acquire is not cancellable") { CF.acquireBracketIsNotCancellable(EQ, ctx) }, + Law("Concurrent Laws: release is not cancellable") { CF.releaseBracketIsNotCancellable(EQ, ctx) }, Law("Concurrent Laws: cancel on guarantee runs finalizer") { CF.guaranteeFinalizerOnCancel(EQ, ctx) }, - Law("Concurrent Laws: release is not cancelable") { CF.guaranteeFinalizerIsNotCancelable(EQ, ctx) }, + Law("Concurrent Laws: release is not cancellable") { CF.guaranteeFinalizerIsNotCancellable(EQ, ctx) }, Law("Concurrent Laws: cancel on onCancel runs finalizer") { CF.onCancelFinalizerOnCancel(EQ, ctx) }, - Law("Concurrent Laws: async cancelable coherence") { CF.asyncCancelableCoherence(EQ) }, - Law("Concurrent Laws: cancelable cancelableF coherence") { CF.cancelableCancelableFCoherence(EQ) }, - Law("Concurrent Laws: cancelable should run CancelToken on cancel") { CF.cancelableReceivesCancelSignal(EQ, ctx) }, - Law("Concurrent Laws: cancelableF should run CancelToken on cancel") { CF.cancelableFReceivesCancelSignal(EQ, ctx) }, + Law("Concurrent Laws: async cancellable coherence") { CF.asyncCancellableCoherence(EQ) }, + Law("Concurrent Laws: cancellable cancellableF coherence") { CF.cancellableCancellableFCoherence(EQ) }, + Law("Concurrent Laws: cancellable should run CancelToken on cancel") { CF.cancellableReceivesCancelSignal(EQ, ctx) }, + Law("Concurrent Laws: cancellableF should run CancelToken on cancel") { CF.cancellableFReceivesCancelSignal(EQ, ctx) }, Law("Concurrent Laws: asyncF register can be cancelled") { CF.asyncFRegisterCanBeCancelled(EQ, ctx) }, Law("Concurrent Laws: start join is identity") { CF.startJoinIsIdentity(EQ, ctx) }, Law("Concurrent Laws: join is idempotent") { CF.joinIsIdempotent(EQ, ctx) }, Law("Concurrent Laws: start cancel is unit") { CF.startCancelIsUnit(EQ_UNIT, ctx) }, - Law("Concurrent Laws: uncancelable mirrors source") { CF.uncancelableMirrorsSource(EQ) }, + Law("Concurrent Laws: uncancellable mirrors source") { CF.uncancellableMirrorsSource(EQ) }, Law("Concurrent Laws: race pair mirrors left winner") { CF.racePairMirrorsLeftWinner(EQ, ctx) }, Law("Concurrent Laws: race pair mirrors right winner") { CF.racePairMirrorsRightWinner(EQ, ctx) }, Law("Concurrent Laws: race pair can cancel loser") { CF.racePairCanCancelsLoser(EQ, ctx) }, @@ -163,7 +163,7 @@ object ConcurrentLaws { use = { a -> startLatch.complete(Unit).flatMap { never() } }, release = { r, exitCase -> when (exitCase) { - is ExitCase.Canceled -> exitLatch.complete(r) // Fulfil promise that `release` was executed with Canceled + is ExitCase.Cancelled -> exitLatch.complete(r) // Fulfil promise that `release` was executed with Cancelled else -> unit() } } @@ -178,12 +178,12 @@ object ConcurrentLaws { } } - fun Concurrent.acquireBracketIsNotCancelable(EQ: Eq>, ctx: CoroutineContext) = + fun Concurrent.acquireBracketIsNotCancellable(EQ: Eq>, ctx: CoroutineContext) = forAll(Gen.int(), Gen.int()) { a, b -> fx.concurrent { - val mvar = MVar(a, this@acquireBracketIsNotCancelable).bind() + val mvar = MVar(a, this@acquireBracketIsNotCancellable).bind() mvar.take().bind() - val p = Promise.uncancelable(this@acquireBracketIsNotCancelable).bind() + val p = Promise.uncancellable(this@acquireBracketIsNotCancellable).bind() val task = p.complete(Unit).flatMap { mvar.put(b) } .bracket(use = { never() }, release = { unit() }) val (_, cancel) = task.fork(ctx).bind() @@ -194,11 +194,11 @@ object ConcurrentLaws { }.equalUnderTheLaw(just(b), EQ) } - fun Concurrent.releaseBracketIsNotCancelable(EQ: Eq>, ctx: CoroutineContext) = + fun Concurrent.releaseBracketIsNotCancellable(EQ: Eq>, ctx: CoroutineContext) = forAll(Gen.int(), Gen.int()) { a, b -> fx.concurrent { - val mvar = MVar(a, this@releaseBracketIsNotCancelable).bind() - val p = Promise.uncancelable(this@releaseBracketIsNotCancelable).bind() + val mvar = MVar(a, this@releaseBracketIsNotCancellable).bind() + val p = Promise.uncancellable(this@releaseBracketIsNotCancellable).bind() val task = p.complete(Unit) .bracket(use = { never() }, release = { mvar.put(b) }) val (_, cancel) = task.fork(ctx).bind() @@ -219,7 +219,7 @@ object ConcurrentLaws { val (_, cancel) = startLatch.complete(Unit).flatMap { never() } .guaranteeCase { exitCase -> when (exitCase) { - is ExitCase.Canceled -> exitLatch.complete(i) // Fulfil promise that `release` was executed with Canceled + is ExitCase.Cancelled -> exitLatch.complete(i) // Fulfil promise that `release` was executed with Cancelled else -> unit() } }.fork(ctx).bind() // Fork execution, allowing us to cancel it later @@ -238,7 +238,7 @@ object ConcurrentLaws { val exitLatch = Promise(this@onCancelFinalizerOnCancel).bind() // A promise that `release` was executed val (_, cancel) = startLatch.complete(Unit).flatMap { never() } - .onCancel(exitLatch.complete(i)) // Fulfil promise that `release` was executed with Canceled + .onCancel(exitLatch.complete(i)) // Fulfil promise that `release` was executed with Cancelled .fork(ctx).bind() // Fork execution, allowing us to cancel it later startLatch.get().bind() // Waits on promise of `use` @@ -248,11 +248,11 @@ object ConcurrentLaws { }.equalUnderTheLaw(just(i), EQ) } - fun Concurrent.guaranteeFinalizerIsNotCancelable(EQ: Eq>, ctx: CoroutineContext) = + fun Concurrent.guaranteeFinalizerIsNotCancellable(EQ: Eq>, ctx: CoroutineContext) = forAll(Gen.int(), Gen.int()) { a, b -> fx.concurrent { - val mvar = MVar(a, this@guaranteeFinalizerIsNotCancelable).bind() - val p = Promise.uncancelable(this@guaranteeFinalizerIsNotCancelable).bind() + val mvar = MVar(a, this@guaranteeFinalizerIsNotCancellable).bind() + val p = Promise.uncancellable(this@guaranteeFinalizerIsNotCancellable).bind() val task = p.complete(Unit).followedBy(never()).guaranteeCase { mvar.put(b) } val (_, cancel) = task.fork(ctx).bind() p.get().bind() @@ -263,26 +263,26 @@ object ConcurrentLaws { }.equalUnderTheLaw(just(b), EQ) } - fun Concurrent.asyncCancelableCoherence(EQ: Eq>): Unit = + fun Concurrent.asyncCancellableCoherence(EQ: Eq>): Unit = forAll(Gen.either(Gen.throwable(), Gen.int())) { eith -> async { cb -> cb(eith) } - .equalUnderTheLaw(cancelable { cb -> cb(eith); just(Unit) }, EQ) + .equalUnderTheLaw(cancellable { cb -> cb(eith); just(Unit) }, EQ) } - fun Concurrent.cancelableCancelableFCoherence(EQ: Eq>): Unit = + fun Concurrent.cancellableCancellableFCoherence(EQ: Eq>): Unit = forAll(Gen.either(Gen.throwable(), Gen.int())) { eith -> - cancelable { cb -> cb(eith); just(Unit) } - .equalUnderTheLaw(cancelableF { cb -> later { cb(eith); just(Unit) } }, EQ) + cancellable { cb -> cb(eith); just(Unit) } + .equalUnderTheLaw(cancellableF { cb -> later { cb(eith); just(Unit) } }, EQ) } - fun Concurrent.cancelableReceivesCancelSignal(EQ: Eq>, ctx: CoroutineContext) = + fun Concurrent.cancellableReceivesCancelSignal(EQ: Eq>, ctx: CoroutineContext) = forAll(Gen.int()) { i -> fx.concurrent { - val release = Promise.uncancelable(this@cancelableReceivesCancelSignal).bind() + val release = Promise.uncancellable(this@cancellableReceivesCancelSignal).bind() val cancelToken: CancelToken = release.complete(i) val latch = CountDownLatch(1) - val (_, cancel) = cancelable { + val (_, cancel) = cancellable { latch.countDown() cancelToken }.fork(ctx).bind() @@ -297,12 +297,12 @@ object ConcurrentLaws { }.equalUnderTheLaw(just(i), EQ) } - fun Concurrent.cancelableFReceivesCancelSignal(EQ: Eq>, ctx: CoroutineContext) = + fun Concurrent.cancellableFReceivesCancelSignal(EQ: Eq>, ctx: CoroutineContext) = forAll(Gen.int()) { i -> fx.concurrent { - val release = Promise(this@cancelableFReceivesCancelSignal).bind() - val latch = Promise(this@cancelableFReceivesCancelSignal).bind() - val async = cancelableF { + val release = Promise(this@cancellableFReceivesCancelSignal).bind() + val latch = Promise(this@cancellableFReceivesCancelSignal).bind() + val async = cancellableF { latch.complete(Unit) .map { release.complete(i) } } @@ -348,9 +348,9 @@ object ConcurrentLaws { .equalUnderTheLaw(just(Unit), EQ_UNIT) } - fun Concurrent.uncancelableMirrorsSource(EQ: Eq>): Unit = + fun Concurrent.uncancellableMirrorsSource(EQ: Eq>): Unit = forAll(Gen.int()) { i -> - just(i).uncancelable().equalUnderTheLaw(just(i), EQ) + just(i).uncancellable().equalUnderTheLaw(just(i), EQ) } fun Concurrent.raceMirrorsLeftWinner(EQ: Eq>, ctx: CoroutineContext): Unit = @@ -371,7 +371,7 @@ object ConcurrentLaws { forAll(Gen.either(Gen.throwable(), Gen.string()), Gen.bool(), Gen.int()) { eith, leftWins, i -> fx.concurrent { val s = Semaphore(0L, this@raceCancelsLoser).bind() - val promise = Promise.uncancelable(this@raceCancelsLoser).bind() + val promise = Promise.uncancellable(this@raceCancelsLoser).bind() val winner = s.acquire().flatMap { async { cb -> cb(eith) } } val loser = s.release().bracket(use = { never() }, release = { promise.complete(i) }) val race = @@ -426,7 +426,7 @@ object ConcurrentLaws { forAll(Gen.either(Gen.throwable(), Gen.string()), Gen.bool(), Gen.int()) { eith, leftWinner, i -> val received = fx.concurrent { val s = Semaphore(0L, this@racePairCanCancelsLoser).bind() - val p = Promise.uncancelable(this@racePairCanCancelsLoser).bind() + val p = Promise.uncancellable(this@racePairCanCancelsLoser).bind() val winner = s.acquire().flatMap { async { cb -> cb(eith) } } val loser = s.release().bracket(use = { never() }, release = { p.complete(i) }) val race = if (leftWinner) ctx.racePair(winner, loser) @@ -530,8 +530,8 @@ object ConcurrentLaws { forAll(Gen.either(Gen.throwable(), Gen.string()), Gen.from(listOf(1, 2, 3)), Gen.int(), Gen.int()) { eith, leftWinner, a, b -> val received = fx.concurrent { val s = Semaphore(0L, this@raceTripleCanCancelsLoser).bind() - val pa = Promise.uncancelable(this@raceTripleCanCancelsLoser).bind() - val pb = Promise.uncancelable(this@raceTripleCanCancelsLoser).bind() + val pa = Promise.uncancellable(this@raceTripleCanCancelsLoser).bind() + val pb = Promise.uncancellable(this@raceTripleCanCancelsLoser).bind() val winner = s.acquireN(2).flatMap { async { cb -> cb(eith) } } val loser = s.release().bracket(use = { never() }, release = { pa.complete(a) }) diff --git a/arrow-fx/src/main/kotlin/arrow/fx/IO.kt b/arrow-fx/src/main/kotlin/arrow/fx/IO.kt index bcce78193..e1ab39ab8 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/IO.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/IO.kt @@ -13,7 +13,7 @@ import arrow.core.right import arrow.fx.OnCancel.Companion.CancellationException import arrow.fx.OnCancel.Silent import arrow.fx.OnCancel.ThrowCancellationException -import arrow.fx.internal.ForwardCancelable +import arrow.fx.internal.ForwardCancellable import arrow.fx.internal.IOBracket import arrow.fx.internal.IOFiber import arrow.fx.internal.IOForkedStart @@ -153,7 +153,7 @@ sealed class IO : IOOf { * ``` **/ fun sleep(duration: Duration, continueOn: CoroutineContext = IODispatchers.CommonPool): IO = - cancelable { cb -> + cancellable { cb -> val cancelRef = scheduler.schedule(ShiftTick(continueOn, cb), duration.amount, duration.timeUnit) later { cancelRef.cancel(false); Unit } } @@ -232,7 +232,7 @@ sealed class IO : IOOf { * ``` * * @param k an asynchronous computation that might fail typed as [IOProc]. - * @see cancelable for an operator that supports cancellation. + * @see cancellable for an operator that supports cancellation. * @see asyncF for a version that can suspend side effects in the registration function. */ fun async(k: IOProc): IO = @@ -286,7 +286,7 @@ sealed class IO : IOOf { * * @param k a deferred asynchronous computation that might fail typed as [IOProcF]. * @see async for a version that can suspend side effects in the registration function. - * @see cancelableF for an operator that supports cancellation. + * @see cancellableF for an operator that supports cancellation. */ fun asyncF(k: IOProcF): IO = Async { conn: IOConnection, ff: (Either) -> Unit -> @@ -303,14 +303,14 @@ sealed class IO : IOOf { } } - IORunLoop.startCancelable(fa, conn2) { result -> + IORunLoop.startCancellable(fa, conn2) { result -> result.fold({ e -> callback(Left(e)) }, mapUnit) } } } /** - * Creates a cancelable instance of [IO] that executes an asynchronous process on evaluation. + * Creates a cancellable instance of [IO] that executes an asynchronous process on evaluation. * This combinator can be used to wrap callbacks or other similar impure code that requires cancellation code. * * ```kotlin:ank:playground @@ -338,7 +338,7 @@ sealed class IO : IOOf { * fun main(args: Array) { * //sampleStart * fun getUsernames(): IO> = - * IO.cancelable { cb: (Either>) -> Unit -> + * IO.cancellable { cb: (Either>) -> Unit -> * val id = GithubService.getUsernames { names, throwable -> * when { * names != null -> cb(Right(names)) @@ -359,13 +359,13 @@ sealed class IO : IOOf { * @param cb an asynchronous computation that might fail. * @see async for wrapping impure APIs without cancellation */ - fun cancelable(cb: ((Either) -> Unit) -> CancelToken): IO = + fun cancellable(cb: ((Either) -> Unit) -> CancelToken): IO = Async { conn: IOConnection, cbb: (Either) -> Unit -> onceOnly(conn, cbb).let { cbb2 -> - val cancelable = ForwardCancelable() - conn.push(cancelable.cancel()) - if (conn.isNotCanceled()) { - cancelable.complete(try { + val cancellable = ForwardCancellable() + conn.push(cancellable.cancel()) + if (conn.isNotCancelled()) { + cancellable.complete(try { cb(cbb2) } catch (throwable: Throwable) { cbb2(Left(throwable.nonFatalOrThrow())) @@ -375,8 +375,12 @@ sealed class IO : IOOf { } } + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(cb)")) + fun cancelable(cb: ((Either) -> Unit) -> CancelToken): IO = + cancellable(cb) + /** - * Creates a cancelable instance of [IO] that executes an asynchronous process on evaluation. + * Creates a cancellable instance of [IO] that executes an asynchronous process on evaluation. * This combinator can be used to wrap callbacks or other similar impure code that requires cancellation code. * * ```kotlin:ank:playground @@ -404,7 +408,7 @@ sealed class IO : IOOf { * fun main(args: Array) { * //sampleStart * fun getUsernames(): IO> = - * IO.cancelableF { cb: (Either>) -> Unit -> + * IO.cancellableF { cb: (Either>) -> Unit -> * IO { * val id = GithubService.getUsernames { names, throwable -> * when { @@ -427,11 +431,11 @@ sealed class IO : IOOf { * @param cb a deferred asynchronous computation that might fail. * @see asyncF for wrapping impure APIs without cancellation */ - fun cancelableF(cb: ((Either) -> Unit) -> IOOf>): IO = + fun cancellableF(cb: ((Either) -> Unit) -> IOOf>): IO = Async { conn: IOConnection, cbb: (Either) -> Unit -> - val cancelable = ForwardCancelable() + val cancellable = ForwardCancellable() val conn2 = IOConnection() - conn.push(cancelable.cancel()) + conn.push(cancellable.cancel()) conn.push(conn2.cancel()) onceOnly(conn, cbb).let { cbb2 -> @@ -442,13 +446,17 @@ sealed class IO : IOOf { just(unit) } - IORunLoop.startCancelable(fa, conn2) { result -> + IORunLoop.startCancellable(fa, conn2) { result -> conn.pop() - result.fold({ }, cancelable::complete) + result.fold({ }, cancellable::complete) } } } + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellableF(cb)")) + fun cancelableF(cb: ((Either) -> Unit) -> IOOf>): IO = + cancellableF(cb) + /** * A pure [IO] value of [Unit]. * @@ -567,9 +575,9 @@ sealed class IO : IOOf { * ``` */ suspend fun suspended(): A = suspendCoroutine { cont -> - val connection = cont.context[IOContext]?.connection ?: IOConnection.uncancelable + val connection = cont.context[IOContext]?.connection ?: IOConnection.uncancellable - IORunLoop.startCancelable(this, connection) { + IORunLoop.startCancellable(this, connection) { it.fold(cont::resumeWithException, cont::resume) } } @@ -688,7 +696,7 @@ sealed class IO : IOOf { val promise = UnsafePromise() // A new IOConnection, because its cancellation is now decoupled from our current one. val conn = IOConnection() - IORunLoop.startCancelable(IOForkedStart(this, ctx), conn, promise::complete) + IORunLoop.startCancellable(IOForkedStart(this, ctx), conn, promise::complete) cb(Either.Right(IOFiber(promise, conn))) } @@ -793,7 +801,7 @@ sealed class IO : IOOf { IORunLoop.start(this, cb) /** - * A pure version of [unsafeRunAsyncCancellable], it defines how an [IO] is ran in a cancelable manner but it doesn't run yet. + * A pure version of [unsafeRunAsyncCancellable], it defines how an [IO] is ran in a cancellable manner but it doesn't run yet. * * It receives the values in a callback [cb] and thus **has** the ability to run `NonBlocking` but that depends on the implementation. * When the underlying effects/program runs blocking on the callers thread this method will run blocking. @@ -811,14 +819,14 @@ sealed class IO : IOOf { ThrowCancellationException -> cb andThen { it.fix().unsafeRunAsync { } } Silent -> - { either -> either.fold({ if (!conn.isCanceled() || it != CancellationException) cb(either) }, { cb(either); Unit }) } + { either -> either.fold({ if (!conn.isCancelled() || it != CancellationException) cb(either) }, { cb(either); Unit }) } } ccb(conn.toDisposable().right()) - IORunLoop.startCancelable(this, conn, onCancelCb) + IORunLoop.startCancellable(this, conn, onCancelCb) } /** - * [unsafeRunAsyncCancellable] allows you to run any [IO] and receive the values in a callback [cb] while being cancelable. + * [unsafeRunAsyncCancellable] allows you to run any [IO] and receive the values in a callback [cb] while being cancellable. * It **has** the ability to run `NonBlocking` but that depends on the implementation, when the underlying * effects/program runs blocking on the callers thread this method will run blocking. * @@ -860,9 +868,13 @@ sealed class IO : IOOf { internal abstract fun unsafeRunTimedTotal(limit: Duration): Option - /** Makes the source [IO] uncancelable such that a [Fiber.cancel] signal has no effect. */ + /** Makes the source [IO] uncancellable such that a [Fiber.cancel] signal has no effect. */ + fun uncancellable(): IO = + ContextSwitch(this, ContextSwitch.makeUncancellable, ContextSwitch.disableUncancellable) + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellable()")) fun uncancelable(): IO = - ContextSwitch(this, ContextSwitch.makeUncancelable, ContextSwitch.disableUncancelable) + uncancellable() /** * Meant for specifying tasks with safe resource acquisition and release in the face of errors and interruption. @@ -905,16 +917,16 @@ sealed class IO : IOOf { * 2. consumption * 3. releasing * - * 1. Resource acquisition is **NON CANCELABLE**. + * 1. Resource acquisition is **NON CANCELLABLE**. * If resource acquisition fails, meaning no resource was actually successfully acquired then we short-circuit the effect. * Reason being, we cannot [release] what we did not `acquire` first. Same reason we cannot call [use]. * If it is successful we pass the result to stage 2 [use]. * * 2. Resource consumption is like any other [IO] effect. The key difference here is that it's wired in such a way that - * [release] **will always** be called either on [ExitCase.Canceled], [ExitCase.Error] or [ExitCase.Completed]. + * [release] **will always** be called either on [ExitCase.Cancelled], [ExitCase.Error] or [ExitCase.Completed]. * If it failed than the resulting [IO] from [bracketCase] will be `IO.raiseError(e)`, otherwise the result of [use]. * - * 3. Resource releasing is **NON CANCELABLE**, otherwise it could result in leaks. + * 3. Resource releasing is **NON CANCELLABLE**, otherwise it could result in leaks. * In the case it throws the resulting [IO] will be either the error or a composed error if one occurred in the [use] stage. * * @param use is the action to consume the resource and produce an [IO] with the result. @@ -943,7 +955,7 @@ sealed class IO : IOOf { * release = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -959,7 +971,7 @@ sealed class IO : IOOf { IOBracket(this, release, use) /** - * Executes the given [finalizer] when the source is finished, either in success or in error, or if canceled. + * Executes the given [finalizer] when the source is finished, either in success or in error, or if cancelled. * * As best practice, prefer [bracket] for the acquisition and release of resources. * @@ -969,7 +981,7 @@ sealed class IO : IOOf { fun guarantee(finalizer: IOOf): IO = guaranteeCase { finalizer } /** - * Executes the given `finalizer` when the source is finished, either in success or in error, or if canceled, allowing + * Executes the given `finalizer` when the source is finished, either in success or in error, or if cancelled, allowing * for differentiating between exit conditions. That's thanks to the [ExitCase] argument of the finalizer. * * As best practice, it's not a good idea to release resources via `guaranteeCase` in polymorphic code. @@ -1038,9 +1050,9 @@ sealed class IO : IOOf { companion object { // Internal reusable reference. - internal val makeUncancelable: (IOConnection) -> IOConnection = { KindConnection.uncancelable } + internal val makeUncancellable: (IOConnection) -> IOConnection = { KindConnection.uncancellable } - internal val disableUncancelable: (Any?, Throwable?, IOConnection, IOConnection) -> IOConnection = + internal val disableUncancellable: (Any?, Throwable?, IOConnection, IOConnection) -> IOConnection = { _, _, old, _ -> old } } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/IOConnection.kt b/arrow-fx/src/main/kotlin/arrow/fx/IOConnection.kt index 754433719..01ebdd37c 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/IOConnection.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/IOConnection.kt @@ -18,9 +18,9 @@ internal class IOContext(val connection: IOConnection) : AbstractCoroutineContex @Suppress("UNUSED_PARAMETER", "FunctionName") fun IOConnection(dummy: Unit = Unit): IOConnection = KindConnection(MD) { it.fix().unsafeRunAsync { } } -private val _uncancelable = KindConnection.uncancelable(MD) -internal inline val KindConnection.Companion.uncancelable: IOConnection - inline get() = _uncancelable +private val _uncancellable = KindConnection.uncancellable(MD) +internal inline val KindConnection.Companion.uncancellable: IOConnection + inline get() = _uncancellable private object MD : MonadDefer { override fun defer(fa: () -> IOOf): IO = diff --git a/arrow-fx/src/main/kotlin/arrow/fx/IOParMap.kt b/arrow-fx/src/main/kotlin/arrow/fx/IOParMap.kt index 6cafc9d24..16f34e3ac 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/IOParMap.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/IOParMap.kt @@ -86,7 +86,7 @@ interface IOParMap { } } - IORunLoop.startCancelable(IOForkedStart(fa, ctx), connA) { resultA -> + IORunLoop.startCancellable(IOForkedStart(fa, ctx), connA) { resultA -> resultA.fold({ e -> sendError(connB, e) }, { a -> @@ -99,7 +99,7 @@ interface IOParMap { }) } - IORunLoop.startCancelable(IOForkedStart(fb, ctx), connB) { resultB -> + IORunLoop.startCancellable(IOForkedStart(fb, ctx), connB) { resultB -> resultB.fold({ e -> sendError(connA, e) }, { b -> @@ -122,7 +122,7 @@ interface IOParMap { val connB = IOConnection() val connC = IOConnection() - // Composite cancelable that cancels all ops. + // Composite cancellable that cancels all ops. // NOTE: conn.pop() called when cb gets called below in complete. conn.push(connA.cancel(), connB.cancel(), connC.cancel()) @@ -153,7 +153,7 @@ interface IOParMap { } } else Unit - IORunLoop.startCancelable(IOForkedStart(fa, ctx), connA) { resultA -> + IORunLoop.startCancellable(IOForkedStart(fa, ctx), connA) { resultA -> resultA.fold({ e -> sendError(connB, connC, e) }, { a -> @@ -165,7 +165,7 @@ interface IOParMap { }) } - IORunLoop.startCancelable(IOForkedStart(fb, ctx), connB) { resultB -> + IORunLoop.startCancellable(IOForkedStart(fb, ctx), connB) { resultB -> resultB.fold({ e -> sendError(connA, connC, e) }, { b -> @@ -177,7 +177,7 @@ interface IOParMap { }) } - IORunLoop.startCancelable(IOForkedStart(fc, ctx), connC) { resultC -> + IORunLoop.startCancellable(IOForkedStart(fc, ctx), connC) { resultC -> resultC.fold({ e -> sendError(connA, connB, e) }, { c -> diff --git a/arrow-fx/src/main/kotlin/arrow/fx/IORace.kt b/arrow-fx/src/main/kotlin/arrow/fx/IORace.kt index 9c1c32a19..8da5400ca 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/IORace.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/IORace.kt @@ -50,7 +50,7 @@ interface IORace { * * fun main(args: Array) { * fun Concurrent.example(): Kind { - * val never: Kind = cancelable { effect { println("Never got canelled for losing.") } } + * val never: Kind = cancellable { effect { println("Never got cancelled for losing.") } } * * //sampleStart * val result = fx.concurrent { @@ -271,7 +271,7 @@ interface IORace { val connB = IOConnection() conn.pushPair(connA, connB) - IORunLoop.startCancelable(IOForkedStart(ioA, ctx), connA) { result -> + IORunLoop.startCancellable(IOForkedStart(ioA, ctx), connA) { result -> result.fold({ onError(active, cb, conn, connB, it) }, { @@ -279,7 +279,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioB, ctx), connB) { result -> + IORunLoop.startCancellable(IOForkedStart(ioB, ctx), connB) { result -> result.fold({ onError(active, cb, conn, connA, it) }, { @@ -346,7 +346,7 @@ interface IORace { val connC = IOConnection() conn.push(connA.cancel(), connB.cancel(), connC.cancel()) - IORunLoop.startCancelable(IOForkedStart(ioA, ctx), connA) { result -> + IORunLoop.startCancellable(IOForkedStart(ioA, ctx), connA) { result -> result.fold({ onError(active, cb, conn, connB, connC, it) }, { @@ -354,7 +354,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioB, ctx), connB) { result -> + IORunLoop.startCancellable(IOForkedStart(ioB, ctx), connB) { result -> result.fold({ onError(active, cb, conn, connA, connC, it) }, { @@ -362,7 +362,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioC, ctx), connC) { result -> + IORunLoop.startCancellable(IOForkedStart(ioC, ctx), connC) { result -> result.fold({ onError(active, cb, conn, connA, connB, it) }, { @@ -419,7 +419,7 @@ interface IORace { conn.pushPair(connA, connB) - IORunLoop.startCancelable(IOForkedStart(ioA, ctx), connA) { either: Either -> + IORunLoop.startCancellable(IOForkedStart(ioA, ctx), connA) { either: Either -> either.fold({ error -> if (active.getAndSet(false)) { // if an error finishes first, stop the race. connB.cancel().fix().unsafeRunAsync { r2 -> @@ -439,7 +439,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioB, ctx), connB) { either: Either -> + IORunLoop.startCancellable(IOForkedStart(ioB, ctx), connB) { either: Either -> either.fold({ error -> if (active.getAndSet(false)) { // if an error finishes first, stop the race. connA.cancel().fix().unsafeRunAsync { r2 -> @@ -509,7 +509,7 @@ interface IORace { conn.push(connA.cancel(), connB.cancel(), connC.cancel()) - IORunLoop.startCancelable(IOForkedStart(ioA, ctx), connA) { either: Either -> + IORunLoop.startCancellable(IOForkedStart(ioA, ctx), connA) { either: Either -> either.fold({ error -> if (active.getAndSet(false)) { // if an error finishes first, stop the race. connB.cancel().fix().unsafeRunAsync { r2 -> @@ -536,7 +536,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioB, ctx), connB) { either: Either -> + IORunLoop.startCancellable(IOForkedStart(ioB, ctx), connB) { either: Either -> either.fold({ error -> if (active.getAndSet(false)) { // if an error finishes first, stop the race. connA.cancel().fix().unsafeRunAsync { r2 -> @@ -563,7 +563,7 @@ interface IORace { }) } - IORunLoop.startCancelable(IOForkedStart(ioC, ctx), connC) { either: Either -> + IORunLoop.startCancellable(IOForkedStart(ioC, ctx), connC) { either: Either -> either.fold({ error -> if (active.getAndSet(false)) { // if an error finishes first, stop the race. connA.cancel().fix().unsafeRunAsync { r2 -> diff --git a/arrow-fx/src/main/kotlin/arrow/fx/IORunLoop.kt b/arrow-fx/src/main/kotlin/arrow/fx/IORunLoop.kt index 817736878..915de2137 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/IORunLoop.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/IORunLoop.kt @@ -21,13 +21,13 @@ private typealias Callback = (Either) -> Unit internal object IORunLoop { fun start(source: IOOf, cb: (Either) -> Unit): Unit = - loop(source, KindConnection.uncancelable, cb as Callback, null, null, null, IOContext(KindConnection.uncancelable)) + loop(source, KindConnection.uncancellable, cb as Callback, null, null, null, IOContext(KindConnection.uncancellable)) /** * Evaluates the given `IO` reference, calling the given callback * with the result when completed. */ - fun startCancelable(source: IOOf, conn: IOConnection, cb: (Either) -> Unit): Unit = + fun startCancellable(source: IOOf, conn: IOConnection, cb: (Either) -> Unit): Unit = loop(source, conn, cb as Callback, null, null, null, IOContext(conn)) fun step(source: IO): IO { @@ -150,7 +150,7 @@ internal object IORunLoop { private fun loop( source: Current, - cancelable: IOConnection, + cancellable: IOConnection, cb: (Either) -> Unit, rcbRef: RestartCallback?, bFirstRef: BindF?, @@ -158,7 +158,7 @@ internal object IORunLoop { ctx: CoroutineContext ) { var currentIO: Current? = source - var conn: IOConnection = cancelable + var conn: IOConnection = cancellable var bFirst: BindF? = bFirstRef var bRest: CallStack? = bRestRef var rcb: RestartCallback? = rcbRef @@ -168,7 +168,7 @@ internal object IORunLoop { var result: Any? = null do { - if (conn.isCanceled()) { + if (conn.isCancelled()) { cb(Left(OnCancel.CancellationException)) return } @@ -358,7 +358,7 @@ internal object IORunLoop { } /** - * A `RestartCallback` gets created only once, per [startCancelable] (`unsafeRunAsync`) invocation, once an `Async` + * A `RestartCallback` gets created only once, per [startCancellable] (`unsafeRunAsync`) invocation, once an `Async` * state is hit, its job being to resume the loop after the boundary, but with the bind call-stack restored. */ private data class RestartCallback(val connInit: IOConnection, val cb: Callback) : Callback, kotlin.coroutines.Continuation { diff --git a/arrow-fx/src/main/kotlin/arrow/fx/KindConnection.kt b/arrow-fx/src/main/kotlin/arrow/fx/KindConnection.kt index 9a56c465c..a4d567920 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/KindConnection.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/KindConnection.kt @@ -26,7 +26,7 @@ object ConnectionCancellationException : JavaCancellationException("User cancell * The cancellation functions are maintained in a stack and executed in a FIFO order. */ @Deprecated(message = "Cancelling operations through KindConnection will not be supported anymore." + - "In case you need to cancel multiple processes can do so by using cancelable and composing cancel operations using parMapN") + "In case you need to cancel multiple processes can do so by using cancellable and composing cancel operations using parMapN") sealed class KindConnection { /** @@ -53,7 +53,7 @@ sealed class KindConnection { abstract fun cancel(): CancelToken /** - * Check if the [KindConnection] is canceled + * Check if the [KindConnection] is cancelled * * ```kotlin:ank:playground * import arrow.fx.* @@ -62,22 +62,25 @@ sealed class KindConnection { * //sampleStart * val conn = IOConnection() * - * val isNotCanceled = conn.isCanceled() + * val isNotCancelled = conn.isCancelled() * * conn.cancel().fix().unsafeRunSync() * - * val isCanceled = conn.isCanceled() + * val isCancelled = conn.isCancelled() * //sampleEnd - * println("isNotCanceled: $isNotCanceled, isCanceled: $isCanceled") + * println("isNotCancelled: $isNotCancelled, isCancelled: $isCancelled") * } * ``` * - * @see isNotCanceled + * @see isNotCancelled */ - abstract fun isCanceled(): Boolean + abstract fun isCancelled(): Boolean + + @Deprecated("Renaming this api for consistency", ReplaceWith("isCancelled()")) + fun isCanceled(): Boolean = isCancelled() /** - * Check if the [KindConnection] is not canceled + * Check if the [KindConnection] is not cancelled * * ```kotlin:ank:playground * import arrow.fx.* @@ -86,19 +89,22 @@ sealed class KindConnection { * //sampleStart * val conn = IOConnection() * - * val isNotCanceled = conn.isNotCanceled() + * val isNotCancelled = conn.isNotCancelled() * * conn.cancel().fix().unsafeRunSync() * - * val isCanceled = conn.isNotCanceled() + * val isCancelled = conn.isNotCancelled() * //sampleEnd - * println("isNotCanceled: $isNotCanceled, isCanceled: $isCanceled") + * println("isNotCancelled: $isNotCancelled, isCancelled: $isCancelled") * } * ``` * - * @see isCanceled + * @see isCancelled */ - fun isNotCanceled(): Boolean = !isCanceled() + fun isNotCancelled(): Boolean = !isCancelled() + + @Deprecated("Renaming this api for consistency", ReplaceWith("isNotCancelled()")) + fun isNotCanceled(): Boolean = !isCancelled() /** * Pushes a cancellation function, or token, meant to cancel and cleanup resources. @@ -147,7 +153,7 @@ sealed class KindConnection { /** * Pushes a pair of [KindConnection] on the stack, which on cancellation will get trampolined. This is useful in * race for example, because combining a whole collection of tasks, two by two, can lead to building a - * cancelable that's stack unsafe. + * cancellable that's stack unsafe. * * ```kotlin:ank:playground * import arrow.fx.* @@ -172,7 +178,7 @@ sealed class KindConnection { /** * Pushes a pair of [KindConnection] on the stack, which on cancellation will get trampolined. This is useful in * race for example, because combining a whole collection of tasks, two by two, can lead to building a - * cancelable that's stack unsafe. + * cancellable that's stack unsafe. * * ```kotlin:ank:playground * import arrow.fx.* @@ -195,10 +201,10 @@ sealed class KindConnection { push(lh, rh) /** - * Pops a cancelable reference from the FIFO stack of references for this connection. - * A cancelable reference is meant to cancel and cleanup resources. + * Pops a cancellable reference from the FIFO stack of references for this connection. + * A cancellable reference is meant to cancel and cleanup resources. * - * @return the cancelable reference that was removed. + * @return the cancellable reference that was removed. * * ```kotlin:ank:playground * import arrow.fx.* @@ -232,10 +238,10 @@ sealed class KindConnection { * val conn = IOConnection() * * conn.cancel().fix().unsafeRunSync() - * val isCanceled = conn.isCanceled() + * val isCancelled = conn.isCancelled() * val couldReactive = conn.tryReactivate() * - * val isReactivated = conn.isCanceled() + * val isReactivated = conn.isCancelled() * //sampleEnd * } * ``` @@ -262,7 +268,7 @@ sealed class KindConnection { DefaultKindConnection(MD, run) /** - * Construct an uncancelable [KindConnection] for a kind [F] based on [MonadDefer]. + * Construct an uncancellable [KindConnection] for a kind [F] based on [MonadDefer]. * * ```kotlin:ank:playground * import arrow.fx.* @@ -270,25 +276,28 @@ sealed class KindConnection { * * fun main(args: Array) { * //sampleStart - * val conn: IOConnection = KindConnection.uncancelable(IO.applicative()) + * val conn: IOConnection = KindConnection.uncancellable(IO.applicative()) * //sampleEnd * } * ``` **/ - fun uncancelable(FA: Applicative): KindConnection = Uncancelable(FA) + fun uncancellable(FA: Applicative): KindConnection = Uncancellable(FA) + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellable(FA)")) + fun uncancelable(FA: Applicative): KindConnection = Uncancellable(FA) } /** - * [KindConnection] reference that cannot be canceled. + * [KindConnection] reference that cannot be cancelled. */ - private class Uncancelable(FA: Applicative) : KindConnection(), Applicative by FA { + private class Uncancellable(FA: Applicative) : KindConnection(), Applicative by FA { override fun cancel(): CancelToken = unit() - override fun isCanceled(): Boolean = false + override fun isCancelled(): Boolean = false override fun push(token: CancelToken) = Unit override fun push(vararg token: CancelToken) = Unit override fun pop(): CancelToken = unit() override fun tryReactivate(): Boolean = true - override fun toString(): String = "UncancelableConnection" + override fun toString(): String = "UncancellableConnection" } /** @@ -306,7 +315,7 @@ sealed class KindConnection { } } - override fun isCanceled(): Boolean = state.value == null + override fun isCancelled(): Boolean = state.value == null override tailrec fun push(token: CancelToken): Unit = when (val list = state.value) { null -> run(token) // If connection is already cancelled cancel token immediately. diff --git a/arrow-fx/src/main/kotlin/arrow/fx/MVar.kt b/arrow-fx/src/main/kotlin/arrow/fx/MVar.kt index 8e68646ed..585db87da 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/MVar.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/MVar.kt @@ -2,8 +2,8 @@ package arrow.fx import arrow.Kind import arrow.core.Option -import arrow.fx.internal.CancelableMVar -import arrow.fx.internal.UncancelableMVar +import arrow.fx.internal.CancellableMVar +import arrow.fx.internal.UncancellableMVar import arrow.fx.typeclasses.Async import arrow.fx.typeclasses.Concurrent @@ -26,7 +26,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.empty().flatMap { v -> * v.isEmpty() @@ -51,7 +51,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.just(10).flatMap { v -> * v.isNotEmpty() @@ -77,7 +77,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.empty().flatMap { v -> * v.put(5).flatMap { @@ -101,7 +101,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.empty().flatMap { v -> * v.tryPut(5) @@ -126,7 +126,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.just(5).flatMap { v -> * v.take() @@ -152,7 +152,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.just(5).flatMap { v -> * v.tryTake() @@ -178,7 +178,7 @@ interface MVar { * import arrow.fx.extensions.io.monad.map * fun main(args: Array) { * //sampleStart - * val mvar = MVar.factoryUncancelable(IO.async()) + * val mvar = MVar.factoryUncancellable(IO.async()) * * mvar.just(5).flatMap { v -> * v.read() @@ -204,7 +204,7 @@ interface MVar { companion object { /** - * Create an cancelable empty [MVar]. + * Create an cancellable empty [MVar]. * * ```kotlin:ank:playground * import arrow.fx.* @@ -218,10 +218,10 @@ interface MVar { * ``` */ fun empty(CF: Concurrent): Kind> = - CancelableMVar.empty(CF) + CancellableMVar.empty(CF) /** - * Create a cancelable [MVar] that's initialized to an [initial] value. + * Create a cancellable [MVar] that's initialized to an [initial] value. * * ```kotlin:ank:playground * import arrow.fx.* @@ -229,16 +229,20 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar: IOOf> = MVar.cancelable(5, IO.concurrent()) + * val mvar: IOOf> = MVar.cancellable(5, IO.concurrent()) * //sampleEnd * } * ``` */ + fun cancellable(initial: A, CF: Concurrent): Kind> = + CancellableMVar(initial, CF) + + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(initial, CF)")) fun cancelable(initial: A, CF: Concurrent): Kind> = - CancelableMVar(initial, CF) + cancellable(initial, CF) /** - * Create an uncancelable [MVar] that's initialized to an [initial] value. + * Create an uncancellable [MVar] that's initialized to an [initial] value. * * ```kotlin:ank:playground * import arrow.fx.* @@ -246,16 +250,16 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar: IOOf> = MVar.cancelable(5, IO.concurrent()) + * val mvar: IOOf> = MVar.cancellable(5, IO.concurrent()) * //sampleEnd * } * ``` */ operator fun invoke(initial: A, CF: Concurrent): Kind> = - CancelableMVar(initial, CF) + CancellableMVar(initial, CF) /** - * Create an uncancelable empty [MVar]. + * Create an uncancellable empty [MVar]. * * ```kotlin:ank:playground * import arrow.fx.* @@ -263,16 +267,20 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar: IOOf> = MVar.uncancelableEmpty(IO.async()) + * val mvar: IOOf> = MVar.uncancellableEmpty(IO.async()) * //sampleEnd * } * ``` */ + fun uncancellableEmpty(AS: Async): Kind> = + UncancellableMVar.empty(AS) + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellableEmpty(AS)")) fun uncancelableEmpty(AS: Async): Kind> = - UncancelableMVar.empty(AS) + uncancellableEmpty(AS) /** - * Create an uncancelable [MVar] that's initialized to an [initial] value. + * Create an uncancellable [MVar] that's initialized to an [initial] value. * * ```kotlin:ank:playground * import arrow.fx.* @@ -280,40 +288,52 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvar: IOOf> = MVar.uncancelableOf(5, IO.async()) + * val mvar: IOOf> = MVar.uncancellableOf(5, IO.async()) * //sampleEnd * } * ``` */ + fun uncancellableOf(initial: A, AS: Async): Kind> = + UncancellableMVar(initial, AS) + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellableOf(initial, AS)")) fun uncancelableOf(initial: A, AS: Async): Kind> = - UncancelableMVar(initial, AS) + uncancellableOf(initial, AS) /** * Build a [MVarFactory] value for creating MVar types [F] without deciding the type of the MVar's value. * * @see MVarFactory */ - fun factoryUncancelable(AS: Async) = object : MVarFactory { + fun factoryUncancellable(AS: Async) = object : MVarFactory { override fun just(a: A): Kind> = - uncancelableOf(a, AS) + uncancellableOf(a, AS) override fun empty(): Kind> = - uncancelableEmpty(AS) + uncancellableEmpty(AS) } + @Deprecated("Renaming this api for consistency", ReplaceWith("factoryUncancellable(AS)")) + fun factoryUncancelable(AS: Async) = + factoryUncancellable(AS) + /** * Build a [MVarFactory] value for creating MVar types [F] without deciding the type of the MVar's value. * * @see MVarFactory */ - fun factoryCancelable(CF: Concurrent) = object : MVarFactory { + fun factoryCancellable(CF: Concurrent) = object : MVarFactory { override fun just(a: A): Kind> = - cancelable(a, CF) + cancellable(a, CF) override fun empty(): Kind> = empty(CF) } + + @Deprecated("Renaming this api for consistency", ReplaceWith("factoryCancellable(CF)")) + fun factoryCancelable(CF: Concurrent) = + factoryCancellable(CF) } } @@ -327,7 +347,7 @@ interface MVar { * * fun main(args: Array) { * //sampleStart - * val mvarFactory: MVarFactory = MVar.factoryCancelable(IO.concurrent()) + * val mvarFactory: MVarFactory = MVar.factoryCancellable(IO.concurrent()) * val intVar: IOOf> = mvarFactory.just(5) * val stringVar: IOOf> = mvarFactory.empty() * //sampleEnd @@ -345,7 +365,7 @@ interface MVarFactory { * * fun main(args: Array) { * //sampleStart - * val mvarPartial: MVarFactory = MVar.factoryUncancelable(IO.async()) + * val mvarPartial: MVarFactory = MVar.factoryUncancellable(IO.async()) * val intVar: IOOf> = mvarPartial.just(5) * //sampleEnd * } @@ -362,7 +382,7 @@ interface MVarFactory { * * fun main(args: Array) { * //sampleStart - * val mvarPartial: MVarFactory = MVar.factoryUncancelable(IO.async()) + * val mvarPartial: MVarFactory = MVar.factoryUncancellable(IO.async()) * val stringVar: IOOf> = mvarPartial.empty() * //sampleEnd * } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/Promise.kt b/arrow-fx/src/main/kotlin/arrow/fx/Promise.kt index 93972fb35..70d47699f 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/Promise.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/Promise.kt @@ -1,8 +1,8 @@ package arrow.fx import arrow.Kind -import arrow.fx.internal.CancelablePromise -import arrow.fx.internal.UncancelablePromise +import arrow.fx.internal.CancellablePromise +import arrow.fx.internal.UncancellablePromise import arrow.fx.typeclasses.Async import arrow.fx.typeclasses.Concurrent import arrow.core.Tuple2 @@ -32,11 +32,11 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * * promise.flatMap { p -> * p.get() - * } //Never ends since is uncancelable + * } //Never ends since is uncancellable * * promise.flatMap { p -> * p.complete(1).flatMap { @@ -62,7 +62,7 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * * promise.flatMap { p -> * p.tryGet() @@ -90,7 +90,7 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * * promise.flatMap { p -> * p.complete(1).flatMap { @@ -121,7 +121,7 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * * promise.flatMap { p -> * p.tryComplete(1) @@ -149,7 +149,7 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * * promise.flatMap { p -> * p.error(RuntimeException("Boom")) @@ -180,7 +180,7 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise = Promise.uncancelable(IO.async()) + * val promise = Promise.uncancellable(IO.async()) * val throwable = RuntimeException("Boom") * * promise.flatMap { p -> @@ -216,7 +216,7 @@ interface Promise { * ``` */ operator fun invoke(CF: Concurrent): Kind> = - CF.later { CancelablePromise(CF) } + CF.later { CancellablePromise(CF) } /** * Creates an empty `Promise` from on [Concurrent] instance for [F]. @@ -228,12 +228,16 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val unsafePromise: Promise = Promise.unsafeCancelable(IO.concurrent()) + * val unsafePromise: Promise = Promise.unsafeCancellable(IO.concurrent()) * //sampleEnd * } * ``` */ - fun unsafeCancelable(CF: Concurrent): Promise = CancelablePromise(CF) + fun unsafeCancellable(CF: Concurrent): Promise = CancellablePromise(CF) + + @Deprecated("Renaming this api for consistency", ReplaceWith("unsafeCancellable(CF)")) + fun unsafeCancelable(CF: Concurrent): Promise = + unsafeCancellable(CF) /** * Creates an empty `Promise` from on [Async] instance for [F]. @@ -245,13 +249,17 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val promise: IOOf> = Promise.uncancelable(IO.async()) + * val promise: IOOf> = Promise.uncancellable(IO.async()) * //sampleEnd * } * ``` */ + fun uncancellable(AS: Async): Kind> = + AS.later { UncancellablePromise(AS) } + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellable(AS)")) fun uncancelable(AS: Async): Kind> = - AS.later { UncancelablePromise(AS) } + uncancellable(AS) /** * Creates an empty `Promise` from on [Async] instance for [F]. @@ -264,12 +272,15 @@ interface Promise { * * fun main(args: Array) { * //sampleStart - * val unsafePromise: Promise = Promise.unsafeUncancelable(IO.async()) + * val unsafePromise: Promise = Promise.unsafeUncancellable(IO.async()) * //sampleEnd * } * ``` */ - fun unsafeUncancelable(AS: Async): Promise = UncancelablePromise(AS) + fun unsafeUncancellable(AS: Async): Promise = UncancellablePromise(AS) + + @Deprecated("Renaming this api for consistency", ReplaceWith("unsafeUncancellable(AS)")) + fun unsafeUncancelable(AS: Async): Promise = unsafeUncancellable(AS) /** * @@ -292,12 +303,12 @@ interface Promise { // creates a new promise for `use` and returns val (fc, pb) = !ref.modify { a -> - val pb = unsafeCancelable(this) + val pb = unsafeCancellable(this) val (fc, a2) = use(pb, a) a2 toT (fc toT pb) } val c = !fc - !(releaseRef.set(Some(c toT pb)).followedBy(just(pb))).uncancelable() + !(releaseRef.set(Some(c toT pb)).followedBy(just(pb))).uncancellable() !pb.get() }.guarantee(releaseRef.get().flatMap { it.map { (c, fb) -> release(c, fb) }.getOrElse { just(Unit) } }) } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/Queue.kt b/arrow-fx/src/main/kotlin/arrow/fx/Queue.kt index 44942272f..b56b6bccd 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/Queue.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/Queue.kt @@ -3,7 +3,7 @@ package arrow.fx import arrow.Kind import arrow.Kind2 import arrow.core.Tuple2 -import arrow.fx.internal.CancelableQueue +import arrow.fx.internal.CancellableQueue import arrow.fx.internal.IQueue import arrow.fx.typeclasses.Concurrent import arrow.typeclasses.Applicative @@ -87,24 +87,24 @@ interface Queue : */ fun bounded(capacity: Int, CF: Concurrent): Kind> = CF.run { ensureCapacity(capacity, CF).map { - CancelableQueue(CancelableQueue.Companion.State.empty(), CancelableQueue.SurplusStrategy.Bounded(capacity, CF), CF) + CancellableQueue(CancellableQueue.Companion.State.empty(), CancellableQueue.SurplusStrategy.Bounded(capacity, CF), CF) } } fun sliding(capacity: Int, CF: Concurrent): Kind> = CF.run { ensureCapacity(capacity, CF).map { n -> - CancelableQueue(CancelableQueue.Companion.State.empty(), CancelableQueue.SurplusStrategy.Sliding(n, CF), CF) + CancellableQueue(CancellableQueue.Companion.State.empty(), CancellableQueue.SurplusStrategy.Sliding(n, CF), CF) } } fun dropping(capacity: Int, CF: Concurrent): Kind> = CF.run { ensureCapacity(capacity, CF).map { - CancelableQueue(CancelableQueue.Companion.State.empty(), CancelableQueue.SurplusStrategy.Dropping(capacity, CF), CF) + CancellableQueue(CancellableQueue.Companion.State.empty(), CancellableQueue.SurplusStrategy.Dropping(capacity, CF), CF) } } fun unbounded(CF: Concurrent): Kind> = CF.later { - CancelableQueue(CancelableQueue.Companion.State.empty(), CancelableQueue.SurplusStrategy.Unbounded(CF), CF) + CancellableQueue(CancellableQueue.Companion.State.empty(), CancellableQueue.SurplusStrategy.Unbounded(CF), CF) } } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/Semaphore.kt b/arrow-fx/src/main/kotlin/arrow/fx/Semaphore.kt index 1b67588ae..35846209d 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/Semaphore.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/Semaphore.kt @@ -29,7 +29,7 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * val result = semaphore.flatMap { s -> * s.available() @@ -51,7 +51,7 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * val result = semaphore.flatMap { s -> * s.count() @@ -73,11 +73,11 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * semaphore.flatMap { s -> * s.acquireN(6) - * } //Never ends since is uncancelable + * } //Never ends since is uncancellable * * semaphore.flatMap { s -> * s.acquireN(5).flatMap { @@ -109,7 +109,7 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * semaphore.flatMap { s -> * s.tryAcquireN(6) @@ -142,7 +142,7 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * semaphore.flatMap { s -> * s.acquireN(5).flatMap { @@ -175,7 +175,7 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * * val result = semaphore.flatMap { s -> * s.withPermit(IO { "Use controlled resource" }) @@ -212,7 +212,7 @@ interface Semaphore { /** * Construct a [Semaphore] initialized with [n] available permits. - * Since it's based on [Async] it's constrained with an uncancelable [acquire] operation. + * Since it's based on [Async] it's constrained with an uncancellable [acquire] operation. * * ```kotlin:ank:playground * import arrow.fx.* @@ -220,17 +220,21 @@ interface Semaphore { * * fun main(args: Array) { * //sampleStart - * val semaphore = Semaphore.uncancelable(5, IO.async()) + * val semaphore = Semaphore.uncancellable(5, IO.async()) * //sampleEnd * } */ - fun uncancelable(n: Long, AS: Async): Kind> = AS.run { + fun uncancellable(n: Long, AS: Async): Kind> = AS.run { assertNonNegative(n).flatMap { Ref>(AS, Right(n)).map { ref -> - DefaultSemaphore(ref, Promise.uncancelable(this), this) + DefaultSemaphore(ref, Promise.uncancellable(this), this) } } } + + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellable(n, AS)")) + fun uncancelable(n: Long, AS: Async): Kind> = + uncancellable(n, AS) } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/extensions/io.kt b/arrow-fx/src/main/kotlin/arrow/fx/extensions/io.kt index 231b5af95..065cf43c1 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/extensions/io.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/extensions/io.kt @@ -195,11 +195,11 @@ interface IOConcurrent : Concurrent, IOAsync { override fun Kind.fork(coroutineContext: CoroutineContext): IO> = fix().fork(coroutineContext) - override fun cancelable(k: ((Either) -> Unit) -> CancelToken): Kind = - IO.cancelable(k) + override fun cancellable(k: ((Either) -> Unit) -> CancelToken): Kind = + IO.cancellable(k) - override fun cancelableF(k: ((Either) -> Unit) -> IOOf>): IO = - IO.cancelableF(k) + override fun cancellableF(k: ((Either) -> Unit) -> IOOf>): IO = + IO.cancellableF(k) override fun CoroutineContext.racePair(fa: Kind, fb: Kind): IO> = IO.racePair(this, fa, fb) diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableQueue.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableQueue.kt index 643fffdad..47f2de2ed 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableQueue.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableQueue.kt @@ -1,366 +1,4 @@ package arrow.fx.internal -import arrow.Kind -import arrow.core.Either -import arrow.core.None -import arrow.core.Option -import arrow.core.Right -import arrow.core.Some -import arrow.core.Tuple2 -import arrow.core.internal.AtomicRefW -import arrow.core.left - -import arrow.fx.Queue -import arrow.fx.QueueShutdown -import arrow.fx.typeclasses.CancelToken -import arrow.fx.typeclasses.Concurrent -import arrow.fx.typeclasses.Fiber -import arrow.fx.typeclasses.mapUnit -import arrow.fx.typeclasses.rightUnit -import arrow.typeclasses.Applicative -import kotlin.coroutines.EmptyCoroutineContext - -class CancelableQueue internal constructor( - initial: State?, - private val strategy: SurplusStrategy, - private val CF: Concurrent -) : Concurrent by CF, Queue { - - private val state: AtomicRefW> = AtomicRefW(initial ?: State.empty()) - - companion object { - operator fun invoke(initial: List, CF: Concurrent): Kind> = CF.later { - CancelableQueue(State.Surplus(IQueue(initial), linkedMapOf(), linkedMapOf()), SurplusStrategy.Unbounded(CF), CF) - } - - /** Returns an empty [UncancelableMVar] instance. */ - fun empty(CF: Concurrent): Kind> = CF.later { - CancelableQueue(null, SurplusStrategy.Unbounded(CF), CF) - } - - internal sealed class State { - data class Deficit( - val reads: Map) -> Unit>, - val takes: Map) -> Unit>, - val shutdownHook: Map) -> Unit> - ) : State() - - data class Surplus( - val value: IQueue, - val offers: Map) -> Unit>>, - val shutdownHook: Map) -> Unit> - ) : State() - - object Shutdown : State() - - companion object { - private val empty: State.Deficit = State.Deficit(linkedMapOf(), linkedMapOf(), linkedMapOf()) - fun empty(): State.Deficit = empty as State.Deficit - fun shutdown(): State = - Shutdown as State - } - } - } - - override fun offer(a: A): Kind = - tryOffer(a).flatMap { didPut -> - if (didPut) unit() else cancelableF { cb -> unsafeOffer(a, cb) } - } - - override fun shutdown(): Kind = - defer { unsafeShutdown() } - - override fun size(): Kind = defer { - when (val curr = state.value) { - is State.Deficit -> just(-curr.takes.size) - is State.Surplus -> just(1 + curr.offers.size) - State.Shutdown -> raiseError(QueueShutdown) - } - } - - fun isEmpty(): Kind = - size().map { it == 0 } - - fun isNotEmpty(): Kind = - isEmpty().map(Boolean::not) - - override fun awaitShutdown(): Kind = - CF.cancelableF(::unsafeRegisterAwaitShutdown) - - fun tryOffer(a: A): Kind = - defer { unsafeTryOffer(a) } - - override fun take(): Kind = - tryTake().flatMap { - it.fold({ cancelableF(::unsafeTake) }, ::just) - } - - fun tryTake(): Kind> = - defer { unsafeTryTake() } - - fun read(): Kind = - cancelable(::unsafeRead) - - private tailrec fun unsafeTryOffer(a: A): Kind = - when (val current = state.value) { - is State.Surplus -> strategy.unsafeTryHandleSurplus(state, a, current) ?: unsafeTryOffer(a) - is State.Deficit -> { - val firstTake = current.takes.values.firstOrNull() - - val update: State = if (firstTake == null) State.Surplus(IQueue(a), linkedMapOf(), current.shutdownHook) else { - val rest = current.takes.toList().drop(1) - if (rest.isEmpty()) current.copy(linkedMapOf(), linkedMapOf()) - else State.Deficit(emptyMap(), rest.toMap(), current.shutdownHook) - } - - if (!state.compareAndSet(current, update)) { - unsafeTryOffer(a) - } else if (firstTake != null || current.reads.isNotEmpty()) { - callPutAndAllReaders(a, firstTake, current.reads) - } else just(true) - } - is State.Shutdown -> raiseError(QueueShutdown) - } - - private tailrec fun unsafeRegisterAwaitShutdown(shutdown: (Either) -> Unit): Kind> = - when (val curr = state.value) { - is State.Deficit -> { - val token = Token() - val newShutdowns = curr.shutdownHook + Pair(token, shutdown) - if (state.compareAndSet(curr, curr.copy(shutdownHook = newShutdowns))) just(later { unsafeCancelAwaitShutdown(token) }) - else unsafeRegisterAwaitShutdown(shutdown) - } - is State.Surplus -> { - val token = Token() - val newShutdowns = curr.shutdownHook + Pair(token, shutdown) - if (state.compareAndSet(curr, curr.copy(shutdownHook = newShutdowns))) just(later { unsafeCancelAwaitShutdown(token) }) - else unsafeRegisterAwaitShutdown(shutdown) - } - State.Shutdown -> { - shutdown(rightUnit) - just(CF.unit()) - } - } - - private tailrec fun unsafeOffer(a: A, onPut: (Either) -> Unit): Kind> = - when (val current = state.value) { - is State.Surplus -> { - val id = Token() - val newMap = current.offers + Pair(id, Tuple2(a, onPut)) - if (state.compareAndSet(current, State.Surplus(current.value, newMap, current.shutdownHook))) just(later { unsafeCancelOffer(id) }) - else unsafeOffer(a, onPut) - } - is State.Deficit -> { - val first = current.takes.values.firstOrNull() - val update = if (current.takes.isEmpty()) State.Surplus(IQueue(a), linkedMapOf(), current.shutdownHook) else { - val rest = current.takes.toList().drop(1) - if (rest.isEmpty()) current.copy(linkedMapOf(), linkedMapOf()) - else State.Deficit(emptyMap(), rest.toMap(), current.shutdownHook) - } - - if (state.compareAndSet(current, update)) { - if (first != null || current.reads.isNotEmpty()) callPutAndAllReaders(a, first, current.reads).map { - onPut(rightUnit) - unit() - } else { - onPut(rightUnit) - just(unit()) - } - } else unsafeOffer(a, onPut) - } - is State.Shutdown -> { - onPut(Either.Left(QueueShutdown)) - just(unit()) - } - } - - private tailrec fun unsafeShutdown(): Kind = - when (val current = state.value) { - is State.Shutdown -> raiseError(QueueShutdown) - is State.Surplus -> - if (state.compareAndSet(current, State.shutdown())) later { - current.offers.values.forEach { (_, cb) -> cb(QueueShutdown.left()) } - current.shutdownHook.values.forEach { cb -> cb(rightUnit) } - } else unsafeShutdown() - is State.Deficit -> - if (state.compareAndSet(current, State.shutdown())) later { - current.takes.forEach { (_, cb) -> cb(QueueShutdown.left()) } - current.reads.forEach { (_, cb) -> cb(QueueShutdown.left()) } - current.shutdownHook.values.forEach { cb -> cb(rightUnit) } - } else unsafeShutdown() - } - - private tailrec fun unsafeCancelAwaitShutdown(id: Token): Unit = - when (val curr = state.value) { - is State.Deficit -> { - val update = curr.copy(shutdownHook = curr.shutdownHook - id) - if (state.compareAndSet(curr, update)) Unit - else unsafeCancelAwaitShutdown(id) - } - is State.Surplus -> { - val update = curr.copy(shutdownHook = curr.shutdownHook - id) - if (state.compareAndSet(curr, update)) Unit - else unsafeCancelAwaitShutdown(id) - } - else -> Unit - } - - private tailrec fun unsafeCancelOffer(id: Token): Unit = - when (val current = state.value) { - is State.Surplus -> { - val update = current.copy(offers = current.offers - id) - if (state.compareAndSet(current, update)) Unit - else unsafeCancelOffer(id) - } - else -> Unit - } - - private tailrec fun unsafeTryTake(): Kind> = - when (val current = state.value) { - is State.Surplus -> { - val (head, tail) = current.value.dequeue() - if (current.offers.isEmpty()) { - val update = if (tail.isEmpty()) State.empty().copy(shutdownHook = current.shutdownHook) else current.copy(value = tail) - if (state.compareAndSet(current, update)) just(Some(head)) - else unsafeTryTake() - } else { - val (ax, notify) = current.offers.values.first() - val xs = current.offers.toList().drop(1) - // TODO ADD STRATEGY - if (state.compareAndSet(current, State.Surplus(tail.enqueue(ax), xs.toMap(), current.shutdownHook))) later { notify(rightUnit) }.fork(EmptyCoroutineContext).map { Some(head) } - else unsafeTryTake() - } - } - is State.Deficit -> just(None) - is State.Shutdown -> just(None) - } - - private tailrec fun unsafeTake(onTake: (Either) -> Unit): Kind> = - when (val current = state.value) { - is State.Surplus -> { - val (head, tail) = current.value.dequeue() - if (current.offers.isEmpty()) { - val update = if (tail.isEmpty()) State.empty().copy(shutdownHook = current.shutdownHook) else current.copy(value = tail) - if (state.compareAndSet(current, update)) { - onTake(Right(head)) - just(unit()) - } else { - unsafeTake(onTake) - } - } else { - val (ax, notify) = current.offers.values.first() - val xs = current.offers.toList().drop(0) // TODO ADD STRATEGY - if (state.compareAndSet(current, State.Surplus(tail.enqueue(ax), xs.toMap(), current.shutdownHook))) { - later { notify(rightUnit) }.fork(EmptyCoroutineContext).map { - onTake(Either.Right(head)) - unit() - } - } else unsafeTake(onTake) - } - } - is State.Deficit -> { - val id = Token() - val newQueue = current.takes + Pair(id, onTake) - if (state.compareAndSet(current, State.Deficit(current.reads, newQueue, current.shutdownHook))) just(later { unsafeCancelTake(id) }) - else unsafeTake(onTake) - } - is State.Shutdown -> { - onTake(Either.Left(QueueShutdown)) - just(unit()) - } - } - - private tailrec fun unsafeCancelTake(id: Token): Unit = - when (val current = state.value) { - is State.Deficit -> { - val newMap = current.takes - id - val update = State.Deficit(current.reads, newMap, current.shutdownHook) - if (state.compareAndSet(current, update)) Unit - else unsafeCancelTake(id) - } - else -> Unit - } - - private tailrec fun unsafeRead(onRead: (Either) -> Unit): Kind = - when (val current = state.value) { - is State.Surplus -> { - onRead(Right(current.value.head())) - unit() - } - is State.Deficit -> { - val id = Token() - val newReads = current.reads + Pair(id, onRead) - if (state.compareAndSet(current, State.Deficit(newReads, current.takes, current.shutdownHook))) later { unsafeCancelRead(id) } - else unsafeRead(onRead) - } - is State.Shutdown -> raiseError(QueueShutdown) - } - - private tailrec fun unsafeCancelRead(id: Token): Unit = - when (val current = state.value) { - is State.Deficit -> { - val newMap = current.reads - id - val update = State.Deficit(newMap, current.takes, current.shutdownHook) - if (state.compareAndSet(current, update)) Unit - else unsafeCancelRead(id) - } - else -> Unit - } - - private fun callPutAndAllReaders(a: A, put: ((Either) -> Unit)?, reads: Map) -> Unit>): Kind { - val value = Right(a) - return reads.values.callAll(value).flatMap { - if (put != null) later { put(value) }.fork(EmptyCoroutineContext).map { true } - else just(true) - } - } - - // For streaming a value to a whole `reads` collection - private fun Iterable<(Either) -> Unit>.callAll(value: Either): Kind = - fold(null as Kind>?) { acc, cb -> - val task = later { cb(value) }.fork(EmptyCoroutineContext) - acc?.flatMap { task } ?: task - }?.map(mapUnit) ?: unit() - - override fun Kind.ap(ff: Kind B>): Kind = CF.run { - this@ap.ap(ff) - } - - override fun Kind.map(f: (A) -> B): Kind = CF.run { - this@map.map(f) - } - - internal sealed class SurplusStrategy { - abstract fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? - - data class Bounded(val capacity: Int, val AP: Applicative) : SurplusStrategy() { - override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? = when { - surplus.value.length() >= capacity -> AP.just(false) - state.compareAndSet(surplus, surplus.copy(surplus.value.enqueue(a))) -> AP.just(true) - else -> null - } - } - - data class Sliding(val capacity: Int, val AP: Applicative) : SurplusStrategy() { - override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? { - val nextQueue = if (surplus.value.length() < capacity) surplus.value.enqueue(a) else surplus.value.dequeue().b.enqueue(a) - return if (!state.compareAndSet(surplus, surplus.copy(value = nextQueue))) null - else AP.just(true) - } - } - - data class Dropping(val capacity: Int, val AP: Applicative) : SurplusStrategy() { - override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? { - val nextQueue = if (surplus.value.length() < capacity) surplus.value.enqueue(a) else surplus.value - return if (!state.compareAndSet(surplus, surplus.copy(value = nextQueue))) null - else AP.just(true) - } - } - - data class Unbounded(val AP: Applicative) : SurplusStrategy() { - override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? = - if (!state.compareAndSet(surplus, surplus.copy(value = surplus.value.enqueue(a)))) null - else AP.just(true) - } - } -} +@Deprecated("Renaming this api for consistency", ReplaceWith("CancellableQueue")) +typealias CancelableQueue = CancellableQueue diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableMVar.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableMVar.kt similarity index 92% rename from arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableMVar.kt rename to arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableMVar.kt index 1336b7251..ad88f3c73 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelableMVar.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableMVar.kt @@ -9,8 +9,8 @@ import arrow.core.Some import arrow.core.Tuple2 import arrow.fx.MVar -import arrow.fx.internal.CancelableMVar.Companion.State.WaitForPut -import arrow.fx.internal.CancelableMVar.Companion.State.WaitForTake +import arrow.fx.internal.CancellableMVar.Companion.State.WaitForPut +import arrow.fx.internal.CancellableMVar.Companion.State.WaitForTake import arrow.fx.typeclasses.CancelToken import arrow.fx.typeclasses.Concurrent import arrow.fx.typeclasses.Fiber @@ -19,19 +19,19 @@ import arrow.fx.typeclasses.rightUnit import kotlinx.atomicfu.atomic import kotlin.coroutines.EmptyCoroutineContext -internal class CancelableMVar private constructor(initial: State, private val CF: Concurrent) : MVar, Concurrent by CF { +internal class CancellableMVar private constructor(initial: State, private val CF: Concurrent) : MVar, Concurrent by CF { private val state = atomic(initial) companion object { - /** Builds an [UncancelableMVar] instance with an [initial] value. */ + /** Builds an [UncancellableMVar] instance with an [initial] value. */ operator fun invoke(initial: A, CF: Concurrent): Kind> = CF.later { - CancelableMVar(State(initial), CF) + CancellableMVar(State(initial), CF) } - /** Returns an empty [UncancelableMVar] instance. */ + /** Returns an empty [UncancellableMVar] instance. */ fun empty(CF: Concurrent): Kind> = CF.later { - CancelableMVar(State.empty(), CF) + CancellableMVar(State.empty(), CF) } internal sealed class State { @@ -63,7 +63,7 @@ internal class CancelableMVar private constructor(initial: State, priva override fun put(a: A): Kind = tryPut(a).flatMap { didPut -> - if (didPut) unit() else cancelableF { cb -> unsafePut(a, cb) } + if (didPut) unit() else cancellableF { cb -> unsafePut(a, cb) } } override fun tryPut(a: A): Kind = @@ -71,14 +71,14 @@ internal class CancelableMVar private constructor(initial: State, priva override fun take(): Kind = tryTake().flatMap { - it.fold({ cancelableF(::unsafeTake) }, ::just) + it.fold({ cancellableF(::unsafeTake) }, ::just) } override fun tryTake(): Kind> = defer { unsafeTryTake() } override fun read(): Kind = - cancelable(::unsafeRead) + cancellable(::unsafeRead) private tailrec fun unsafeTryPut(a: A): Kind = when (val current = state.value) { diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelablePromise.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellablePromise.kt similarity index 92% rename from arrow-fx/src/main/kotlin/arrow/fx/internal/CancelablePromise.kt rename to arrow-fx/src/main/kotlin/arrow/fx/internal/CancellablePromise.kt index e6a143664..cae12e0ac 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancelablePromise.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellablePromise.kt @@ -8,9 +8,9 @@ import arrow.core.Option import arrow.core.Right import arrow.core.Some import arrow.fx.Promise -import arrow.fx.internal.CancelablePromise.State.Complete -import arrow.fx.internal.CancelablePromise.State.Error -import arrow.fx.internal.CancelablePromise.State.Pending +import arrow.fx.internal.CancellablePromise.State.Complete +import arrow.fx.internal.CancellablePromise.State.Error +import arrow.fx.internal.CancellablePromise.State.Pending import arrow.fx.typeclasses.Concurrent import arrow.fx.typeclasses.Fiber import arrow.fx.typeclasses.mapUnit @@ -18,7 +18,7 @@ import kotlinx.atomicfu.AtomicRef import kotlinx.atomicfu.atomic import kotlin.coroutines.EmptyCoroutineContext -internal class CancelablePromise(private val CF: Concurrent) : Promise, Concurrent by CF { +internal class CancellablePromise(private val CF: Concurrent) : Promise, Concurrent by CF { internal sealed class State { data class Pending(val joiners: Map) -> Unit>) : State() @@ -31,7 +31,7 @@ internal class CancelablePromise(private val CF: Concurrent) : Promise< override fun get(): Kind = defer { when (val current = state.value) { is State.Complete -> just(current.value) - is State.Pending -> cancelable { cb -> + is State.Pending -> cancellable { cb -> val id = unsafeRegister(cb) later { unregister(id) } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableQueue.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableQueue.kt new file mode 100644 index 000000000..29a42ca5f --- /dev/null +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/CancellableQueue.kt @@ -0,0 +1,366 @@ +package arrow.fx.internal + +import arrow.Kind +import arrow.core.Either +import arrow.core.None +import arrow.core.Option +import arrow.core.Right +import arrow.core.Some +import arrow.core.Tuple2 +import arrow.core.internal.AtomicRefW +import arrow.core.left + +import arrow.fx.Queue +import arrow.fx.QueueShutdown +import arrow.fx.typeclasses.CancelToken +import arrow.fx.typeclasses.Concurrent +import arrow.fx.typeclasses.Fiber +import arrow.fx.typeclasses.mapUnit +import arrow.fx.typeclasses.rightUnit +import arrow.typeclasses.Applicative +import kotlin.coroutines.EmptyCoroutineContext + +class CancellableQueue internal constructor( + initial: State?, + private val strategy: SurplusStrategy, + private val CF: Concurrent +) : Concurrent by CF, Queue { + + private val state: AtomicRefW> = AtomicRefW(initial ?: State.empty()) + + companion object { + operator fun invoke(initial: List, CF: Concurrent): Kind> = CF.later { + CancellableQueue(State.Surplus(IQueue(initial), linkedMapOf(), linkedMapOf()), SurplusStrategy.Unbounded(CF), CF) + } + + /** Returns an empty [UncancellableMVar] instance. */ + fun empty(CF: Concurrent): Kind> = CF.later { + CancellableQueue(null, SurplusStrategy.Unbounded(CF), CF) + } + + internal sealed class State { + data class Deficit( + val reads: Map) -> Unit>, + val takes: Map) -> Unit>, + val shutdownHook: Map) -> Unit> + ) : State() + + data class Surplus( + val value: IQueue, + val offers: Map) -> Unit>>, + val shutdownHook: Map) -> Unit> + ) : State() + + object Shutdown : State() + + companion object { + private val empty: State.Deficit = State.Deficit(linkedMapOf(), linkedMapOf(), linkedMapOf()) + fun empty(): State.Deficit = empty as State.Deficit + fun shutdown(): State = + Shutdown as State + } + } + } + + override fun offer(a: A): Kind = + tryOffer(a).flatMap { didPut -> + if (didPut) unit() else cancellableF { cb -> unsafeOffer(a, cb) } + } + + override fun shutdown(): Kind = + defer { unsafeShutdown() } + + override fun size(): Kind = defer { + when (val curr = state.value) { + is State.Deficit -> just(-curr.takes.size) + is State.Surplus -> just(1 + curr.offers.size) + State.Shutdown -> raiseError(QueueShutdown) + } + } + + fun isEmpty(): Kind = + size().map { it == 0 } + + fun isNotEmpty(): Kind = + isEmpty().map(Boolean::not) + + override fun awaitShutdown(): Kind = + CF.cancellableF(::unsafeRegisterAwaitShutdown) + + fun tryOffer(a: A): Kind = + defer { unsafeTryOffer(a) } + + override fun take(): Kind = + tryTake().flatMap { + it.fold({ cancellableF(::unsafeTake) }, ::just) + } + + fun tryTake(): Kind> = + defer { unsafeTryTake() } + + fun read(): Kind = + cancellable(::unsafeRead) + + private tailrec fun unsafeTryOffer(a: A): Kind = + when (val current = state.value) { + is State.Surplus -> strategy.unsafeTryHandleSurplus(state, a, current) ?: unsafeTryOffer(a) + is State.Deficit -> { + val firstTake = current.takes.values.firstOrNull() + + val update: State = if (firstTake == null) State.Surplus(IQueue(a), linkedMapOf(), current.shutdownHook) else { + val rest = current.takes.toList().drop(1) + if (rest.isEmpty()) current.copy(linkedMapOf(), linkedMapOf()) + else State.Deficit(emptyMap(), rest.toMap(), current.shutdownHook) + } + + if (!state.compareAndSet(current, update)) { + unsafeTryOffer(a) + } else if (firstTake != null || current.reads.isNotEmpty()) { + callPutAndAllReaders(a, firstTake, current.reads) + } else just(true) + } + is State.Shutdown -> raiseError(QueueShutdown) + } + + private tailrec fun unsafeRegisterAwaitShutdown(shutdown: (Either) -> Unit): Kind> = + when (val curr = state.value) { + is State.Deficit -> { + val token = Token() + val newShutdowns = curr.shutdownHook + Pair(token, shutdown) + if (state.compareAndSet(curr, curr.copy(shutdownHook = newShutdowns))) just(later { unsafeCancelAwaitShutdown(token) }) + else unsafeRegisterAwaitShutdown(shutdown) + } + is State.Surplus -> { + val token = Token() + val newShutdowns = curr.shutdownHook + Pair(token, shutdown) + if (state.compareAndSet(curr, curr.copy(shutdownHook = newShutdowns))) just(later { unsafeCancelAwaitShutdown(token) }) + else unsafeRegisterAwaitShutdown(shutdown) + } + State.Shutdown -> { + shutdown(rightUnit) + just(CF.unit()) + } + } + + private tailrec fun unsafeOffer(a: A, onPut: (Either) -> Unit): Kind> = + when (val current = state.value) { + is State.Surplus -> { + val id = Token() + val newMap = current.offers + Pair(id, Tuple2(a, onPut)) + if (state.compareAndSet(current, State.Surplus(current.value, newMap, current.shutdownHook))) just(later { unsafeCancelOffer(id) }) + else unsafeOffer(a, onPut) + } + is State.Deficit -> { + val first = current.takes.values.firstOrNull() + val update = if (current.takes.isEmpty()) State.Surplus(IQueue(a), linkedMapOf(), current.shutdownHook) else { + val rest = current.takes.toList().drop(1) + if (rest.isEmpty()) current.copy(linkedMapOf(), linkedMapOf()) + else State.Deficit(emptyMap(), rest.toMap(), current.shutdownHook) + } + + if (state.compareAndSet(current, update)) { + if (first != null || current.reads.isNotEmpty()) callPutAndAllReaders(a, first, current.reads).map { + onPut(rightUnit) + unit() + } else { + onPut(rightUnit) + just(unit()) + } + } else unsafeOffer(a, onPut) + } + is State.Shutdown -> { + onPut(Either.Left(QueueShutdown)) + just(unit()) + } + } + + private tailrec fun unsafeShutdown(): Kind = + when (val current = state.value) { + is State.Shutdown -> raiseError(QueueShutdown) + is State.Surplus -> + if (state.compareAndSet(current, State.shutdown())) later { + current.offers.values.forEach { (_, cb) -> cb(QueueShutdown.left()) } + current.shutdownHook.values.forEach { cb -> cb(rightUnit) } + } else unsafeShutdown() + is State.Deficit -> + if (state.compareAndSet(current, State.shutdown())) later { + current.takes.forEach { (_, cb) -> cb(QueueShutdown.left()) } + current.reads.forEach { (_, cb) -> cb(QueueShutdown.left()) } + current.shutdownHook.values.forEach { cb -> cb(rightUnit) } + } else unsafeShutdown() + } + + private tailrec fun unsafeCancelAwaitShutdown(id: Token): Unit = + when (val curr = state.value) { + is State.Deficit -> { + val update = curr.copy(shutdownHook = curr.shutdownHook - id) + if (state.compareAndSet(curr, update)) Unit + else unsafeCancelAwaitShutdown(id) + } + is State.Surplus -> { + val update = curr.copy(shutdownHook = curr.shutdownHook - id) + if (state.compareAndSet(curr, update)) Unit + else unsafeCancelAwaitShutdown(id) + } + else -> Unit + } + + private tailrec fun unsafeCancelOffer(id: Token): Unit = + when (val current = state.value) { + is State.Surplus -> { + val update = current.copy(offers = current.offers - id) + if (state.compareAndSet(current, update)) Unit + else unsafeCancelOffer(id) + } + else -> Unit + } + + private tailrec fun unsafeTryTake(): Kind> = + when (val current = state.value) { + is State.Surplus -> { + val (head, tail) = current.value.dequeue() + if (current.offers.isEmpty()) { + val update = if (tail.isEmpty()) State.empty().copy(shutdownHook = current.shutdownHook) else current.copy(value = tail) + if (state.compareAndSet(current, update)) just(Some(head)) + else unsafeTryTake() + } else { + val (ax, notify) = current.offers.values.first() + val xs = current.offers.toList().drop(1) + // TODO ADD STRATEGY + if (state.compareAndSet(current, State.Surplus(tail.enqueue(ax), xs.toMap(), current.shutdownHook))) later { notify(rightUnit) }.fork(EmptyCoroutineContext).map { Some(head) } + else unsafeTryTake() + } + } + is State.Deficit -> just(None) + is State.Shutdown -> just(None) + } + + private tailrec fun unsafeTake(onTake: (Either) -> Unit): Kind> = + when (val current = state.value) { + is State.Surplus -> { + val (head, tail) = current.value.dequeue() + if (current.offers.isEmpty()) { + val update = if (tail.isEmpty()) State.empty().copy(shutdownHook = current.shutdownHook) else current.copy(value = tail) + if (state.compareAndSet(current, update)) { + onTake(Right(head)) + just(unit()) + } else { + unsafeTake(onTake) + } + } else { + val (ax, notify) = current.offers.values.first() + val xs = current.offers.toList().drop(0) // TODO ADD STRATEGY + if (state.compareAndSet(current, State.Surplus(tail.enqueue(ax), xs.toMap(), current.shutdownHook))) { + later { notify(rightUnit) }.fork(EmptyCoroutineContext).map { + onTake(Either.Right(head)) + unit() + } + } else unsafeTake(onTake) + } + } + is State.Deficit -> { + val id = Token() + val newQueue = current.takes + Pair(id, onTake) + if (state.compareAndSet(current, State.Deficit(current.reads, newQueue, current.shutdownHook))) just(later { unsafeCancelTake(id) }) + else unsafeTake(onTake) + } + is State.Shutdown -> { + onTake(Either.Left(QueueShutdown)) + just(unit()) + } + } + + private tailrec fun unsafeCancelTake(id: Token): Unit = + when (val current = state.value) { + is State.Deficit -> { + val newMap = current.takes - id + val update = State.Deficit(current.reads, newMap, current.shutdownHook) + if (state.compareAndSet(current, update)) Unit + else unsafeCancelTake(id) + } + else -> Unit + } + + private tailrec fun unsafeRead(onRead: (Either) -> Unit): Kind = + when (val current = state.value) { + is State.Surplus -> { + onRead(Right(current.value.head())) + unit() + } + is State.Deficit -> { + val id = Token() + val newReads = current.reads + Pair(id, onRead) + if (state.compareAndSet(current, State.Deficit(newReads, current.takes, current.shutdownHook))) later { unsafeCancelRead(id) } + else unsafeRead(onRead) + } + is State.Shutdown -> raiseError(QueueShutdown) + } + + private tailrec fun unsafeCancelRead(id: Token): Unit = + when (val current = state.value) { + is State.Deficit -> { + val newMap = current.reads - id + val update = State.Deficit(newMap, current.takes, current.shutdownHook) + if (state.compareAndSet(current, update)) Unit + else unsafeCancelRead(id) + } + else -> Unit + } + + private fun callPutAndAllReaders(a: A, put: ((Either) -> Unit)?, reads: Map) -> Unit>): Kind { + val value = Right(a) + return reads.values.callAll(value).flatMap { + if (put != null) later { put(value) }.fork(EmptyCoroutineContext).map { true } + else just(true) + } + } + + // For streaming a value to a whole `reads` collection + private fun Iterable<(Either) -> Unit>.callAll(value: Either): Kind = + fold(null as Kind>?) { acc, cb -> + val task = later { cb(value) }.fork(EmptyCoroutineContext) + acc?.flatMap { task } ?: task + }?.map(mapUnit) ?: unit() + + override fun Kind.ap(ff: Kind B>): Kind = CF.run { + this@ap.ap(ff) + } + + override fun Kind.map(f: (A) -> B): Kind = CF.run { + this@map.map(f) + } + + internal sealed class SurplusStrategy { + abstract fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? + + data class Bounded(val capacity: Int, val AP: Applicative) : SurplusStrategy() { + override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? = when { + surplus.value.length() >= capacity -> AP.just(false) + state.compareAndSet(surplus, surplus.copy(surplus.value.enqueue(a))) -> AP.just(true) + else -> null + } + } + + data class Sliding(val capacity: Int, val AP: Applicative) : SurplusStrategy() { + override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? { + val nextQueue = if (surplus.value.length() < capacity) surplus.value.enqueue(a) else surplus.value.dequeue().b.enqueue(a) + return if (!state.compareAndSet(surplus, surplus.copy(value = nextQueue))) null + else AP.just(true) + } + } + + data class Dropping(val capacity: Int, val AP: Applicative) : SurplusStrategy() { + override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? { + val nextQueue = if (surplus.value.length() < capacity) surplus.value.enqueue(a) else surplus.value + return if (!state.compareAndSet(surplus, surplus.copy(value = nextQueue))) null + else AP.just(true) + } + } + + data class Unbounded(val AP: Applicative) : SurplusStrategy() { + override fun unsafeTryHandleSurplus(state: AtomicRefW>, a: A, surplus: State.Surplus): Kind? = + if (!state.compareAndSet(surplus, surplus.copy(value = surplus.value.enqueue(a)))) null + else AP.just(true) + } + } +} diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/ConcurrentSleep.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/ConcurrentSleep.kt index 009cc4cfe..272048346 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/ConcurrentSleep.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/ConcurrentSleep.kt @@ -12,7 +12,7 @@ import kotlin.coroutines.Continuation import kotlin.coroutines.CoroutineContext import kotlin.coroutines.startCoroutine -internal fun Concurrent.ConcurrentSleep(duration: Duration): Kind = cancelable { cb -> +internal fun Concurrent.ConcurrentSleep(duration: Duration): Kind = cancellable { cb -> val cancelRef = scheduler.schedule(ShiftTick(dispatchers().default(), cb), duration.amount, duration.timeUnit) later { cancelRef.cancel(false); Unit } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancelable.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancellable.kt similarity index 87% rename from arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancelable.kt rename to arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancellable.kt index ae938b698..63b6e7aca 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancelable.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/ForwardCancellable.kt @@ -2,14 +2,13 @@ package arrow.fx.internal import arrow.core.Either import arrow.core.NonFatal - import arrow.fx.ForIO import arrow.fx.IO import arrow.fx.IOConnection import arrow.fx.IORunLoop import arrow.fx.fix -import arrow.fx.internal.ForwardCancelable.Companion.State.Active -import arrow.fx.internal.ForwardCancelable.Companion.State.Empty +import arrow.fx.internal.ForwardCancellable.Companion.State.Active +import arrow.fx.internal.ForwardCancellable.Companion.State.Empty import arrow.fx.typeclasses.CancelToken import kotlinx.atomicfu.atomic @@ -17,19 +16,19 @@ import kotlinx.atomicfu.atomic * A placeholder for a [CancelToken] that will be set at a later time, the equivalent of a * `Promise>`. Used in the implementation of `bracket`, see [IOBracket]. */ -internal class ForwardCancelable { +internal class ForwardCancellable { private val state = atomic(init) fun cancel(): CancelToken { fun loop(conn: IOConnection, cb: (Either) -> Unit): Unit = state.value.let { current -> when (current) { - is State.Empty -> if (!state.compareAndSet(current, State.Empty(listOf(cb) + current.stack))) + is Empty -> if (!state.compareAndSet(current, Empty(listOf(cb) + current.stack))) loop(conn, cb) is Active -> { state.lazySet(finished) // GC purposes - Platform.trampoline { IORunLoop.startCancelable(current.token, conn, cb) } + Platform.trampoline { IORunLoop.startCancellable(current.token, conn, cb) } } } } @@ -59,7 +58,7 @@ internal class ForwardCancelable { companion object { /** - * Models the internal state of [ForwardCancelable]: + * Models the internal state of [ForwardCancellable]: * * - on start, the state is [Empty] of `Nil`, aka [init] * - on `cancel`, if no token was assigned yet, then the state will diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/IOBracket.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/IOBracket.kt index f9cb5541e..cf92a08df 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/IOBracket.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/IOBracket.kt @@ -21,14 +21,14 @@ internal object IOBracket { operator fun invoke(acquire: IOOf, release: (A, ExitCase) -> IOOf, use: (A) -> IOOf): IO = IO.Async { conn, cb -> // Placeholder for the future finalizer - val deferredRelease = ForwardCancelable() + val deferredRelease = ForwardCancellable() conn.push(deferredRelease.cancel()) // Race-condition check, avoiding starting the bracket if the connection // was cancelled already, to ensure that `cancel` really blocks if we - // start `acquire` — n.b. `isCanceled` is visible here due to `push` - if (!conn.isCanceled()) { - // Note `acquire` is uncancelable due to usage of `IORunLoop.start` + // start `acquire` — n.b. `isCancelled` is visible here due to `push` + if (!conn.isCancelled()) { + // Note `acquire` is uncancellable due to usage of `IORunLoop.start` // (in other words it is disconnected from our IOConnection) IORunLoop.start(acquire, BracketStart(use, release, conn, deferredRelease, cb)) } else { @@ -41,7 +41,7 @@ internal object IOBracket { val use: (A) -> IOOf, val release: (A, ExitCase) -> IOOf, val conn: IOConnection, - val deferredRelease: ForwardCancelable, + val deferredRelease: ForwardCancellable, val cb: (Either) -> Unit ) : (Either) -> Unit { @@ -68,10 +68,10 @@ internal object IOBracket { IO.Bind(fb.fix(), frame) } - // Registering our cancelable token ensures that in case cancellation is detected, release gets called + // Registering our cancellable token ensures that in case cancellation is detected, release gets called deferredRelease.complete(frame.cancel) // Actual execution - IORunLoop.startCancelable(onNext(), conn, cb) + IORunLoop.startCancellable(onNext(), conn, cb) } is Either.Left -> cb(ea) } @@ -84,14 +84,14 @@ internal object IOBracket { Platform.trampoline { val frame = EnsureReleaseFrame(release) val onNext = IO.Bind(source, frame) - // Registering our cancelable token ensures that in case + // Registering our cancellable token ensures that in case // cancellation is detected, `release` gets called conn.push(frame.cancel) // Race condition check, avoiding starting `source` in case // the connection was already cancelled — n.b. we don't need // to trigger `release` otherwise, because it already happened - if (!conn.isCanceled()) IORunLoop.startCancelable(onNext, conn, cb) + if (!conn.isCancelled()) IORunLoop.startCancellable(onNext, conn, cb) } } @@ -123,19 +123,19 @@ internal object IOBracket { IO.unit } - val cancel: CancelToken = applyRelease(ExitCase.Canceled).fix().uncancelable() + val cancel: CancelToken = applyRelease(ExitCase.Cancelled).fix().uncancellable() // Unregistering cancel token, otherwise we can have a memory leak; // N.B. conn.pop() happens after the evaluation of `release`, because // otherwise we might have a conflict with the auto-cancellation logic - override fun recover(e: Throwable): IO = IO.ContextSwitch(applyRelease(ExitCase.Error(e)), IO.ContextSwitch.makeUncancelable, disableUncancelableAndPop) + override fun recover(e: Throwable): IO = IO.ContextSwitch(applyRelease(ExitCase.Error(e)), IO.ContextSwitch.makeUncancellable, disableUncancellableAndPop) .flatMap(ReleaseRecover(e)) override operator fun invoke(a: B): IO = // Unregistering cancel token, otherwise we can have a memory leak // N.B. conn.pop() happens after the evaluation of `release`, because // otherwise we might have a conflict with the auto-cancellation logic - IO.ContextSwitch(applyRelease(ExitCase.Completed), IO.ContextSwitch.makeUncancelable, disableUncancelableAndPop) + IO.ContextSwitch(applyRelease(ExitCase.Completed), IO.ContextSwitch.makeUncancellable, disableUncancellableAndPop) .map { a } } @@ -147,7 +147,7 @@ internal object IOBracket { override fun invoke(a: Unit): IO = IO.raiseError(error) } - private val disableUncancelableAndPop: (Any?, Throwable?, IOConnection, IOConnection) -> IOConnection = + private val disableUncancellableAndPop: (Any?, Throwable?, IOConnection, IOConnection) -> IOConnection = { _, _, old, _ -> old.pop() old diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelableMVar.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellableMVar.kt similarity index 91% rename from arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelableMVar.kt rename to arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellableMVar.kt index c2d971b01..d64261b26 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelableMVar.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellableMVar.kt @@ -8,8 +8,8 @@ import arrow.core.Right import arrow.core.Some import arrow.core.Tuple2 import arrow.fx.MVar -import arrow.fx.internal.UncancelableMVar.Companion.State.WaitForPut -import arrow.fx.internal.UncancelableMVar.Companion.State.WaitForTake +import arrow.fx.internal.UncancellableMVar.Companion.State.WaitForPut +import arrow.fx.internal.UncancellableMVar.Companion.State.WaitForTake import arrow.fx.typeclasses.Async import arrow.fx.typeclasses.rightUnit import arrow.fx.typeclasses.unitCallback @@ -17,7 +17,7 @@ import kotlinx.atomicfu.atomic // [MVar] implementation for [Async] data types. @Suppress("DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") -internal class UncancelableMVar private constructor(initial: State, private val AS: Async) : MVar, Async by AS { +internal class UncancellableMVar private constructor(initial: State, private val AS: Async) : MVar, Async by AS { private val stateRef = atomic(initial) @@ -193,14 +193,14 @@ internal class UncancelableMVar private constructor(initial: State, pri private val asyncBoundary = async(unitCallback) companion object { - /** Builds an [UncancelableMVar] instance with an [initial] value. */ + /** Builds an [UncancellableMVar] instance with an [initial] value. */ operator fun invoke(initial: A, AS: Async): Kind> = AS.later { - UncancelableMVar(State(initial), AS) + UncancellableMVar(State(initial), AS) } - /** Returns an empty [UncancelableMVar] instance. */ + /** Returns an empty [UncancellableMVar] instance. */ fun empty(AS: Async): Kind> = AS.later { - UncancelableMVar(State.empty(), AS) + UncancellableMVar(State.empty(), AS) } /** Internal state of [MVar]. */ @@ -214,7 +214,7 @@ internal class UncancelableMVar private constructor(initial: State, pri } /** - * [UncancelableMVar] state signaling it has [take] callbacks registered + * [UncancellableMVar] state signaling it has [take] callbacks registered * and we are waiting for one or multiple [put] operations. * * @param takes are the rest of the requests waiting in line, @@ -223,7 +223,7 @@ internal class UncancelableMVar private constructor(initial: State, pri class WaitForPut(val reads: IQueue>, val takes: IQueue>) : State() /** - * [UncancelableMVar] state signaling it has one or more values enqueued, + * [UncancellableMVar] state signaling it has one or more values enqueued, * to be signaled on the next [take]. * * @param value is the first value to signal diff --git a/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelablePromise.kt b/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellablePromise.kt similarity index 96% rename from arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelablePromise.kt rename to arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellablePromise.kt index 495527da5..f42c393c0 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancelablePromise.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/internal/UncancellablePromise.kt @@ -12,7 +12,7 @@ import arrow.fx.typeclasses.Async import kotlinx.atomicfu.AtomicRef import kotlinx.atomicfu.atomic -internal class UncancelablePromise(private val AS: Async) : Promise, Async by AS { +internal class UncancellablePromise(private val AS: Async) : Promise, Async by AS { internal sealed class State { data class Pending(val joiners: List<(Either) -> Unit>) : State() diff --git a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Async.kt b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Async.kt index e764261d7..0b053f723 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Async.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Async.kt @@ -96,7 +96,7 @@ interface Async : MonadDefer { * //sampleStart * fun Async.makeCompleteAndGetPromiseInAsync() = * asyncF { cb: (Either) -> Unit -> - * Promise.uncancelable(this).flatMap { promise -> + * Promise.uncancellable(this).flatMap { promise -> * promise.complete("Hello World!").flatMap { * promise.get().map { str -> cb(Right(str)) } * } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Bracket.kt b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Bracket.kt index 6efc50418..f649cc478 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Bracket.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Bracket.kt @@ -12,8 +12,8 @@ sealed class ExitCase { override fun toString() = "ExitCase.Completed" } - object Canceled : ExitCase() { - override fun toString() = "ExitCase.Canceled" + object Cancelled : ExitCase() { + override fun toString() = "ExitCase.Cancelled" } data class Error(val e: E) : ExitCase() @@ -64,7 +64,7 @@ interface Bracket : MonadError { * val release: (File, ExitCase) -> Kind = { file, exitCase -> * when (exitCase) { * is ExitCase.Completed -> { /* do something */ } - * is ExitCase.Canceled -> { /* do something */ } + * is ExitCase.Cancelled -> { /* do something */ } * is ExitCase.Error -> { /* do something */ } * } * closeFile(file) @@ -116,11 +116,15 @@ interface Bracket : MonadError { /** * Meant for ensuring a given task continues execution even when interrupted. */ - fun Kind.uncancelable(): Kind = + fun Kind.uncancellable(): Kind = bracket({ just(Unit) }, { just(it) }) + @Deprecated("Renaming this api for consistency", ReplaceWith("uncancellable()")) + fun Kind.uncancelable(): Kind = + uncancellable() + /** - * Executes the given `finalizer` when the source is finished, either in success or in error, or if canceled. + * Executes the given `finalizer` when the source is finished, either in success or in error, or if cancelled. * * As best practice, it's not a good idea to release resources via `guaranteeCase` in polymorphic code. * Prefer [bracket] for the acquisition and release of resources. @@ -133,7 +137,7 @@ interface Bracket : MonadError { guaranteeCase { finalizer } /** - * Executes the given `finalizer` when the source is finished, either in success or in error, or if canceled, allowing + * Executes the given `finalizer` when the source is finished, either in success or in error, or if cancelled, allowing * for differentiating between exit conditions. That's thanks to the [ExitCase] argument of the finalizer. * * As best practice, it's not a good idea to release resources via `guaranteeCase` in polymorphic code. @@ -148,14 +152,14 @@ interface Bracket : MonadError { just(Unit).bracketCase({ _, e -> finalizer(e) }, { this }) /** - * Executes the given [finalizer] when the source is canceled, allowing registering a cancellation token. + * Executes the given [finalizer] when the source is cancelled, allowing registering a cancellation token. * * Useful for wiring cancellation tokens between fibers, building inter-op with other effect systems or testing. */ fun Kind.onCancel(finalizer: Kind): Kind = guaranteeCase { case -> when (case) { - ExitCase.Canceled -> finalizer + ExitCase.Cancelled -> finalizer else -> just(Unit) } } diff --git a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Concurrent.kt b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Concurrent.kt index d75f9f836..36434750b 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Concurrent.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Concurrent.kt @@ -40,7 +40,7 @@ typealias CancelToken = Kind /** * ank_macro_hierarchy(arrow.fx.typeclasses.Concurrent) * - * Type class for async data types that are cancelable and can be started concurrently. + * Type class for async data types that are cancellable and can be started concurrently. */ interface Concurrent : Async { @@ -179,7 +179,7 @@ interface Concurrent : Async { fun CoroutineContext.raceTriple(fa: Kind, fb: Kind, fc: Kind): Kind> /** - * Creates a cancelable [F] instance that executes an asynchronous process on evaluation. + * Creates a cancellable [F] instance that executes an asynchronous process on evaluation. * Derived from [async] and [bracketCase]. * * ```kotlin:ank:playground:extension @@ -206,7 +206,7 @@ interface Concurrent : Async { * } * * fun cancel(): Unit = kotlinx.coroutines.runBlocking { - * println("Canceled, closing NetworkApi") + * println("Cancelled, closing NetworkApi") * kotlinx.coroutines.delay(500) * println("Closed NetworkApi") * } @@ -215,7 +215,7 @@ interface Concurrent : Async { * fun main(args: Array) { * //sampleStart * val getAccounts = Default._shift_().flatMap { - * _extensionFactory_.cancelable> { cb -> + * _extensionFactory_.cancellable> { cb -> * val service = NetworkService() * service.getAccounts( * successCallback = { accs -> cb(Right(accs)) }, @@ -228,16 +228,20 @@ interface Concurrent : Async { * //sampleEnd * } * ``` - * @see cancelableF for a version that can safely suspend impure callback registration code. + * @see cancellableF for a version that can safely suspend impure callback registration code. */ - fun cancelable(k: ((Either) -> Unit) -> CancelToken): Kind = - cancelableF { cb -> + fun cancellable(k: ((Either) -> Unit) -> CancelToken): Kind = + cancellableF { cb -> val token = k(cb) later { token } } + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(k))")) + fun cancelable(k: ((Either) -> Unit) -> CancelToken): Kind = + cancellable(k) + /** - * Builder to create a cancelable [F] instance that executes an asynchronous process on evaluation. + * Builder to create a cancellable [F] instance that executes an asynchronous process on evaluation. * Function derived from [async] and [bracketCase]. * * ```kotlin:ank:playground:extension @@ -247,7 +251,7 @@ interface Concurrent : Async { * * fun main(args: Array) { * //sampleStart - * val result = _extensionFactory_.cancelableF { cb -> + * val result = _extensionFactory_.cancellableF { cb -> * effect { * val deferred = kotlinx.coroutines.GlobalScope.async { * kotlinx.coroutines.delay(1000) @@ -260,7 +264,7 @@ interface Concurrent : Async { * * println(result) //Run with `fix().unsafeRunSync()` * - * val result2 = _extensionFactory_.cancelableF { cb -> + * val result2 = _extensionFactory_.cancellableF { cb -> * effect { * println("Doing something that can be cancelled.") * effect { println("Cancelling the task") } @@ -272,9 +276,9 @@ interface Concurrent : Async { * } * ``` * - * @see cancelable for a simpler non-suspending version. + * @see cancellable for a simpler non-suspending version. */ - fun cancelableF(k: ((Either) -> Unit) -> Kind>): Kind = + fun cancellableF(k: ((Either) -> Unit) -> Kind>): Kind = asyncF { cb -> val state = AtomicRefW<((Either) -> Unit)?>(null) val cb1 = { r: Either -> @@ -297,12 +301,16 @@ interface Concurrent : Async { } }, release = { token, exitCase -> when (exitCase) { - is ExitCase.Canceled -> token + is ExitCase.Cancelled -> token else -> just(Unit) } }) } + @Deprecated("Renaming this api for consistency", ReplaceWith("cancellable(k)")) + fun cancelableF(k: ((Either) -> Unit) -> Kind>): Kind = + cancellableF(k) + /** * Given a function which returns an [F] effect, run this effect in parallel for all the values in [G]. * @@ -583,7 +591,7 @@ interface Concurrent : Async { * * fun main(args: Array) { * fun Concurrent.example(): Kind { - * val never: Kind = cancelable { effect { println("Never got canelled for losing.") } } + * val never: Kind = cancellable { effect { println("Never got cancelled for losing.") } } * * //sampleStart * val result = fx.concurrent { diff --git a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Fiber.kt b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Fiber.kt index a4f22265a..605a329cb 100644 --- a/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Fiber.kt +++ b/arrow-fx/src/main/kotlin/arrow/fx/typeclasses/Fiber.kt @@ -6,7 +6,7 @@ import arrow.higherkind /** * [Fiber] represents the pure result of an [Async] data type - * being started concurrently and that can be either joined or canceled. + * being started concurrently and that can be either joined or cancelled. * * You can think of fibers as being lightweight threads, a Fiber being a * concurrency primitive for doing cooperative multi-tasking. diff --git a/arrow-fx/src/test/kotlin/arrow/fx/IOTest.kt b/arrow-fx/src/test/kotlin/arrow/fx/IOTest.kt index 8f377651e..a6e56b463 100644 --- a/arrow-fx/src/test/kotlin/arrow/fx/IOTest.kt +++ b/arrow-fx/src/test/kotlin/arrow/fx/IOTest.kt @@ -108,8 +108,8 @@ class IOTest : UnitSpec() { } } - "should return immediate value by uncancelable" { - val run = just(1).uncancelable().unsafeRunSync() + "should return immediate value by uncancellable" { + val run = just(1).uncancellable().unsafeRunSync() val expected = 1 @@ -196,7 +196,7 @@ class IOTest : UnitSpec() { } } - "should rethrow exceptions within run block with unsafeRunAsyncCancelable" { + "should rethrow exceptions within run block with unsafeRunAsyncCancellable" { try { val exception = MyException() val ioa = IO { throw exception } @@ -504,7 +504,7 @@ class IOTest : UnitSpec() { } "IO bracket cancellation should release resource with cancel exit status" { - Promise.uncancelable>(IO.async()).flatMap { p -> + Promise.uncancellable>(IO.async()).flatMap { p -> just(0L) .bracketCase( use = { IO.never }, @@ -514,12 +514,12 @@ class IOTest : UnitSpec() { .invoke() // cancel immediately p.get() - }.unsafeRunSync() shouldBe ExitCase.Canceled + }.unsafeRunSync() shouldBe ExitCase.Cancelled } - "Cancelable should run CancelToken" { - Promise.uncancelable(IO.async()).flatMap { p -> - IO.concurrent().cancelable { + "Cancellable should run CancelToken" { + Promise.uncancellable(IO.async()).flatMap { p -> + IO.concurrent().cancellable { p.complete(Unit) }.fix() .unsafeRunAsyncCancellable { } @@ -529,9 +529,9 @@ class IOTest : UnitSpec() { }.unsafeRunSync() shouldBe Unit } - "CancelableF should run CancelToken" { - Promise.uncancelable(IO.async()).flatMap { p -> - IO.concurrent().cancelableF { + "CancellableF should run CancelToken" { + Promise.uncancellable(IO.async()).flatMap { p -> + IO.concurrent().cancellableF { IO { p.complete(Unit) } }.fix() .unsafeRunAsyncCancellable { } @@ -541,10 +541,10 @@ class IOTest : UnitSpec() { }.unsafeRunSync() shouldBe Unit } - "IO should cancel cancelable on dispose" { - Promise.uncancelable(IO.async()).flatMap { latch -> + "IO should cancel cancellable on dispose" { + Promise.uncancellable(IO.async()).flatMap { latch -> IO { - IO.cancelable { + IO.cancellable { latch.complete(Unit) }.unsafeRunAsyncCancellable { } .invoke() @@ -690,7 +690,7 @@ class IOTest : UnitSpec() { !sleep(100.milliseconds) !cancel val result = !p.get() - !effect { result shouldBe ExitCase.Canceled } + !effect { result shouldBe ExitCase.Cancelled } }.suspended() } } diff --git a/arrow-fx/src/test/kotlin/arrow/fx/KindConnectionTests.kt b/arrow-fx/src/test/kotlin/arrow/fx/KindConnectionTests.kt index 5ce40550b..1fe1707e2 100644 --- a/arrow-fx/src/test/kotlin/arrow/fx/KindConnectionTests.kt +++ b/arrow-fx/src/test/kotlin/arrow/fx/KindConnectionTests.kt @@ -17,24 +17,24 @@ class KindConnectionTests : UnitSpec() { effect shouldBe 1 } - "empty; isCanceled" { + "empty; isCancelled" { val c = IOConnection() - c.isCanceled() shouldBe false + c.isCancelled() shouldBe false } - "empty; isNotCanceled" { + "empty; isNotCancelled" { val c = IOConnection() - c.isNotCanceled() shouldBe true + c.isNotCancelled() shouldBe true } - "empty; push; cancel; isCanceled" { + "empty; push; cancel; isCancelled" { val c = IOConnection() c.push(IO {}) c.cancel().fix().unsafeRunSync() - c.isCanceled() shouldBe true + c.isCancelled() shouldBe true } - "cancel immediately if already canceled" { + "cancel immediately if already cancelled" { var effect = 0 val initial = IO { effect += 1 } val c = IOConnection() @@ -103,29 +103,29 @@ class KindConnectionTests : UnitSpec() { effect shouldBe 3 } - "uncancelable returns same reference" { - val ref1 = IOConnection.uncancelable - val ref2 = IOConnection.uncancelable + "uncancellable returns same reference" { + val ref1 = IOConnection.uncancellable + val ref2 = IOConnection.uncancellable ref1 shouldBe ref2 } - "uncancelable reference cannot be canceled" { - val ref = IOConnection.uncancelable - ref.isCanceled() shouldBe false + "uncancellable reference cannot be cancelled" { + val ref = IOConnection.uncancellable + ref.isCancelled() shouldBe false ref.cancel().fix().unsafeRunSync() - ref.isCanceled() shouldBe false + ref.isCancelled() shouldBe false } - "uncancelable.pop" { - val ref = IOConnection.uncancelable + "uncancellable.pop" { + val ref = IOConnection.uncancellable ref.pop() shouldBe IO.unit ref.push(IO.just(Unit)) ref.pop() shouldBe IO.unit } - "uncancelable.push never cancels the given cancelable" { - val ref = IOConnection.uncancelable + "uncancellable.push never cancels the given cancellable" { + val ref = IOConnection.uncancellable ref.cancel().fix().unsafeRunSync() var effect = 0 diff --git a/arrow-fx/src/test/kotlin/arrow/fx/MVarTest.kt b/arrow-fx/src/test/kotlin/arrow/fx/MVarTest.kt index 0f104ab7b..a4d23fc18 100644 --- a/arrow-fx/src/test/kotlin/arrow/fx/MVarTest.kt +++ b/arrow-fx/src/test/kotlin/arrow/fx/MVarTest.kt @@ -295,7 +295,7 @@ class MVarTest : UnitSpec() { fun concurrentTests(label: String, mvar: MVarFactory) { tests(label, mvar) - "$label - put is cancelable" { + "$label - put is cancellable" { IO.fx { val mVar = !mvar.just(0) !mVar.put(1).fork() @@ -310,7 +310,7 @@ class MVarTest : UnitSpec() { }.equalUnderTheLaw(IO.just(setOf(1, 3)), EQ()) } - "$label - take is cancelable" { + "$label - take is cancellable" { IO.fx { val mVar = !mvar.empty() val t1 = !mVar.take().fork() @@ -326,7 +326,7 @@ class MVarTest : UnitSpec() { }.equalUnderTheLaw(IO.just(setOf(1, 3)), EQ()) } - "$label - read is cancelable" { + "$label - read is cancellable" { IO.fx { val mVar = !mvar.empty() val finished = !Promise() @@ -340,8 +340,8 @@ class MVarTest : UnitSpec() { } } - tests("UncancelableMVar", MVar.factoryUncancelable(IO.async())) - concurrentTests("CancelableMVar", MVar.factoryCancelable(IO.concurrent())) + tests("UncancellableMVar", MVar.factoryUncancellable(IO.async())) + concurrentTests("cancellableMVar", MVar.factoryCancellable(IO.concurrent())) } } diff --git a/arrow-fx/src/test/kotlin/arrow/fx/PromiseTest.kt b/arrow-fx/src/test/kotlin/arrow/fx/PromiseTest.kt index 1996f4f7d..82b023b0c 100644 --- a/arrow-fx/src/test/kotlin/arrow/fx/PromiseTest.kt +++ b/arrow-fx/src/test/kotlin/arrow/fx/PromiseTest.kt @@ -149,7 +149,7 @@ class PromiseTest : UnitSpec() { } } - tests("CancelablePromise", promise = Promise(IO.concurrent()).fix()) - tests("UncancelablePromise", promise = Promise.uncancelable(IO.async()).fix()) + tests("cancellablePromise", promise = Promise(IO.concurrent()).fix()) + tests("UncancellablePromise", promise = Promise.uncancellable(IO.async()).fix()) } } diff --git a/arrow-fx/src/test/kotlin/arrow/fx/SemaphoreTest.kt b/arrow-fx/src/test/kotlin/arrow/fx/SemaphoreTest.kt index 7c5be664a..4ae98e305 100644 --- a/arrow-fx/src/test/kotlin/arrow/fx/SemaphoreTest.kt +++ b/arrow-fx/src/test/kotlin/arrow/fx/SemaphoreTest.kt @@ -134,10 +134,10 @@ class SemaphoreTest : UnitSpec() { } } - tests("UncancelableSemaphore") { Semaphore.uncancelable(it, IO.async()) } - tests("CancelableSemaphore") { Semaphore(it, IO.concurrent()) } + tests("UncancellableSemaphore") { Semaphore.uncancellable(it, IO.async()) } + tests("cancellableSemaphore") { Semaphore(it, IO.concurrent()) } - "CancelableSemaphore - supports cancellation of acquire" { + "cancellableSemaphore - supports cancellation of acquire" { Semaphore(0, IO.concurrent()).flatMap { s -> s.acquire() }.unsafeRunAsyncCancellable { } diff --git a/arrow-streams/src/main/kotlin/arrow/streams/internal/FreeC.kt b/arrow-streams/src/main/kotlin/arrow/streams/internal/FreeC.kt index 445bdd999..fd9fa1da5 100644 --- a/arrow-streams/src/main/kotlin/arrow/streams/internal/FreeC.kt +++ b/arrow-streams/src/main/kotlin/arrow/streams/internal/FreeC.kt @@ -150,7 +150,7 @@ sealed class FreeC : FreeCOf { fun asExitCase(): ExitCase = this.fold( pure = { ExitCase.Completed }, fail = { t -> ExitCase.Error(t) }, - interrupted = { _, _ -> ExitCase.Canceled } + interrupted = { _, _ -> ExitCase.Cancelled } ) companion object {