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

Commit

Permalink
Deprecate @higherkind & @extension for Either (#354)
Browse files Browse the repository at this point in the history
* Either.catch doesn't accept suspend lambda

* Remove another Either.catch with lambda

* Rewrite CancellableF test

* Assert with `should either`

* Split test off into function

* Add log for debugging on CI

* Remove Arb.result
  • Loading branch information
nomisRev committed Dec 20, 2020
1 parent da751ce commit b861890
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 67 deletions.
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 @@ -109,12 +108,6 @@ fun <A> catchSystemErrInto(outStream: OutputStream, thunk: () -> A): A {
fun Arb.Companion.throwable(): Arb<Throwable> =
Arb.string().map(::RuntimeException)

fun <A> Arb.Companion.result(right: Arb<A>): Arb<Result<A>> {
val failure: Arb<Result<A>> = Arb.throwable().map { e -> Result.failure<A>(e) }
val success: Arb<Result<A>> = right.map { a -> Result.success(a) }
return Arb.choice(failure, success)
}

fun <L, R> Arb.Companion.either(left: Arb<L>, right: Arb<R>): Arb<Either<L, R>> {
val failure: Arb<Either<L, R>> = left.map { l -> l.left() }
val success: Arb<Either<L, R>> = right.map { r -> r.right() }
Expand Down Expand Up @@ -170,26 +163,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 All @@ -10,13 +11,16 @@ import kotlinx.coroutines.launch
class CancellableF : ArrowFxSpec(spec = {

"cancelable works for immediate values" {
checkAll(Arb.result(Arb.int())) { res ->
checkAll(Arb.either(Arb.throwable(), Arb.int())) { res ->
Either.catch {
cancellable<Int> { cb ->
cb(res)
res.fold(
{ e -> cb(Result.failure(e)) },
{ a -> cb(Result.success(a)) }
)
CancelToken.unit
}
} shouldBe res.toEither()
} should either(res)
}
}

Expand All @@ -38,25 +42,20 @@ class CancellableF : ArrowFxSpec(spec = {
}

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

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

Expand Down Expand Up @@ -113,3 +112,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
}

0 comments on commit b861890

Please sign in to comment.