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

com.avito.android.Result.kt Maven / Gradle / Ivy

Go to download

Collection of infrastructure libraries and gradle plugins of Avito Android project

The newest version!
package com.avito.android

import com.avito.composite_exception.CompositeException
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract

/**
 * Why not [kotlin.Result]?
 *  - It's usage as return type is experimental before Kotlin 1.5
 *    [KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.md#limitations)
 *  - it requires to enable special compiler option to go without error
 *  - it sometimes exposed in modules API, which will require clients to enable this compiler options
 *
 * Could be replaced with [kotlin.Result] as it's return type usage matures to stable
 */
public sealed class Result {

    public fun getOrThrow(): T = when (this) {
        is Success -> value
        is Failure -> throw throwable
    }

    public fun getOrElse(func: (Throwable) -> T): T = when (this) {
        is Success -> value
        is Failure -> func(throwable)
    }

    public inline fun  map(
        mapSuccess: (value: T) -> R
    ): Result = when (this) {
        is Success -> try {
            Success(mapSuccess(value))
        } catch (throwable: Throwable) {
            Failure(throwable)
        }
        is Failure -> Failure(throwable)
    }

    public inline fun  flatMap(
        mapSuccess: (value: T) -> Result
    ): Result = when (this) {
        is Success -> try {
            mapSuccess(value)
        } catch (e: Throwable) {
            Failure(e)
        }
        is Failure -> Failure(throwable)
    }

    public inline fun  fold(onSuccess: (value: T) -> R, onFailure: (throwable: Throwable) -> R): R = when (this) {
        is Success -> onSuccess(value)
        is Failure -> onFailure(throwable)
    }

    public inline fun recover(func: (Throwable) -> T): Result = when (this) {
        is Success -> this
        is Failure -> try {
            Success(func(throwable))
        } catch (t: Throwable) {
            Failure(t)
        }
    }

    public inline fun rescue(f: (Throwable) -> Result): Result = when (this) {
        is Success -> this
        is Failure -> try {
            f(throwable)
        } catch (t: Throwable) {
            Failure(t)
        }
    }

    public inline fun exists(predicate: (T) -> Boolean): Boolean = when (this) {
        is Success -> try {
            predicate(getOrThrow())
        } catch (e: Throwable) {
            false
        }
        is Failure -> false
    }

    public inline fun onSuccess(func: (T) -> Unit): Result = when (this) {
        is Success -> {
            func(value)
            this
        }
        is Failure -> this
    }

    public inline fun onFailure(func: (Throwable) -> Unit): Result = when (this) {
        is Success -> this
        is Failure -> {
            func(throwable)
            this
        }
    }

    public inline fun  combine(other: Result, func: (T, T) -> R): Result {
        return when {
            this is Success && other is Success -> Success(func(this.value, other.value))
            this is Failure && other is Success -> Failure(this.throwable)
            this is Success && other is Failure -> Failure(other.throwable)
            this is Failure && other is Failure -> Failure(
                CompositeException(
                    "${this.throwable.message}\n${other.throwable.message}",
                    arrayOf(this.throwable, other.throwable)
                )
            )
            else -> throw IllegalStateException("this shouldn't happen")
        }
    }

    public class Success(public val value: T) : Result() {

        override fun equals(other: Any?): Boolean = when (other) {
            is Success<*> -> value == other.value
            else -> false
        }

        override fun hashCode(): Int = value?.hashCode() ?: 0

        override fun toString(): String = "Success[$value]"
    }

    public class Failure(public val throwable: Throwable) : Result() {

        override fun equals(other: Any?): Boolean = when (other) {
            is Failure<*> -> throwable == other.throwable
            else -> false
        }

        override fun hashCode(): Int = throwable.hashCode()

        override fun toString(): String = "Failure[${throwable.message}]"
    }

    public companion object {

        public inline fun  tryCatch(func: () -> T): Result = try {
            Success(func.invoke())
        } catch (e: Throwable) {
            Failure(e)
        }
    }
}

@OptIn(ExperimentalContracts::class)
public fun  Result.isFailure(): Boolean {
    contract {
        returns(true) implies (this@isFailure is Result.Failure)
    }
    return this is Result.Failure
}

@OptIn(ExperimentalContracts::class)
public fun  Result.isSuccess(): Boolean {
    contract {
        returns(true) implies (this@isSuccess is Result.Success)
    }
    return this is Result.Success
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy