All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.OutcomeComprehension.kt Maven / Gradle / Ivy

The newest version!
package no.dossier.libraries.functional

import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext

/**
 * This is a context object used as a receiver of the [composeOutcome] function. It carries a
 * CoroutineContext instance so that we can launch child coroutines in that block, and also it carries a reference
 * to [failureSetter] so that the latest partial result can be captured in case of [Failure].
 */
class AccumulatedResultContext(
    override val coroutineContext: CoroutineContext,
    private val failureSetter: (failure: Failure) -> Unit
) : CoroutineScope {
    suspend operator fun  Outcome.component1(): T = this.bind()
    suspend operator fun  Outcome.not(): T = this.bind()
    suspend fun  Outcome.bind(): T = this.resolve {
        failureSetter(it)
        coroutineScope { cancel() }
        awaitCancellation()
    }
}

/**
 * Attempts to compose an instance of [Outcome] by evaluating a set of partial results.
 * This emulates monad comprehensions by controlling flow via coroutines.
 *
 * Expressions inside the *block* lambda returning Outcome are supposed to be bound via *!* operator function
 * so that they either return the Success value of T, or in case of Failure the whole block is interrupted
 * and that specific partial Failure result is returned from the whole [composeOutcome] block.
 *
 * This a simple coroutine-based implementation of Result/Outcome/Either monad comprehension inspired by Arrow library.
 *
 * @param E Error type
 * @param T Success type
 */
fun  composeOutcome(
    block: suspend AccumulatedResultContext.() -> Outcome
): Outcome = runBlocking {
    lateinit var outcome: Outcome
    val failureSetter: (failure: Failure) -> Unit = { outcome = it }

    coroutineScope {
        launch {
            outcome = block(AccumulatedResultContext(coroutineContext, failureSetter))
        }
    }

    outcome
}

/**
 * @see composeOutcome
 * @param E Error type
 * @param T Success type
 */
@Deprecated("This function was renamed", ReplaceWith("composeOutcome(block)"))
fun  attemptBuildResult(
    block: suspend AccumulatedResultContext.() -> Outcome
): Outcome = composeOutcome(block)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy