diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/HandleSafely.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/HandleSafely.kt index 3b1a93e8f0a..33449ca5071 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/HandleSafely.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/HandleSafely.kt @@ -44,6 +44,24 @@ class ContextSafelyExceptionHandler( get() = ContextSafelyExceptionHandlerKey } +suspend inline fun runCatchingSafely( + onException: ExceptionHandler, + block: suspend () -> T +): Result { + return runCatching { + block() + }.onFailure { + coroutineContext[ContextSafelyExceptionHandlerKey] ?.handler ?.invoke(it) + return runCatching { + onException(it) + } + } +} + +suspend inline fun runCatchingSafely( + block: suspend () -> T +): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) + /** * @return [ContextSafelyExceptionHandler] from [coroutineContext] by key [ContextSafelyExceptionHandlerKey] if * exists @@ -64,7 +82,7 @@ suspend fun contextSafelyExceptionHandler() = coroutineContext[ContextSafelyExce suspend fun safelyWithContextExceptionHandler( contextExceptionHandler: ExceptionHandler, safelyExceptionHandler: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend CoroutineScope.() -> T + block: suspend () -> T ): T { val contextSafelyExceptionHandler = contextSafelyExceptionHandler() ?.handler ?.let { oldHandler -> ContextSafelyExceptionHandler { @@ -96,24 +114,33 @@ suspend fun safelyWithContextExceptionHandler( * @see safelyWithoutExceptions * @see safelyWithContextExceptionHandler */ -suspend fun safely( - onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend CoroutineScope.() -> T -): T { - return try { - supervisorScope(block) - } catch (e: Throwable) { - coroutineContext[ContextSafelyExceptionHandlerKey] ?.handler ?.invoke(e) - onException(e) - } -} +suspend inline fun safely( + onException: ExceptionHandler, + block: suspend () -> T +): T = runCatchingSafely(onException, block).getOrThrow() -suspend fun runCatchingSafely( - onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend CoroutineScope.() -> T -): Result = runCatching { - safely(onException, block) -} +/** + * It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions + * + * Priorities of [ExceptionHandler]s: + * + * * [onException] In case if custom (will be used anyway if not [defaultSafelyExceptionHandler]) + * * [CoroutineContext.get] with [SafelyExceptionHandlerKey] as key + * * [defaultSafelyExceptionHandler] + * + * Remember, that [ExceptionHandler] from [CoroutineContext.get] will be used anyway if it is available. After it will + * be called [onException] + * + * @param [onException] Will be called when happen exception inside of [block]. By default will throw exception - this + * exception will be available for catching + * + * @see defaultSafelyExceptionHandler + * @see safelyWithoutExceptions + * @see safelyWithContextExceptionHandler + */ +suspend inline fun safely( + block: suspend () -> T +): T = safely(defaultSafelyExceptionHandler, block) suspend fun T.runCatchingSafely( onException: ExceptionHandler = defaultSafelyExceptionHandler, @@ -122,8 +149,9 @@ suspend fun T.runCatchingSafely( safely(onException) { block() } } +@Deprecated("Renamed", ReplaceWith("runCatchingSafely(block)", "dev.inmo.micro_utils.coroutines.runCatchingSafely")) suspend fun safelyWithResult( - block: suspend CoroutineScope.() -> T + block: suspend () -> T ): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) suspend fun T.safelyWithResult( @@ -148,18 +176,20 @@ val defaultSafelyWithoutExceptionHandlerWithNull: ExceptionHandler = { * result from exception (instead of throwing it, by default always returns null) */ suspend fun safelyWithoutExceptions( - onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend CoroutineScope.() -> T -): T? = safely(onException, block) + onException: ExceptionHandler = defaultSafelyExceptionHandler, + block: suspend () -> T +): T? = runCatchingSafely(onException, block).getOrNull() suspend fun runCatchingSafelyWithoutExceptions( - onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend CoroutineScope.() -> T -): Result = runCatching { - safelyWithoutExceptions(onException, block) + onException: ExceptionHandler = defaultSafelyExceptionHandler, + block: suspend () -> T +): Result = runCatchingSafely(onException, block).let { + if (it.isFailure) return Result.success(null) + + it } -fun CoroutineScope( +fun CoroutineScopeWithDefaultFallback( context: CoroutineContext, defaultExceptionsHandler: ExceptionHandler ) = CoroutineScope( diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSafely.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSafely.kt index ee3cd890c44..ea2f738fe30 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSafely.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSafely.kt @@ -10,7 +10,7 @@ fun CoroutineScope.launchSafely( onException: ExceptionHandler = defaultSafelyExceptionHandler, block: suspend CoroutineScope.() -> Unit ) = launch(context, start) { - safely(onException, block) + runCatchingSafely(onException) { block() } } fun CoroutineScope.launchSafelyWithoutExceptions( @@ -19,7 +19,7 @@ fun CoroutineScope.launchSafelyWithoutExceptions( onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, block: suspend CoroutineScope.() -> Unit ) = launch(context, start) { - safelyWithoutExceptions(onException, block) + runCatchingSafelyWithoutExceptions(onException) { block() } } fun CoroutineScope.asyncSafely( @@ -28,7 +28,7 @@ fun CoroutineScope.asyncSafely( onException: ExceptionHandler = defaultSafelyExceptionHandler, block: suspend CoroutineScope.() -> T ) = async(context, start) { - safely(onException, block) + runCatchingSafely(onException) { block() } } fun CoroutineScope.asyncSafelyWithoutExceptions( @@ -37,5 +37,5 @@ fun CoroutineScope.asyncSafelyWithoutExceptions( onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, block: suspend CoroutineScope.() -> T ) = async(context, start) { - safelyWithoutExceptions(onException, block) + runCatchingSafelyWithoutExceptions(onException) { block() } }