commonMain.Either.kt Maven / Gradle / Ivy
/*
* 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