Skip to content
This repository has been archived by the owner on Feb 24, 2021. It is now read-only.

Deprecate @higherkind & @extension for Either #354

Merged
merged 7 commits into from
Dec 20, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ class Scope private constructor(
val job = coroutineContext[Job]
val scope = ScopedResource()
val release: suspend (R, ExitCase) -> Unit = { r, ex -> withContext(NonCancellable) { release(r, ex) } }
Either.catch(fr).flatMap { resource ->
Either.catch { fr() }.flatMap { resource ->
scope.acquired { ex: ExitCase -> release(resource, ex) }.map { registered ->
state.modify {
if ((conn.isCancelled() || job?.isCancelled == true) && registered) Pair(it, suspend { release(resource, ExitCase.Cancelled(CancellationException())) })
Expand Down Expand Up @@ -402,9 +402,9 @@ class Scope private constructor(
*/ // TODO return Pull.Result here, only usage in `Compiler` reconstructs into Pull.Result
internal suspend fun <A> interruptibleEval(f: suspend () -> A): Either<Either<Throwable, Token>, A> =
when (interruptible) {
null -> Either.catch(f).mapLeft { it.left() }
null -> Either.catch { f() }.mapLeft { it.left() }
else -> {
val res = raceN({ interruptible.deferred.get() }, { Either.catch(f) })
val res = raceN({ interruptible.deferred.get() }, { Either.catch { f() } })
when (res) {
is Either.Right -> res.b.mapLeft { it.left() }
is Either.Left -> Either.Left(res.a)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
import kotlin.coroutines.intrinsics.intercepted
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.startCoroutine

data class SideEffect(var counter: Int = 0) {
Expand Down Expand Up @@ -170,26 +169,6 @@ suspend fun <A> A.suspend(): A =
fun <A> A.suspended(): suspend () -> A =
suspend { suspend() }

suspend fun <A> Either<Throwable, A>.suspend(): A =
suspendCoroutineUninterceptedOrReturn { cont ->
suspend { this }.startCoroutine(Continuation(ComputationPool) {
it.fold(
{
it.fold(
{ e -> cont.intercepted().resumeWithException(e) },
{ a -> cont.intercepted().resume(a) }
)
},
{ e -> cont.intercepted().resumeWithException(e) }
)
})

COROUTINE_SUSPENDED
}

fun <A> Either<Throwable, A>.suspended(): suspend () -> A =
suspend { suspend() }

/**
* Example usage:
* ```kotlin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package arrow.fx.coroutines

import arrow.core.Either
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
Expand All @@ -27,23 +25,6 @@ class PredefTest : ArrowFxSpec(spec = {
}
}

"either.suspended always suspends" {
checkAll(Arb.either(Arb.throwable(), Arb.int())) { ea ->
val promise = UnsafePromise<Int>()

val x = ea.suspended()
.startCoroutineUninterceptedOrReturn(Continuation(EmptyCoroutineContext) {
promise.complete(it)
})

x shouldBe COROUTINE_SUSPENDED

Either.catch {
promise.join()
} should either(ea)
}
}

"shift" {
checkAll(Arb.string(), Arb.string()) { a, b ->
val t0 = threadName.invoke()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package arrow.fx.coroutines

import arrow.core.Either
import io.kotest.matchers.should
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.int
Expand Down Expand Up @@ -38,25 +39,18 @@ class CancellableF : ArrowFxSpec(spec = {
}

"cancelableF works for immediate values" {
checkAll(Arb.result(Arb.int())) { res ->
checkAll(Arb.either(Arb.throwable(), Arb.int())) { res ->
Either.catch {
cancellableF<Int> { cb ->
cb(res)
CancelToken.unit
}
} shouldBe res.toEither()
immediateValues(res)
} should either(res)
}
}

"cancelableF works for async values" {
checkAll(Arb.result(Arb.int())) { res ->
checkAll(Arb.either(Arb.throwable(), Arb.int())) { res ->
Either.catch {
cancellableF<Int> { cb ->
val res = res.suspend()
cb(res)
CancelToken.unit
}
} shouldBe res.toEither()
asyncValues(res)
} should either(res)
}
}

Expand Down Expand Up @@ -113,3 +107,22 @@ class CancellableF : ArrowFxSpec(spec = {
}
}
})

suspend fun immediateValues(e: Either<Throwable, Int>): Int =
cancellableF { cb ->
e.fold(
{ e -> cb(Result.failure(e)) },
{ i -> cb(Result.success(i)) }
)
CancelToken.unit
}

suspend fun asyncValues(e: Either<Throwable, Int>): Int =
cancellableF { cb ->
val res = e.suspend()
res.fold(
{ e -> cb(Result.failure(e)) },
{ i -> cb(Result.success(i)) }
)
CancelToken.unit
}