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

ru.hnau.jutils.possible.Possible.kt Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package ru.hnau.jutils.possible

import ru.hnau.jutils.tryOrElse


class Possible private constructor(
        val data: T?,
        val error: Exception?
) {

    companion object {

        fun  success(data: T): Possible =
                Possible(data = data, error = null)

        fun success() = success(Unit)

        fun  successOrUndefined(data: T?): Possible =
                data?.let { success(it) } ?: undefined()

        fun  successOrError(data: T?): Possible =
                data?.let { success(it) } ?: error()

        fun  error(error: Exception? = null): Possible =
                Possible(data = null, error = error ?: Exception())

        fun  error(message: String?): Possible =
                error(Exception(message))

        fun  errorOrUndefined(error: Exception?): Possible =
                error?.let { error(it) } ?: undefined()

        fun  error(th: Throwable?): Possible =
                (th as? Exception)?.let { Possible.error(it) } ?: Possible.error(th?.message)

        fun  errorOrUndefined(th: Throwable?): Possible =
                (th as? Exception)?.let { Possible.errorOrUndefined(it) }
                        ?: Possible.errorOrUndefined(th?.message)

        fun  errorOrUndefined(message: String?): Possible =
                message?.let { error(it) } ?: undefined()

        fun  undefined(): Possible =
                Possible(data = null, error = null)

        inline fun  trySuccessCatchError(throwsAction: () -> T): Possible =
                trySuccessCatchErrorPossible { success(throwsAction.invoke()) }

        inline fun  trySuccessCatchUndefined(throwsAction: () -> T): Possible =
                trySuccessCatchUndefinedPossible { success(throwsAction.invoke()) }

        inline fun  trySuccessCatchErrorPossible(throwsAction: () -> Possible): Possible =
                tryOrElse(
                        throwsAction = throwsAction,
                        onThrow = { Possible.error(it) }
                )

        inline fun  trySuccessCatchUndefinedPossible(throwsAction: () -> Possible): Possible =
                tryOrElse(
                        throwsAction = throwsAction,
                        onThrow = { Possible.undefined() }
                )

    }

    operator fun component1() = data

    operator fun component2() = error

    override fun toString() = "Possible{" +
            "status=${handle("SUCCESS", "ERROR", "UNDEFINED")}" +
            (data?.let { ", data=$it" } ?: "") +
            (error?.let { ", error=$it" } ?: "") +
            "}"

    operator fun  plus(other: Possible) =
            mapPossible { thisData ->
                other.mapPossible { otherData ->
                    Possible.success(thisData to otherData)
                }
            }

    inline fun  ifSuccess(action: (T) -> R) =
            data?.let { action.invoke(it) }

    inline fun  ifError(action: (Exception) -> R) =
            error?.let { action.invoke(it) }

    inline fun  ifUndefined(action: () -> R) =
            if (data != null || error != null) null else action.invoke()

    inline fun  ifSuccessOrUndefined(action: (T?) -> R) =
            if (error != null) null else action.invoke(data)

    inline fun  ifSuccessOrError(action: (T?) -> R) =
            if (error == null && data == null) null else action.invoke(data)

    inline fun  ifErrorOrUndefined(action: (Exception?) -> R) =
            if (data != null) null else action.invoke(error)

    inline fun  handle(
            onSuccess: (T) -> R,
            onError: (Exception) -> R,
            onUndefined: () -> R
    ): R {

        if (data != null) {
            return onSuccess.invoke(data)
        }

        if (error != null) {
            return onError.invoke(error)
        }

        return onUndefined.invoke()
    }

    inline fun  handle(
            onSuccess: (T) -> R,
            onError: (Exception?) -> R
    ): R {

        if (data != null) {
            return onSuccess.invoke(data)
        }

        return onError.invoke(error)
    }

    fun  handle(
            forSuccess: R,
            forError: R,
            forUndefined: R
    ): R {
        if (data != null) {
            return forSuccess
        }

        if (error != null) {
            return forError
        }

        return forUndefined
    }

    fun  handle(
            forSuccess: R,
            forError: R
    ): R {
        if (data != null) {
            return forSuccess
        }

        return forError
    }

    fun getDataOrThrow() = handle(
            onSuccess = { it },
            onError = { throw (it ?: Exception()) }
    )

    inline fun getDataOrHandleError(
            onError: (ex: Exception) -> Unit,
            onUndefined: () -> Unit
    ) =
            handle(
                    onSuccess = { it },
                    onError = { onError.invoke(it); null },
                    onUndefined = { onUndefined.invoke(); null }
            )

    inline fun getDataOrHandleError(
            onError: (ex: Exception?) -> Unit
    ) =
            handle(
                    onSuccess = { it },
                    onError = { onError.invoke(it); null }
            )

    inline fun  map(
            converter: (T) -> O
    ) =
            data?.let { success(converter.invoke(it)) } ?: error?.let { error(it) }
            ?: undefined()

    inline fun  tryMap(
            throwsConverter: (T) -> O
    ) =
            mapPossible { trySuccessCatchError { throwsConverter.invoke(it) } }

    inline fun  mapPossible(
            converter: (T) -> Possible
    ) =
            data?.let { converter.invoke(it) } ?: error?.let { error(it) } ?: undefined()

   inline fun  tryMapPossible(
            throwsConverter: (T) -> Possible
    ) =
            mapPossible { data ->
                tryOrElse(
                        throwsAction = { throwsConverter.invoke(data) },
                        onThrow = { Possible.error(it) }
                )
            }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is Possible<*>) return false

        if (data != null && data == other.data) return true
        if (error != null && error == other.error) return true
        if (data == null && other.data == null && error == null && other.error == null) return true

        return false
    }

    override fun hashCode(): Int {
        var result = data?.hashCode() ?: 0
        result = 31 * result + (error?.hashCode() ?: 0)
        return result
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy