From 9c9616d04752e5b47966917f8648fdbb62e05ba9 Mon Sep 17 00:00:00 2001 From: Aditya Wasan Date: Wed, 23 Mar 2022 18:18:06 +0530 Subject: fix: ignore `CancellationException` in suspend functions (#1794) * fix: ignore `CancellationException` in suspend functions Signed-off-by: Aditya Wasan * build(coroutine-utils): use `api` instead of `implementation` Co-authored-by: Harsh Shandilya Co-authored-by: Harsh Shandilya --- coroutine-utils/build.gradle.kts | 1 + .../aps/util/coroutines/RunSuspendCatching.kt | 48 ++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt (limited to 'coroutine-utils') diff --git a/coroutine-utils/build.gradle.kts b/coroutine-utils/build.gradle.kts index 2a20df08..78f1e8c2 100644 --- a/coroutine-utils/build.gradle.kts +++ b/coroutine-utils/build.gradle.kts @@ -10,4 +10,5 @@ plugins { dependencies { implementation(libs.kotlin.coroutines.core) implementation(libs.dagger.hilt.core) + api(libs.thirdparty.kotlinResult) } diff --git a/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt b/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt new file mode 100644 index 00000000..7e5b906c --- /dev/null +++ b/coroutine-utils/src/main/kotlin/dev/msfjarvis/aps/util/coroutines/RunSuspendCatching.kt @@ -0,0 +1,48 @@ +@file:OptIn(ExperimentalContracts::class) +@file:Suppress("RedundantSuspendModifier") + +package dev.msfjarvis.aps.util.coroutines + +import com.github.michaelbull.result.Err +import com.github.michaelbull.result.Ok +import com.github.michaelbull.result.Result +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract +import kotlinx.coroutines.CancellationException + +/** + * Calls the specified function [block] with [this] value as its receiver and returns its + * encapsulated result if invocation was successful, catching any [Throwable] except + * [CancellationException] that was thrown from the [block] function execution and encapsulating it + * as a failure. + */ +public suspend inline fun runSuspendCatching(block: () -> V): Result { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + return try { + Ok(block()) + } catch (e: Throwable) { + if (e is CancellationException) throw e + Err(e) + } +} + +/** + * Calls the specified function [block] with [this] value as its receiver and returns its + * encapsulated result if invocation was successful, catching any [Throwable] except + * [CancellationException] that was thrown from the [block] function execution and encapsulating it + * as a failure. + */ +public suspend inline infix fun T.runSuspendCatching( + block: T.() -> V +): Result { + contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + + return try { + Ok(block()) + } catch (e: Throwable) { + if (e is CancellationException) throw e + Err(e) + } +} -- cgit v1.2.3