From e0f6165f1026e66e586d9095c7f1acf3b21d3bc5 Mon Sep 17 00:00:00 2001 From: Roman Elizarov Date: Fri, 13 Jul 2018 10:27:41 +0300 Subject: [PATCH] Updated SuccessOrFailure: * Parameter names for lambda * getOrElse takes exception parameters * fold added * Improved docs --- .../coroutines/src/kotlin/SuccessOrFailure.kt | 64 +++++++++++++------ 1 file changed, 46 insertions(+), 18 deletions(-) diff --git a/libraries/stdlib/coroutines/src/kotlin/SuccessOrFailure.kt b/libraries/stdlib/coroutines/src/kotlin/SuccessOrFailure.kt index 85876e096fd..ed4b57a5932 100644 --- a/libraries/stdlib/coroutines/src/kotlin/SuccessOrFailure.kt +++ b/libraries/stdlib/coroutines/src/kotlin/SuccessOrFailure.kt @@ -46,6 +46,8 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( /** * Returns the encapsulated value if this instance represents [success][isSuccess] or throws the encapsulated exception * if it is [failure][isFailure]. + * + * This function is shorthand for `getOrElse { throw it }` (see [getOrElse]). */ public fun getOrThrow(): T = when (value) { @@ -56,6 +58,8 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( /** * Returns the encapsulated value if this instance represents [success][isSuccess] or `null` * if it is [failure][isFailure]. + * + * This function is shorthand for `getOrElse { null }` (see [getOrElse]). */ public fun getOrNull(): T? = when (value) { @@ -68,6 +72,8 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( /** * Returns the encapsulated exception if this instance represents [failure][isFailure] or `null` * if it is [success][isSuccess]. + * + * This function is shorthand for `fold(onSuccess = { null }, onFailure = { it })` (see [fold]). */ public fun exceptionOrNull(): Throwable? = when (value) { @@ -80,11 +86,7 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( /** * Returns `true` if the [other] object is `SuccessOrFailure` that encapsulates an equal value or exception. */ - public override fun equals(other: Any?): Boolean { - // todo: this is workaround for is/as bugs, rewrite in direct way when fixed - val other = other as? SuccessOrFailure<*> ?: return false - return value == other.value - } + public override fun equals(other: Any?): Boolean = other is SuccessOrFailure<*> && value == other.value /** * Returns hashcode of either the encapsulated value or of the exception. @@ -162,15 +164,41 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( /** * Returns the encapsulated value if this instance represents [success][SuccessOrFailure.isSuccess] or the - * result of [defaultValue] function if it is [failure][SuccessOrFailure.isFailure]. + * result of [onFailure] function for encapsulated exception if it is [failure][SuccessOrFailure.isFailure]. * - * Note, that an exception thrown by [defaultValue] function is rethrown by this function. + * Note, that an exception thrown by [onFailure] function is rethrown by this function. + * + * This function is shorthand for `fold(onSuccess = { it }, onFailure = onFailure)` (see [fold]). */ -@InlineOnly public inline fun SuccessOrFailure.getOrElse(defaultValue: () -> R): R = - when(value) { - is SuccessOrFailure.Failure -> defaultValue() +@InlineOnly public inline fun SuccessOrFailure.getOrElse(onFailure: (exception: Throwable) -> R): R { + contract { + callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE) + } + return when(value) { + is SuccessOrFailure.Failure -> onFailure(value.exception) else -> value as T } +} + +/** + * Returns the the result of [onSuccess] for encapsulated value if this instance represents [success][SuccessOrFailure.isSuccess] + * or the result of [onFailure] function for encapsulated exception if it is [failure][SuccessOrFailure.isFailure]. + * + * Note, that an exception thrown by [onSuccess] or by [onFailure] function is rethrown by this function. + */ +@InlineOnly public inline fun SuccessOrFailure.fold( + onSuccess: (value: T) -> R, + onFailure: (exception: Throwable) -> R +): R { + contract { + callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE) + callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE) + } + return when(value) { + is SuccessOrFailure.Failure -> onFailure(value.exception) + else -> onSuccess(value as T) + } +} // transformation @@ -182,12 +210,12 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Note, that an exception thrown by [transform] function is rethrown by this function. * See [mapCatching] for an alternative that encapsulates exceptions. */ -@InlineOnly public inline fun SuccessOrFailure.map(transform: (T) -> R): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.map(transform: (value: T) -> R): SuccessOrFailure { contract { callsInPlace(transform, InvocationKind.AT_MOST_ONCE) } return when(value) { - is SuccessOrFailure.Failure -> SuccessOrFailure(value) // cannot cast here -- casts don't work (todo) + is SuccessOrFailure.Failure -> SuccessOrFailure(value) else -> SuccessOrFailure.success(transform(value as T)) } } @@ -200,12 +228,12 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. * See [map] for an alternative that rethrows exceptions. */ -@InlineOnly public inline fun SuccessOrFailure.mapCatching(transform: (T) -> R): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.mapCatching(transform: (value: T) -> R): SuccessOrFailure { contract { callsInPlace(transform, InvocationKind.AT_MOST_ONCE) } return when(value) { - is SuccessOrFailure.Failure -> SuccessOrFailure(value) // cannot cast here -- casts don't work (todo) + is SuccessOrFailure.Failure -> SuccessOrFailure(value) else -> runCatching { transform(value as T) } } } @@ -218,7 +246,7 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Note, that an exception thrown by [transform] function is rethrown by this function. * See [recoverCatching] for an alternative that encapsulates exceptions. */ -@InlineOnly public inline fun SuccessOrFailure.recover(transform: (Throwable) -> R): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.recover(transform: (exception: Throwable) -> R): SuccessOrFailure { contract { callsInPlace(transform, InvocationKind.AT_MOST_ONCE) } @@ -236,7 +264,7 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Any exception thrown by [transform] function is caught, encapsulated as a failure and returned by this function. * See [recover] for an alternative that rethrows exceptions. */ -@InlineOnly public inline fun SuccessOrFailure.recoverCatching(transform: (Throwable) -> R): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.recoverCatching(transform: (exception: Throwable) -> R): SuccessOrFailure { contract { callsInPlace(transform, InvocationKind.AT_MOST_ONCE) } @@ -253,7 +281,7 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Performs the given [action] on encapsulated value if this instance represents [success][SuccessOrFailure.isSuccess]. * Returns the original `SuccessOrFailure` unchanged. */ -@InlineOnly public inline fun SuccessOrFailure.onFailure(action: (Throwable) -> Unit): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.onFailure(action: (exception: Throwable) -> Unit): SuccessOrFailure { contract { callsInPlace(action, InvocationKind.AT_MOST_ONCE) } @@ -265,7 +293,7 @@ public inline class SuccessOrFailure @PublishedApi internal constructor( * Performs the given [action] on encapsulated exception if this instance represents [failure][SuccessOrFailure.isFailure]. * Returns the original `SuccessOrFailure` unchanged. */ -@InlineOnly public inline fun SuccessOrFailure.onSuccess(action: (T) -> Unit): SuccessOrFailure { +@InlineOnly public inline fun SuccessOrFailure.onSuccess(action: (value: T) -> Unit): SuccessOrFailure { contract { callsInPlace(action, InvocationKind.AT_MOST_ONCE) }