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

commonMain.Either.kt Maven / Gradle / Ivy

There is a newer version: 2.12.3
Show newest version
/*
 * Copyright 2019-2021 Mamoe Technologies and contributors.
 *
 *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
 *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
 *
 *  https://github.com/mamoe/mirai/blob/master/LICENSE
 */

@file:Suppress("NOTHING_TO_INLINE", "unused")

package net.mamoe.mirai.utils

/**
 * Safe union of two types.
 */
@JvmInline
public value class Either private constructor(
    @PublishedApi
    @JvmField
    internal val value: Any?,
) {
    override fun toString(): String = value.toString()

    public companion object {
        ///////////////////////////////////////////////////////////////////////////
        // constructors
        ///////////////////////////////////////////////////////////////////////////

        @PublishedApi
        internal object CheckedTypes

        @PublishedApi
        internal fun  CheckedTypes.new(value: Any?): Either = Either(value)

        @PublishedApi
        internal inline fun  checkTypes(value: Any?): CheckedTypes {
            if (!(value is R).xor(value is L)) {
                throw IllegalArgumentException("value(${getTypeHint(value)}) must be either L(${getTypeHint()}) or R(${getTypeHint()}), and must not be both of them.")
            }
            return CheckedTypes
        }

        /**
         * Create a [Either] whose value is [left].
         * @throws IllegalArgumentException if [left] satisfies both types [L] and [R].
         */
        @JvmName("left1")
        @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
        @kotlin.internal.LowPriorityInOverloadResolution
        public inline operator fun  invoke(left: L): Either =
            checkTypes(left).new(left)

        /**
         * Create a [Either] whose value is [right].
         * @throws IllegalArgumentException if [right] satisfies both types [L] and [R].
         */
        @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
        @kotlin.internal.LowPriorityInOverloadResolution
        @JvmName("right1")
        public inline operator fun  invoke(right: R): Either =
            checkTypes(right).new(right)

        /**
         * Create a [Either] whose value is [left].
         * @throws IllegalArgumentException if [left] satisfies both types [L] and [R].
         */
        @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
        public inline fun  left(left: L): Either =
            checkTypes(left).new(left)

        /**
         * Create a [Either] whose value is [right].
         * @throws IllegalArgumentException if [right] satisfies both types [L] and [R].
         */
        @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
        public inline fun  right(right: R): Either =
            checkTypes(right).new(right)


        ///////////////////////////////////////////////////////////////////////////
        // functions
        ///////////////////////////////////////////////////////////////////////////


        public inline val  Either.rightOrNull: R? get() = value.safeCast()
        public inline val  Either.right: R get() = value.cast()

        public inline val  Either.leftOrNull: L? get() = value.safeCast()
        public inline val  Either.left: L get() = value.cast()

        public inline val  Either.isLeft: Boolean get() = value is L
        public inline val  Either.isRight: Boolean get() = value is R


        public inline fun  Either.ifLeft(block: (L) -> T): T? =
            this.leftOrNull?.let(block)

        public inline fun  Either.ifRight(block: (R) -> T): T? =
            this.rightOrNull?.let(block)


        public inline fun  Either.onLeft(block: (L) -> Unit): Either {
            this.leftOrNull?.let(block)
            return this
        }

        public inline fun  Either.onRight(block: (R) -> Unit): Either {
            this.rightOrNull?.let(block)
            return this
        }


        public inline fun  Either.mapLeft(block: (L) -> T): Either {
            @Suppress("RemoveExplicitTypeArguments")
            return this.fold(
                onLeft = { invoke(block(it)) },
                onRight = { invoke(it) }
            )
        }

        public inline fun  Either.mapRight(block: (R) -> T): Either {
            @Suppress("RemoveExplicitTypeArguments")
            return this.fold(
                onLeft = { invoke(it) },
                onRight = { invoke(it.let(block)) }
            )
        }


        public inline fun  Either.fold(
            onLeft: (L) -> T,
            onRight: (R) -> T,
        ): T = leftOrNull?.let { onLeft(it) } ?: value.cast().let(onRight)

        public inline fun  Either.toResult(): Result = this.fold(
            onLeft = { Result.failure(it) },
            onRight = { Result.success(it) }
        )

        @PublishedApi
        internal fun getTypeHint(value: Any?): String {
            return if (value == null) "null"
            else value::class.run { simpleName ?: toString() }
        }

        @PublishedApi
        internal inline fun  getTypeHint(): String {
            return T::class.run { simpleName ?: toString() }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy