diff --git a/lib/api/lib.api b/lib/api/lib.api index 2c965ca..b35d9ef 100644 --- a/lib/api/lib.api +++ b/lib/api/lib.api @@ -37,6 +37,7 @@ public final class app/cash/quiver/OutcomeKt { public static final fun asOption (Lapp/cash/quiver/Outcome;)Larrow/core/Option; public static final fun asOutcome (Larrow/core/Either;)Lapp/cash/quiver/Outcome; public static final fun asResult (Lapp/cash/quiver/Outcome;)Ljava/lang/Object; + public static final fun asResult (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static final fun failure (Ljava/lang/Object;)Lapp/cash/quiver/Outcome; public static final fun filter (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function1;)Lapp/cash/quiver/Outcome; public static final fun flatMap (Lapp/cash/quiver/Outcome;Lkotlin/jvm/functions/Function1;)Lapp/cash/quiver/Outcome; diff --git a/lib/src/main/kotlin/app/cash/quiver/Outcome.kt b/lib/src/main/kotlin/app/cash/quiver/Outcome.kt index 7103939..31eac45 100644 --- a/lib/src/main/kotlin/app/cash/quiver/Outcome.kt +++ b/lib/src/main/kotlin/app/cash/quiver/Outcome.kt @@ -3,6 +3,10 @@ package app.cash.quiver import app.cash.quiver.extensions.OutcomeOf +import app.cash.quiver.extensions.orThrow +import app.cash.quiver.extensions.toResult +import app.cash.quiver.raise.OutcomeRaise +import app.cash.quiver.raise.outcome import arrow.core.Either import arrow.core.Either.Left import arrow.core.Either.Right @@ -14,14 +18,10 @@ import arrow.core.flatMap import arrow.core.getOrElse import arrow.core.identity import arrow.core.left +import arrow.core.raise.catch import arrow.core.right import arrow.core.some import arrow.core.valid -import app.cash.quiver.extensions.orThrow -import app.cash.quiver.extensions.toResult -import app.cash.quiver.raise.OutcomeRaise -import app.cash.quiver.raise.outcome -import arrow.core.raise.catch import kotlin.experimental.ExperimentalTypeInference /** @@ -247,6 +247,18 @@ inline fun Outcome.asEither(onAbsent: () -> E): Either = */ fun OutcomeOf.asResult(): Result> = inner.toResult() +/** + * Converts an OutcomeOf to a Result, converting Absent to a Failure. + */ +inline fun OutcomeOf.asResult(onAbsent: () -> Throwable): Result = + inner.toResult() + .flatMap { maybeValue -> + maybeValue.fold( + { Result.failure(onAbsent()) }, + { Result.success(it) } + ) + } + inline fun Outcome.foldOption(onAbsent: () -> B, onPresent: (A) -> B): Either = inner.map { it.fold(onAbsent, onPresent) } diff --git a/lib/src/test/kotlin/app/cash/quiver/OutcomeTest.kt b/lib/src/test/kotlin/app/cash/quiver/OutcomeTest.kt index f66f0c1..5c8130b 100644 --- a/lib/src/test/kotlin/app/cash/quiver/OutcomeTest.kt +++ b/lib/src/test/kotlin/app/cash/quiver/OutcomeTest.kt @@ -31,6 +31,7 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.common.runBlocking import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.result.shouldBeFailure +import io.kotest.matchers.result.shouldBeSuccess import io.kotest.matchers.shouldBe import io.kotest.property.Arb import io.kotest.property.arbitrary.int @@ -40,6 +41,7 @@ import io.kotest.property.arrow.core.either import io.kotest.property.arrow.core.option import io.kotest.property.checkAll import kotlinx.coroutines.coroutineScope +import java.lang.IllegalStateException class OutcomeTest : StringSpec({ "Present flatMap" { @@ -475,6 +477,7 @@ class OutcomeTest : StringSpec({ absent.recover { fallback.bind() }.shouldBeAbsent() } } + "recover can recover from Failure" { checkAll(Arb.either(Arb.long(), Arb.int())) { either -> val failed: Outcome = "failure".failure() @@ -495,9 +498,16 @@ class OutcomeTest : StringSpec({ } } - "Converting to Result" { + "converting to Result" { Absent.asResult() shouldBe Result.success(None) 1.present().asResult() shouldBe Result.success(Some(1)) Throwable("sad").failure().asResult().shouldBeFailure().message shouldBe "sad" } + + "asResult converts to Either converting Absent to an error" { + 1.present().asResult { IllegalStateException("nup") }.shouldBeSuccess(1) + Absent.asEither { IllegalStateException("nup") }.shouldBeLeft().message shouldBe "nup" + "bad".failure().asEither { IllegalStateException("nup") }.shouldBeLeft("bad") + } + })