Rename SuccessOrFailure to Result and hide Failure from ABI
* The members of Result are isSuccess, isFailure, exceptionOrNull, getOrNull * The rest of API is implemented via inline-only extensions * There are two internal functions to hide detailed mechanics of an internal Result.Failure class: createFailure and throwOnFailure * Result.toString is explicit: either Success(v) or Failure(x) See KT-26538
This commit is contained in:
+1
-1
@@ -79,7 +79,7 @@ private class ExperimentalContinuationMigration<T>(val continuation: Continuatio
|
||||
|
||||
private class ContinuationMigration<T>(val continuation: ExperimentalContinuation<T>): Continuation<T> {
|
||||
override val context: CoroutineContext = continuation.context.toCoroutineContext()
|
||||
override fun resumeWith(result: SuccessOrFailure<T>) {
|
||||
override fun resumeWith(result: Result<T>) {
|
||||
result
|
||||
.onSuccess { continuation.resume(it) }
|
||||
.onFailure { continuation.resumeWithException(it) }
|
||||
|
||||
@@ -17,5 +17,5 @@ internal expect class SafeContinuation<in T> : Continuation<T> {
|
||||
internal fun getOrThrow(): Any?
|
||||
|
||||
override val context: CoroutineContext
|
||||
override fun resumeWith(result: SuccessOrFailure<T>): Unit
|
||||
override fun resumeWith(result: Result<T>): Unit
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ internal actual constructor(
|
||||
|
||||
private var result: Any? = initialResult
|
||||
|
||||
public actual override fun resumeWith(result: SuccessOrFailure<T>) {
|
||||
public actual override fun resumeWith(result: Result<T>) {
|
||||
val cur = this.result
|
||||
when {
|
||||
cur === UNDECIDED -> {
|
||||
@@ -46,7 +46,7 @@ internal actual constructor(
|
||||
val result = this.result
|
||||
return when {
|
||||
result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream
|
||||
result is SuccessOrFailure.Failure -> throw result.exception
|
||||
result is Result.Failure -> throw result.exception
|
||||
else -> result // either COROUTINE_SUSPENDED or data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ internal abstract class CoroutineImpl(private val resultContinuation: Continuati
|
||||
?: (context[ContinuationInterceptor]?.interceptContinuation(this) ?: this)
|
||||
.also { intercepted_ = it }
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
||||
override fun resumeWith(result: Result<Any?>) {
|
||||
var current = this
|
||||
var currentResult: Any? = result.getOrNull()
|
||||
var currentException: Throwable? = result.exceptionOrNull()
|
||||
@@ -84,7 +84,7 @@ internal object CompletedContinuation : Continuation<Any?> {
|
||||
override val context: CoroutineContext
|
||||
get() = error("This continuation is already complete")
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
||||
override fun resumeWith(result: Result<Any?>) {
|
||||
error("This continuation is already complete")
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ internal actual constructor(
|
||||
)
|
||||
}
|
||||
|
||||
public actual override fun resumeWith(result: SuccessOrFailure<T>) {
|
||||
public actual override fun resumeWith(result: Result<T>) {
|
||||
while (true) { // lock-free loop
|
||||
val cur = this.result // atomic read
|
||||
when {
|
||||
@@ -57,7 +57,7 @@ internal actual constructor(
|
||||
}
|
||||
return when {
|
||||
result === RESUMED -> COROUTINE_SUSPENDED // already called continuation, indicate COROUTINE_SUSPENDED upstream
|
||||
result is SuccessOrFailure.Failure -> throw result.exception
|
||||
result is Result.Failure -> throw result.exception
|
||||
else -> result // either COROUTINE_SUSPENDED or data
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ private inline fun <T> createCoroutineFromSuspendFunction(
|
||||
object : RestrictedContinuationImpl(completion as Continuation<Any?>) {
|
||||
private var label = 0
|
||||
|
||||
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
|
||||
override fun invokeSuspend(result: Result<Any?>): Any? =
|
||||
when (label) {
|
||||
0 -> {
|
||||
label = 1
|
||||
@@ -180,7 +180,7 @@ private inline fun <T> createCoroutineFromSuspendFunction(
|
||||
object : ContinuationImpl(completion as Continuation<Any?>, context) {
|
||||
private var label = 0
|
||||
|
||||
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? =
|
||||
override fun invokeSuspend(result: Result<Any?>): Any? =
|
||||
when (label) {
|
||||
0 -> {
|
||||
label = 1
|
||||
|
||||
+6
-6
@@ -18,7 +18,7 @@ internal abstract class BaseContinuationImpl(
|
||||
public val completion: Continuation<Any?>?
|
||||
) : Continuation<Any?>, CoroutineStackFrame, Serializable {
|
||||
// This implementation is final. This fact is used to unroll resumeWith recursion.
|
||||
public final override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
||||
public final override fun resumeWith(result: Result<Any?>) {
|
||||
// Invoke "resume" debug probe only once, even if previous frames are "resumed" in the loop below, too
|
||||
probeCoroutineResumed(this)
|
||||
// This loop unrolls recursion in current.resumeWith(param) to make saner and shorter stack traces on resume
|
||||
@@ -27,13 +27,13 @@ internal abstract class BaseContinuationImpl(
|
||||
while (true) {
|
||||
with(current) {
|
||||
val completion = completion!! // fail fast when trying to resume continuation without completion
|
||||
val outcome: SuccessOrFailure<Any?> =
|
||||
val outcome: Result<Any?> =
|
||||
try {
|
||||
val outcome = invokeSuspend(param)
|
||||
if (outcome === COROUTINE_SUSPENDED) return
|
||||
SuccessOrFailure.success(outcome)
|
||||
Result.success(outcome)
|
||||
} catch (exception: Throwable) {
|
||||
SuccessOrFailure.failure(exception)
|
||||
Result.failure(exception)
|
||||
}
|
||||
releaseIntercepted() // this state machine instance is terminating
|
||||
if (completion is BaseContinuationImpl) {
|
||||
@@ -49,7 +49,7 @@ internal abstract class BaseContinuationImpl(
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun invokeSuspend(result: SuccessOrFailure<Any?>): Any?
|
||||
protected abstract fun invokeSuspend(result: Result<Any?>): Any?
|
||||
|
||||
protected open fun releaseIntercepted() {
|
||||
// does nothing here, overridden in ContinuationImpl
|
||||
@@ -124,7 +124,7 @@ internal object CompletedContinuation : Continuation<Any?> {
|
||||
override val context: CoroutineContext
|
||||
get() = error("This continuation is already complete")
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<Any?>) {
|
||||
override fun resumeWith(result: Result<Any?>) {
|
||||
error("This continuation is already complete")
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ private class RunSuspend : Continuation<Unit> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
var result: SuccessOrFailure<Unit>? = null
|
||||
var result: Result<Unit>? = null
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<Unit>) = synchronized(this) {
|
||||
override fun resumeWith(result: Result<Unit>) = synchronized(this) {
|
||||
this.result = result
|
||||
(this as Object).notifyAll()
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ private class MyContinuation : BaseContinuationImpl(null) {
|
||||
|
||||
var label = 0
|
||||
|
||||
override fun invokeSuspend(result: SuccessOrFailure<Any?>): Any? = null
|
||||
override fun invokeSuspend(result: Result<Any?>): Any? = null
|
||||
}
|
||||
|
||||
class DebugMetadataTest {
|
||||
|
||||
+6
-6
@@ -7,7 +7,7 @@ package test.kotlin
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
class SuccessOrFailureTest {
|
||||
class ResultTest {
|
||||
@Test
|
||||
fun testRunCatchingSuccess() {
|
||||
val ok = runCatching { "OK" }
|
||||
@@ -22,17 +22,17 @@ class SuccessOrFailureTest {
|
||||
|
||||
@Test
|
||||
fun testConstructedSuccess() {
|
||||
val ok = SuccessOrFailure.success("OK")
|
||||
val ok = Result.success("OK")
|
||||
checkSuccess(ok, "OK", true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testConstructedFailure() {
|
||||
val fail = SuccessOrFailure.failure<Unit>(IllegalStateException("F"))
|
||||
val fail = Result.failure<Unit>(IllegalStateException("F"))
|
||||
checkFailure(fail, "F", true)
|
||||
}
|
||||
|
||||
private fun <T> checkSuccess(ok: SuccessOrFailure<T>, v: T, topLevel: Boolean = false) {
|
||||
private fun <T> checkSuccess(ok: Result<T>, v: T, topLevel: Boolean = false) {
|
||||
assertTrue(ok.isSuccess)
|
||||
assertFalse(ok.isFailure)
|
||||
assertEquals(v, ok.getOrThrow())
|
||||
@@ -44,7 +44,7 @@ class SuccessOrFailureTest {
|
||||
assertEquals("V:$v", ok.fold({ "V:$it" }, { "EX:$it" }))
|
||||
assertEquals(null, ok.exceptionOrNull())
|
||||
assertEquals(null, ok.fold(onSuccess = { null }, onFailure = { it }))
|
||||
assertEquals(v.toString(), ok.toString())
|
||||
assertEquals("Success($v)", ok.toString())
|
||||
assertEquals(ok, ok)
|
||||
if (topLevel) {
|
||||
checkSuccess(ok.map { 42 }, 42)
|
||||
@@ -62,7 +62,7 @@ class SuccessOrFailureTest {
|
||||
assertEquals(0, fCnt)
|
||||
}
|
||||
|
||||
private fun <T> checkFailure(fail: SuccessOrFailure<T>, msg: String, topLevel: Boolean = false) {
|
||||
private fun <T> checkFailure(fail: Result<T>, msg: String, topLevel: Boolean = false) {
|
||||
assertFalse(fail.isSuccess)
|
||||
assertTrue(fail.isFailure)
|
||||
assertFails { fail.getOrThrow() }
|
||||
@@ -41,7 +41,7 @@ class TestDispatcher(
|
||||
inner class DispatchedContinuation<T>(val delegate: Continuation<T>) : Continuation<T> {
|
||||
override val context: CoroutineContext = delegate.context
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<T>) {
|
||||
override fun resumeWith(result: Result<T>) {
|
||||
executor.execute {
|
||||
delegate.resumeWith(result)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("UNCHECKED_CAST", "RedundantVisibilityModifier")
|
||||
|
||||
package kotlin
|
||||
|
||||
import kotlin.contracts.*
|
||||
import kotlin.internal.InlineOnly
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
/**
|
||||
* A discriminated union that encapsulates successful outcome with a value of type [T]
|
||||
* or a failure with an arbitrary [Throwable] exception.
|
||||
*/
|
||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
||||
public inline class Result<out T> @PublishedApi internal constructor(
|
||||
@PublishedApi
|
||||
internal val value: Any?
|
||||
) : Serializable {
|
||||
// discovery
|
||||
|
||||
/**
|
||||
* Returns `true` if this instance represents successful outcome.
|
||||
* In this case [isFailure] returns `false`.
|
||||
*/
|
||||
public val isSuccess: Boolean get() = value !is Failure
|
||||
|
||||
/**
|
||||
* Returns `true` if this instance represents failed outcome.
|
||||
* In this case [isSuccess] returns `false`.
|
||||
*/
|
||||
public val isFailure: Boolean get() = value is Failure
|
||||
|
||||
// value & exception retrieval
|
||||
|
||||
/**
|
||||
* Returns the encapsulated value if this instance represents [success][Result.isSuccess] or `null`
|
||||
* if it is [failure][Result.isFailure].
|
||||
*
|
||||
* This function is shorthand for `getOrElse { null }` (see [getOrElse]) or
|
||||
* `fold(onSuccess = { it }, onFailure = { null })` (see [fold]).
|
||||
*/
|
||||
public fun getOrNull(): T? =
|
||||
when (value) {
|
||||
is Failure -> null
|
||||
else -> value as T
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
is Failure -> value.exception
|
||||
else -> null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string `Success(v)` if this instance represents [success][Result.isSuccess]
|
||||
* where `v` is a string representation of the value or a string `Failure(x)` if
|
||||
* it is [failure][isFailure] where `x` is a string representation of the exception.
|
||||
*/
|
||||
public override fun toString(): String =
|
||||
when (value) {
|
||||
is Failure -> value.toString() // "Failure($exception)"
|
||||
else -> "Success($value)"
|
||||
}
|
||||
|
||||
// companion with constructors
|
||||
|
||||
/**
|
||||
* Companion object for [Result] class that contains its constructor functions
|
||||
* [success] and [failure].
|
||||
*/
|
||||
public companion object {
|
||||
/**
|
||||
* Returns an instance that encapsulates the given [value] as successful value.
|
||||
*/
|
||||
@InlineOnly public inline fun <T> success(value: T): Result<T> =
|
||||
Result(value)
|
||||
|
||||
/**
|
||||
* Returns an instance that encapsulates the given [exception] as failure.
|
||||
*/
|
||||
@InlineOnly public inline fun <T> failure(exception: Throwable): Result<T> =
|
||||
Result(createFailure(exception))
|
||||
}
|
||||
|
||||
internal class Failure(
|
||||
@JvmField
|
||||
val exception: Throwable
|
||||
) : Serializable {
|
||||
override fun equals(other: Any?): Boolean = other is Failure && exception == other.exception
|
||||
override fun hashCode(): Int = exception.hashCode()
|
||||
override fun toString(): String = "Failure($exception)"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of internal marker [Result.Failure] class to
|
||||
* make sure that this class is not exposed in ABI.
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun createFailure(exception: Throwable): Any =
|
||||
Result.Failure(exception)
|
||||
|
||||
/**
|
||||
* Throws exception if the result is failure. This internal function minimizes
|
||||
* inlined bytecode for [getOrThrow] and makes sure that in the future we can
|
||||
* add some exception-augmenting logic here (if needed).
|
||||
*/
|
||||
@PublishedApi
|
||||
internal fun Result<*>.throwOnFailure() {
|
||||
if (value is Result.Failure) throw value.exception
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the specified function [block] and returns its encapsulated result if invocation was successful,
|
||||
* catching and encapsulating any thrown exception as a failure.
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <R> runCatching(block: () -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return try {
|
||||
Result.success(block())
|
||||
} catch (e: Throwable) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the specified function [block] with `this` value as its receiver and returns its encapsulated result
|
||||
* if invocation was successful, catching and encapsulating any thrown exception as a failure.
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
|
||||
}
|
||||
return try {
|
||||
Result.success(block())
|
||||
} catch (e: Throwable) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
// -- extensions ---
|
||||
|
||||
/**
|
||||
* Returns the encapsulated value if this instance represents [success][Result.isSuccess] or throws the encapsulated exception
|
||||
* if it is [failure][Result.isFailure].
|
||||
*
|
||||
* This function is shorthand for `getOrElse { throw it }` (see [getOrElse]).
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <T> Result<T>.getOrThrow(): T {
|
||||
throwOnFailure()
|
||||
return value as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encapsulated value if this instance represents [success][Result.isSuccess] or the
|
||||
* result of [onFailure] function for encapsulated exception if it is [failure][Result.isFailure].
|
||||
*
|
||||
* 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 <R, T : R> Result<T>.getOrElse(onFailure: (exception: Throwable) -> R): R {
|
||||
contract {
|
||||
callsInPlace(onFailure, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return when(val exception = exceptionOrNull()) {
|
||||
null -> value as T
|
||||
else -> onFailure(exception)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encapsulated value if this instance represents [success][Result.isSuccess] or the
|
||||
* [defaultValue] if it is [failure][Result.isFailure].
|
||||
*
|
||||
* This function is shorthand for `getOrElse { defaultValue }` (see [getOrElse]).
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <R, T : R> Result<T>.getOrDefault(defaultValue: R): R {
|
||||
if (isFailure) return defaultValue
|
||||
return value as T
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the the result of [onSuccess] for encapsulated value if this instance represents [success][Result.isSuccess]
|
||||
* or the result of [onFailure] function for encapsulated exception if it is [failure][Result.isFailure].
|
||||
*
|
||||
* Note, that an exception thrown by [onSuccess] or by [onFailure] function is rethrown by this function.
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <R, T> Result<T>.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(val exception = exceptionOrNull()) {
|
||||
null -> onSuccess(value as T)
|
||||
else -> onFailure(exception)
|
||||
}
|
||||
}
|
||||
|
||||
// transformation
|
||||
|
||||
/**
|
||||
* Returns the encapsulated result of the given [transform] function applied to encapsulated value
|
||||
* if this instance represents [success][Result.isSuccess] or the
|
||||
* original encapsulated exception if it is [failure][Result.isFailure].
|
||||
*
|
||||
* 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 <R, T> Result<T>.map(transform: (value: T) -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return when(val exception = exceptionOrNull()) {
|
||||
null -> Result.success(transform(value as T))
|
||||
else -> Result(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encapsulated result of the given [transform] function applied to encapsulated value
|
||||
* if this instance represents [success][Result.isSuccess] or the
|
||||
* original encapsulated exception if it is [failure][Result.isFailure].
|
||||
*
|
||||
* 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 <R, T> Result<T>.mapCatching(transform: (value: T) -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return when(val exception = exceptionOrNull()) {
|
||||
null -> runCatching { transform(value as T) }
|
||||
else -> Result(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encapsulated result of the given [transform] function applied to encapsulated exception
|
||||
* if this instance represents [failure][Result.isFailure] or the
|
||||
* original encapsulated value if it is [success][Result.isSuccess].
|
||||
*
|
||||
* 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 <R, T: R> Result<T>.recover(transform: (exception: Throwable) -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
return when(val exception = exceptionOrNull()) {
|
||||
null -> this
|
||||
else -> Result.success(transform(exception))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encapsulated result of the given [transform] function applied to encapsulated exception
|
||||
* if this instance represents [failure][Result.isFailure] or the
|
||||
* original encapsulated value if it is [success][Result.isSuccess].
|
||||
*
|
||||
* 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 <R, T: R> Result<T>.recoverCatching(transform: (exception: Throwable) -> R): Result<R> {
|
||||
contract {
|
||||
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
val value = value // workaround for inline classes BE bug
|
||||
return when(val exception = exceptionOrNull()) {
|
||||
null -> this
|
||||
else -> runCatching { transform(exception) }
|
||||
}
|
||||
}
|
||||
|
||||
// "peek" onto value/exception and pipe
|
||||
|
||||
/**
|
||||
* Performs the given [action] on encapsulated value if this instance represents [success][Result.isSuccess].
|
||||
* Returns the original `Result` unchanged.
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <T> Result<T>.onFailure(action: (exception: Throwable) -> Unit): Result<T> {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
exceptionOrNull()?.let { action(it) }
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the given [action] on encapsulated exception if this instance represents [failure][Result.isFailure].
|
||||
* Returns the original `Result` unchanged.
|
||||
*/
|
||||
@InlineOnly
|
||||
public inline fun <T> Result<T>.onSuccess(action: (value: T) -> Unit): Result<T> {
|
||||
contract {
|
||||
callsInPlace(action, InvocationKind.AT_MOST_ONCE)
|
||||
}
|
||||
if (isSuccess) action(value as T)
|
||||
return this
|
||||
}
|
||||
|
||||
// -------------------
|
||||
@@ -7,6 +7,7 @@ package kotlin.coroutines
|
||||
|
||||
import kotlin.coroutines.intrinsics.*
|
||||
import kotlin.internal.InlineOnly
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
* Interface representing a continuation after a suspension point that returns value of type `T`.
|
||||
@@ -23,7 +24,7 @@ public interface Continuation<in T> {
|
||||
* Resumes the execution of the corresponding coroutine passing successful or failed [result] as the
|
||||
* return value of the last suspension point.
|
||||
*/
|
||||
public fun resumeWith(result: SuccessOrFailure<T>)
|
||||
public fun resumeWith(result: Result<T>)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +42,7 @@ public annotation class RestrictsSuspension
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@InlineOnly public inline fun <T> Continuation<T>.resume(value: T): Unit =
|
||||
resumeWith(SuccessOrFailure.success(value))
|
||||
resumeWith(Result.success(value))
|
||||
|
||||
/**
|
||||
* Resumes the execution of the corresponding coroutine so that the [exception] is re-thrown right after the
|
||||
@@ -49,7 +50,7 @@ public annotation class RestrictsSuspension
|
||||
*/
|
||||
@SinceKotlin("1.3")
|
||||
@InlineOnly public inline fun <T> Continuation<T>.resumeWithException(exception: Throwable): Unit =
|
||||
resumeWith(SuccessOrFailure.failure(exception))
|
||||
resumeWith(Result.failure(exception))
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,13 +59,13 @@ public annotation class RestrictsSuspension
|
||||
@SinceKotlin("1.3")
|
||||
@InlineOnly public inline fun <T> Continuation(
|
||||
context: CoroutineContext,
|
||||
crossinline resumeWith: (SuccessOrFailure<T>) -> Unit
|
||||
crossinline resumeWith: (Result<T>) -> Unit
|
||||
): Continuation<T> =
|
||||
object : Continuation<T> {
|
||||
override val context: CoroutineContext
|
||||
get() = context
|
||||
|
||||
override fun resumeWith(result: SuccessOrFailure<T>) =
|
||||
override fun resumeWith(result: Result<T>) =
|
||||
resumeWith(result)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ private class SequenceBuilderIterator<T> : SequenceBuilder<T>(), Iterator<T>, Co
|
||||
}
|
||||
|
||||
// Completion continuation implementation
|
||||
override fun resumeWith(result: SuccessOrFailure<Unit>) {
|
||||
override fun resumeWith(result: Result<Unit>) {
|
||||
result.getOrThrow() // just rethrow exception if it is there
|
||||
state = State_Done
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class CoroutinesReferenceValuesTest {
|
||||
bad.startCoroutine(object : Continuation<BadClass> {
|
||||
override val context: CoroutineContext = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWith(result_: SuccessOrFailure<BadClass>) {
|
||||
override fun resumeWith(result_: Result<BadClass>) {
|
||||
assertTrue(result == null)
|
||||
result = result_.getOrThrow()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user