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

commonMain.com.bkahlert.kommons.Either.kt Maven / Gradle / Ivy

Go to download

Kommons Core is a Kotlin Multiplatform Library that offers shared features for all Kommons modules.

There is a newer version: 2.8.0
Show newest version
package com.bkahlert.kommons

import com.bkahlert.kommons.Either.Left
import com.bkahlert.kommons.Either.Right
import kotlin.contracts.InvocationKind.AT_MOST_ONCE
import kotlin.contracts.contract

/**
 * Represents a container containing either an instance of type [A] ([Left])
 * or [B] ([Right]).
 */
public sealed interface Either {
    /** Represents a container containing the left value. */
    public data class Left(
        /** The actual left value. */
        public val value: A
    ) : Either

    /** Represents a container containing the right value. */
    public data class Right(
        /** The actual right value. */
        public val value: B
    ) : Either
}

/**
 * Returns the encapsulated [Left.value] value if this instance represents [Left] or throws a [NoSuchElementException] otherwise.
 *
 * This function is a shorthand for `getLeftOrElse { throw it }` (see [getLeftOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline fun  Either.getLeftOrThrow(): A = when (this) {
    is Left -> value
    else -> throw NoSuchElementException()
}

/**
 * Returns the encapsulated [Right.value] value if this instance represents [Right] or throws a [NoSuchElementException] otherwise.
 *
 * This function is a shorthand for `getRightOrElse { throw it }` (see [getRightOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline fun  Either.getRightOrThrow(): B = when (this) {
    is Right -> value
    else -> throw NoSuchElementException()
}

/**
 * Returns the encapsulated [Left.value] value if this instance represents [Left] or the
 * result of [onRight] function for the encapsulated [Right.value] value otherwise.
 *
 * This function is a shorthand for `fold(onLeft = { it }, onRight = onRight)` (see [fold]).
 */
public inline infix fun  Either.getLeftOrElse(onRight: (B) -> R): R {
    contract {
        callsInPlace(onRight, AT_MOST_ONCE)
    }
    return when (this) {
        is Left -> value
        is Right -> onRight(value)
    }
}

/**
 * Returns the encapsulated [Right.value] value if this instance represents [Right] or the
 * result of [onLeft] function for the encapsulated [Left.value] value otherwise.
 *
 * This function is a shorthand for `fold(onLeft = onLeft, onRight = { it })` (see [fold]).
 */
public inline infix fun  Either.getRightOrElse(onLeft: (A) -> R): R {
    contract {
        callsInPlace(onLeft, AT_MOST_ONCE)
    }
    return when (this) {
        is Left -> onLeft(value)
        is Right -> value
    }
}

/**
 * Returns the encapsulated [Left.value] value if this instance represents [Left] or the
 * [defaultValue] if it's [Right].
 *
 * This function is a shorthand for `getLeftOrElse { defaultValue }` (see [getLeftOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline infix fun  Either.getLeftOrDefault(defaultValue: R): R = when (this) {
    is Left -> value
    is Right -> defaultValue
}

/**
 * Returns the encapsulated [Right.value] value if this instance represents [Right] or the
 * [defaultValue] if it's [Left].
 *
 * This function is a shorthand for `getRightOrElse { defaultValue }` (see [getRightOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline infix fun  Either<*, B>.getRightOrDefault(defaultValue: R): R = when (this) {
    is Left -> defaultValue
    is Right -> value
}

/**
 * Returns the encapsulated [Left.value] value if this instance represents [Left] or
 * `null` if it's [Right].
 *
 * This function is a shorthand for `getLeftOrElse { null }` (see [getLeftOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline fun  Either.getLeftOrNull(): R? = when (this) {
    is Left -> value
    is Right -> null
}

/**
 * Returns the encapsulated [Right.value] value if this instance represents [Right] or
 * `null` if it's [Left].
 *
 * This function is a shorthand for `getRightOrElse { null }` (see [getRightOrElse]).
 */
@Suppress("NOTHING_TO_INLINE")
public inline fun  Either<*, B>.getRightOrNull(): R? = when (this) {
    is Left -> null
    is Right -> value
}

/**
 * Returns the result of [onLeft] for the encapsulated instance [A] or
 * the result of [onRight] for the encapsulated instance [B].
 */
public inline fun  Either.fold(
    onLeft: (A) -> R,
    onRight: (B) -> R,
): R {
    contract {
        callsInPlace(onLeft, AT_MOST_ONCE)
        callsInPlace(onRight, AT_MOST_ONCE)
    }
    return when (this) {
        is Left -> onLeft(value)
        is Right -> onRight(value)
    }
}

/**
 * Returns the encapsulated result of the given [transform] function applied to the encapsulated value
 * if this instance represents [Left] or the
 * original encapsulated [Right] value if it's [Right].
 */
public inline infix fun  Either.mapLeft(transform: (A) -> R): Either {
    contract {
        callsInPlace(transform, AT_MOST_ONCE)
    }
    return when (this) {
        is Left -> Left(transform(value))
        is Right -> @Suppress("UNCHECKED_CAST") (this as Either)
    }
}

/**
 * Returns the encapsulated result of the given [transform] function applied to the encapsulated value
 * if this instance represents [Right] or the
 * original encapsulated [Left] value if it's [Left].
 */
public inline infix fun  Either.mapRight(transform: (B) -> R): Either {
    contract {
        callsInPlace(transform, AT_MOST_ONCE)
    }
    return when (this) {
        is Left -> @Suppress("UNCHECKED_CAST") (this as Either)
        is Right -> Right(transform(value))
    }
}

/**
 * Performs the given [action] on the encapsulated value if this instance represents [Left].
 * Returns the original [Either] unchanged.
 */
public inline infix fun  Either.onLeft(action: (A) -> Unit): Either {
    contract {
        callsInPlace(action, AT_MOST_ONCE)
    }
    if (this is Left) action(value)
    return this
}

/**
 * Performs the given [action] on the encapsulated value if this instance represents [Right].
 * Returns the original [Either] unchanged.
 */
public inline infix fun  Either.onRight(action: (B) -> Unit): Either {
    contract {
        callsInPlace(action, AT_MOST_ONCE)
    }
    if (this is Right) action(value)
    return this
}

/** Converts this [Either] to a [Result]. */
@Suppress("NOTHING_TO_INLINE", "DirectUseOfResultType")
public inline fun  Either.toResult(): Result =
    mapLeft { Result.success(it) } getLeftOrElse { Result.failure(it) }

/** Converts this [Result] to an [Either]. */
@Suppress("NOTHING_TO_INLINE")
public inline fun  Result.toEither(): Either =
    fold({ Left(it) }, { Right(it) })

/**
 * Returns this result's value if it represents [Result.success] and
 * the caught [Throwable] if it represents [Result.failure].
 */
public fun  Result.getOrException(): Pair =
    fold({ it to null }, { null to it })




© 2015 - 2025 Weber Informatics LLC | Privacy Policy