Python: Result documented, show cases added

GitOrigin-RevId: 0acfe32c2db90a3e2dbe58e4b087d581d82ea23a
This commit is contained in:
Ilya.Kazakevich
2024-10-24 19:44:26 +00:00
committed by intellij-monorepo-bot
parent 9864882e88
commit 20bf407b28
@@ -2,8 +2,38 @@
package com.jetbrains.python
/**
* Operation result to be used with pattern matching.
* Unlike Kotlin `Result`, [ERR] could be anything (See [LocalizedErrorString])
* Operation result to be used as `Maybe` instead of checked exceptions.
* Unlike Kotlin `Result`, [ERR] could be anything (See [LocalizedErrorString]).
*
* Typical usages:
*
* ```kotlin
* when(val r = someFun() {
* is Result.Success -> r.result // is ok
* is Result.Failure -> r.error // is error
* }
* ```
* Get result or throw error (I am 100% sure there is no error): [orThrow].
*
* Chain several calls, get latest result or first error (all errors are the same): [mapResult].
*
* When errors are different: [mapResultWithErr]
*
* Fast return: [getOr]
* ```kotlin
* fun foo() {
* val data = getSomeResult().getOr { return }
* }
* ```
*
* Return from function with same error (see [convertErr])
* ```kotlin
* fun foo():Result<String, Int> {
* // Returns Result<Foo, Int>
* getSomeResult().getOr { return it.convertErr()}
* }
* ```
* See showcase in tests.
*/
sealed class Result<SUCC, ERR> {
data class Failure<SUCC, ERR>(val error: ERR) : Result<SUCC, ERR>()
@@ -15,10 +45,24 @@ sealed class Result<SUCC, ERR> {
is Failure -> Failure(error)
}
/***
* ```kotlin
* val data = someFun().getOr { return }
* ```
*/
inline fun getOr(onFailure: (err: Failure<*, ERR>) -> Nothing): SUCC {
when (this) {
is Failure -> onFailure(this)
is Success -> return result
}
}
/**
* Maps success result to another one with same error
* ```kotlin
* findBeer().mapResult{openBeer(it)}.mapResult{drinkIt(it)}
* val drinkResultOrFirstError = findBeer()
* .mapResult{ openBeer(it) }
* .mapResult{ drinkIt(it) }
* ```
*/
inline fun <NEW_S> mapResult(map: (SUCC) -> Result<NEW_S, ERR>): Result<NEW_S, ERR> =
@@ -27,11 +71,42 @@ sealed class Result<SUCC, ERR> {
is Failure -> Failure(error)
}
/**
* Same as [mapResult] but for different errors
* ```kotlin
* val drinkResultOrFirstError = findBeer()
* .mapResult{ openBeer(it) }
* .mapResultWithErr(
* onSuccess = { drink(it) },
* onErr = { LocalizedErrorString("Oops, ${it.message}") }
* )
* ```
*/
inline fun <NEW_ERR, NEW_S> mapResultWithErr(
onSuccess: (SUCC) -> Result<NEW_S, NEW_ERR>,
onErr: (ERR) -> NEW_ERR,
): Result<NEW_S, NEW_ERR> =
when (this) {
is Success -> onSuccess(result)
is Failure -> Failure(onErr(error))
}
val successOrNull: SUCC? get() = if (this is Success) result else null
/**
* Like Rust `unwrap`: returns result or throws exception. Use when error is unexpected
*/
fun orThrow(onError: (ERR) -> Throwable = { e -> AssertionError(e) }): SUCC {
when (this) {
is Success -> return result
is Failure -> throw onError(this.error)
}
}
}
}
/**
* Converts [Result.Failure] to another [Result.Failure] with the same error but different success.
* See class doc for example
*/
fun <S, E> Result.Failure<*, E>.convertErr(): Result.Failure<S, E> = Result.Failure<S, E>(error)