From 9739bd871e4489bec8c9e346d9d9966ccb250e08 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Tue, 22 Dec 2020 22:45:36 +0600 Subject: [PATCH] unworking version --- .../micro_utils/coroutines/HandleSafely.kt | 55 +++++++++++++------ .../HandleSafelyCoroutineContextTest.kt | 32 +++++++++++ 2 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/HandleSafelyCoroutineContextTest.kt 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 327a902cdcf..506932d5e8f 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 @@ -1,9 +1,9 @@ package dev.inmo.micro_utils.coroutines -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext +import kotlin.reflect.KClass typealias ExceptionHandler = suspend (Throwable) -> T @@ -16,13 +16,24 @@ var defaultSafelyExceptionHandler: ExceptionHandler = { throw it } * Key for [SafelyExceptionHandler] which can be used in [CoroutineContext.get] to get current default * [SafelyExceptionHandler] */ -class SafelyExceptionHandlerKey : CoroutineContext.Key> +class SafelyExceptionHandlerKey() : CoroutineContext.Key> +private val nothingSafelyEceptionHandlerKey = SafelyExceptionHandlerKey() +private val unitSafelyEceptionHandlerKey = SafelyExceptionHandlerKey() +private val exceptionHandlersKeysCache = mutableMapOf<>() /** * Shortcut for creating instance of [SafelyExceptionHandlerKey] */ @Suppress("NOTHING_TO_INLINE") -inline fun safelyExceptionHandlerKey() = SafelyExceptionHandlerKey() +inline fun safelyExceptionHandlerKey() = SafelyExceptionHandlerKey(T::class) + +/** + * Shortcut for getting instance of [SafelyExceptionHandler] from current [coroutineContext] + */ +@Suppress("NOTHING_TO_INLINE") +suspend inline fun safelyExceptionHandler() = coroutineContext[safelyExceptionHandlerKey()] +@Suppress("NOTHING_TO_INLINE") +inline fun ExceptionHandler.safelyExceptionHandler() = SafelyExceptionHandler(this, T::class) /** * Wrapper for [ExceptionHandler] which can be used in [CoroutineContext] to set local (for [CoroutineContext]) default @@ -31,11 +42,11 @@ inline fun safelyExceptionHandlerKey() = SafelyExceptionHandlerKey() * @see SafelyExceptionHandlerKey * @see ExceptionHandler */ -class SafelyExceptionHandler( - val handler: ExceptionHandler +class SafelyExceptionHandler( + val handler: ExceptionHandler, + returnKClass: KClass ) : CoroutineContext.Element { - - override val key: CoroutineContext.Key<*> = safelyExceptionHandlerKey() + override val key: CoroutineContext.Key<*> = SafelyExceptionHandlerKey(returnKClass) } /** @@ -56,18 +67,28 @@ class SafelyExceptionHandler( * @see SafelyExceptionHandler */ suspend inline fun safely( - noinline onException: ExceptionHandler = defaultSafelyExceptionHandler, - noinline block: suspend CoroutineScope.() -> T + onException: ExceptionHandler = defaultSafelyExceptionHandler, + block: suspend CoroutineScope.() -> T ): T { + val contextHandler = if (onException === defaultSafelyExceptionHandler) { + coroutineContext[nothingSafelyEceptionHandlerKey] ?: + safelyExceptionHandler() ?.let { unitHandler -> + val handler = unitHandler.handler + SafelyExceptionHandler { + handler(it) + onException(it) + } + } ?: + onException.safelyExceptionHandler() + } else { + onException.safelyExceptionHandler() + } return try { - supervisorScope(block) - } catch (e: Throwable) { - val handler = if (onException == defaultSafelyExceptionHandler) { - coroutineContext[safelyExceptionHandlerKey()] ?.handler ?: onException - } else { - onException + withContext(contextHandler) { + supervisorScope(block) } - handler(e) + } catch (e: Throwable) { + contextHandler.handler(e) } } diff --git a/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/HandleSafelyCoroutineContextTest.kt b/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/HandleSafelyCoroutineContextTest.kt new file mode 100644 index 00000000000..445ba383006 --- /dev/null +++ b/coroutines/src/jvmTest/kotlin/dev/inmo/micro_utils/coroutines/HandleSafelyCoroutineContextTest.kt @@ -0,0 +1,32 @@ +package dev.inmo.micro_utils.coroutines + +import kotlinx.coroutines.* +import kotlin.test.Test + +class HandleSafelyCoroutineContextTest { + @Test + fun testHandleSafelyCoroutineContext() { + val scope = CoroutineScope(Dispatchers.Default) + var contextHandlerHappen = false + var localHandlerHappen = false + val contextHandler: ExceptionHandler = { + contextHandlerHappen = true + } + val checkJob = scope.launch(Dispatchers.Default + contextHandler.safelyExceptionHandler()) { + safely { + safely( + { + localHandlerHappen = true + } + ) { + error("That must happen :)") + } + println(coroutineContext) + error("That must happen too:)") + } + } + launchSynchronously { checkJob.join() } + assert(contextHandlerHappen) + assert(localHandlerHappen) + } +} \ No newline at end of file