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

fuookami.ospf.kotlin.utils.functional.Either.kt Maven / Gradle / Ivy

There is a newer version: 1.0.29
Show newest version
package fuookami.ospf.kotlin.utils.functional

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.descriptors.*
import fuookami.ospf.kotlin.utils.concept.*

data class EitherSerializer(
    val leftSerializer: KSerializer,
    val rightSerializer: KSerializer,
) : KSerializer> {
    @OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)
    override val descriptor: SerialDescriptor = SerialDescriptor("Either", JsonElement::class.serializer().descriptor)

    @OptIn(InternalSerializationApi::class)
    override fun deserialize(decoder: Decoder): Either {
        decoder as? JsonDecoder ?: throw IllegalStateException(
            "This serializer can be used only with Json format." +
                    "Expected Decoder to be JsonDecoder, got ${this::class}"
        )
        val json = Json {
            ignoreUnknownKeys = true
        }
        val element = decoder.decodeSerializableValue(JsonElement::class.serializer())
        return try {
            val leftValue = json.decodeFromJsonElement(leftSerializer, element)
            Either.Left(leftValue)
        } catch (e: Exception) {
            e.printStackTrace()
            val rightValue = json.decodeFromJsonElement(rightSerializer, element)
            Either.Right(rightValue)
        }
    }

    override fun serialize(encoder: Encoder, value: Either) {
        when (value) {
            is Either.Left -> {
                encoder.encodeSerializableValue(leftSerializer, value.value)
            }

            is Either.Right -> {
                encoder.encodeSerializableValue(rightSerializer, value.value)
            }
        }
    }
}

sealed class Either {
    data class Left(val value: L) : Either() {
        override fun hashCode(): Int = value.hashCode()
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (other !is Left<*, *>) return false

            if (value != other.value) return false

            return true
        }

        override fun toString() = "$value"
    }

    data class Right(val value: R) : Either() {
        override fun hashCode(): Int = value.hashCode()
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (other !is Right<*, *>) return false

            if (value != other.value) return false

            return true
        }

        override fun toString() = "$value"
    }

    val isLeft get() = this is Left
    val isRight get() = this is Right

    val left: L?
        get() = when (this) {
            is Left -> {
                this.value
            }

            else -> {
                null
            }
        }

    val right: R?
        get() = when (this) {
            is Right -> {
                this.value
            }

            else -> {
                null
            }
        }

    fun  ifLeft(extractor: Extractor) = EitherMatcher(this).ifLeft(extractor)
    fun  ifRight(extractor: Extractor) = EitherMatcher(this).ifRight(extractor)

    @JvmName("mapLeft")
    fun  map(extractor: Extractor): Either {
        return when (this) {
            is Left -> {
                Left(extractor(this.value))
            }

            is Right -> {
                Right(this.value)
            }
        }
    }

    @JvmName("mapRight")
    fun  map(extractor: Extractor): Either {
        return when (this) {
            is Left -> {
                Left(this.value)
            }

            is Right -> {
                Right(extractor(this.value))
            }
        }
    }

    fun  map(extractor1: Extractor, extractor2: Extractor): Either {
        return when (this) {
            is Left -> {
                Left(extractor1(this.value))
            }

            is Right -> {
                Right(extractor2(this.value))
            }
        }
    }
}

class EitherMatcher(
    private val value: Either
) {
    private lateinit var leftCallBack: (L) -> Ret
    private lateinit var rightCallBack: (R) -> Ret

    fun ifLeft(callBack: (L) -> Ret): EitherMatcher {
        leftCallBack = callBack
        return this
    }

    fun ifRight(callBack: (R) -> Ret): EitherMatcher {
        rightCallBack = callBack
        return this
    }

    @Throws(NullPointerException::class)
    operator fun invoke(): Ret = when (value) {
        is Either.Left -> {
            leftCallBack(value.value); }

        is Either.Right -> {
            rightCallBack(value.value); }
    }
}

@Throws(NullPointerException::class)
fun  match(
    value: Either,
    leftCallBack: (L) -> Ret,
    rightCallBack: (R) -> Ret
): Ret {
    val matcher = value.ifLeft(leftCallBack).ifRight(rightCallBack)
    return matcher()
}

fun , R : Copyable> Either.copy(
    value: Either
): Either {
    return when (value) {
        is Either.Left -> {
            Either.Left(copy(value.value))
        }

        is Either.Right -> {
            Either.Right(copy(value.value))
        }
    }
}

fun , R : Movable> Either.move(
    value: Either
): Either {
    return when (value) {
        is Either.Left -> {
            Either.Left(move(value.value))
        }

        is Either.Right -> {
            Either.Right(move(value.value))
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy