From 5e045219296498fc7f891429c87bd080e2fc1a0c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 15 Jun 2024 17:32:15 +0600 Subject: [PATCH 01/10] start 0.20.53 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3db6aa60047..65d186e9231 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.20.53 + ## 0.20.52 * `Coroutines`: diff --git a/gradle.properties b/gradle.properties index c2138181643..7d3b8b20a63 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,5 +15,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.20.52 -android_code_version=258 +version=0.20.53 +android_code_version=259 From 5db4c5c7171324375a107c110091e81a4dcbbdd1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 15 Jun 2024 17:37:26 +0600 Subject: [PATCH 02/10] improvements in coroutines launch safely --- .../micro_utils/coroutines/HandleSafely.kt | 84 +++++++++++++------ .../micro_utils/coroutines/LaunchSafely.kt | 8 +- 2 files changed, 61 insertions(+), 31 deletions(-) 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() } } From 93b054d55e11af045615274ca44099ef3227ede0 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sun, 16 Jun 2024 22:27:07 +0600 Subject: [PATCH 03/10] add .kotlin in gitignore --- .gitignore | 2 ++ .../micro_utils/coroutines/LaunchSafely.kt | 16 +++++----- .../micro_utils/coroutines/SupervisorJob.kt | 8 +++-- .../micro_utils/fsm/common/StatesMachine.kt | 32 +++++++++++-------- .../TemporalFilesRoutingConfigurator.kt | 2 +- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 9d766410e18..1d2d1b0e7ff 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ publishing.sh local.* local/ + +.kotlin/ 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 ea2f738fe30..5e7c6380027 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 @@ -8,34 +8,34 @@ fun CoroutineScope.launchSafely( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend CoroutineScope.() -> Unit + block: suspend () -> Unit ) = launch(context, start) { - runCatchingSafely(onException) { block() } + runCatchingSafely(onException, block = block) } fun CoroutineScope.launchSafelyWithoutExceptions( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend CoroutineScope.() -> Unit + block: suspend () -> Unit ) = launch(context, start) { - runCatchingSafelyWithoutExceptions(onException) { block() } + runCatchingSafelyWithoutExceptions(onException, block = block) } fun CoroutineScope.asyncSafely( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend CoroutineScope.() -> T + block: suspend () -> T ) = async(context, start) { - runCatchingSafely(onException) { block() } + runCatchingSafely(onException, block = block) } fun CoroutineScope.asyncSafelyWithoutExceptions( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend CoroutineScope.() -> T + block: suspend () -> T ) = async(context, start) { - runCatchingSafelyWithoutExceptions(onException) { block() } + runCatchingSafelyWithoutExceptions(onException, block = block) } diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SupervisorJob.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SupervisorJob.kt index df4131ddecd..8c4c3d010dc 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SupervisorJob.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SupervisorJob.kt @@ -10,8 +10,12 @@ fun CoroutineScope.LinkedSupervisorJob( additionalContext: CoroutineContext? = null ) = coroutineContext.LinkedSupervisorJob(additionalContext) -fun CoroutineScope.LinkedSupervisorScope( + +fun CoroutineContext.LinkedSupervisorScope( additionalContext: CoroutineContext? = null ) = CoroutineScope( - coroutineContext + LinkedSupervisorJob(additionalContext) + this + LinkedSupervisorJob(additionalContext) ) +fun CoroutineScope.LinkedSupervisorScope( + additionalContext: CoroutineContext? = null +) = coroutineContext.LinkedSupervisorScope(additionalContext) diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt index 2c4ffe1c5d7..5a2751d6db0 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt @@ -1,7 +1,6 @@ package dev.inmo.micro_utils.fsm.common import dev.inmo.micro_utils.common.Optional -import dev.inmo.micro_utils.common.onPresented import dev.inmo.micro_utils.coroutines.* import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler @@ -118,23 +117,28 @@ open class DefaultStatesMachine ( * [launchStateHandling] will returns some [State] then [statesManager] [StatesManager.update] will be used, otherwise * [StatesManager.endChain]. */ - override fun start(scope: CoroutineScope): Job = scope.launchSafelyWithoutExceptions { - (statesManager.getActiveStates().asFlow() + statesManager.onStartChain).subscribeSafelyWithoutExceptions(this) { - launch { performStateUpdate(Optional.absent(), it, scope.LinkedSupervisorScope()) } - } - statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(this) { - launch { performStateUpdate(Optional.presented(it.first), it.second, scope.LinkedSupervisorScope()) } - } - statesManager.onEndChain.subscribeSafelyWithoutExceptions(this) { removedState -> - launch { - statesJobsMutex.withLock { - val stateInMap = statesJobs.keys.firstOrNull { stateInMap -> stateInMap == removedState } - if (stateInMap === removedState) { - statesJobs[stateInMap] ?.cancel() + override fun start(scope: CoroutineScope): Job { + val supervisorScope = scope.LinkedSupervisorScope() + supervisorScope.launchSafelyWithoutExceptions { + (statesManager.getActiveStates().asFlow() + statesManager.onStartChain).subscribeSafelyWithoutExceptions(supervisorScope) { + supervisorScope.launch { performStateUpdate(Optional.absent(), it, supervisorScope) } + } + statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(supervisorScope) { + supervisorScope.launch { performStateUpdate(Optional.presented(it.first), it.second, supervisorScope) } + } + statesManager.onEndChain.subscribeSafelyWithoutExceptions(supervisorScope) { removedState -> + supervisorScope.launch { + statesJobsMutex.withLock { + val stateInMap = statesJobs.keys.firstOrNull { stateInMap -> stateInMap == removedState } + if (stateInMap === removedState) { + statesJobs[stateInMap] ?.cancel() + } } } } } + + return supervisorScope.coroutineContext.job } /** diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/TemporalFilesRoutingConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/TemporalFilesRoutingConfigurator.kt index a017e87a7a2..dd45d06741a 100644 --- a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/TemporalFilesRoutingConfigurator.kt +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/TemporalFilesRoutingConfigurator.kt @@ -41,7 +41,7 @@ class TemporalFilesRoutingConfigurator( filesMutex: Mutex, onNewFileFlow: Flow ): Job = scope.launchSafelyWithoutExceptions { - while (isActive) { + while (currentCoroutineContext().isActive) { val filesWithCreationInfo = filesMap.mapNotNull { (fileId, file) -> fileId to ((Files.getAttribute(file.toPath(), "creationTime") as? FileTime) ?.toMillis() ?: return@mapNotNull null) } From a6905e73cb071b9ce0ad3c2d61038ca26573898e Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Mon, 17 Jun 2024 01:31:50 +0600 Subject: [PATCH 04/10] small improvements --- .../ContextSafelyExceptionHandler.kt | 44 ++++++++ .../micro_utils/coroutines/HandleSafely.kt | 100 ++++-------------- 2 files changed, 65 insertions(+), 79 deletions(-) create mode 100644 coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/ContextSafelyExceptionHandler.kt diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/ContextSafelyExceptionHandler.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/ContextSafelyExceptionHandler.kt new file mode 100644 index 00000000000..140e59ae9e1 --- /dev/null +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/ContextSafelyExceptionHandler.kt @@ -0,0 +1,44 @@ +package dev.inmo.micro_utils.coroutines + +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.coroutineContext + +typealias ExceptionHandler = suspend (Throwable) -> T + +/** + * This instance will be used in all calls of [safely] where exception handler has not been passed + */ +var defaultSafelyExceptionHandler: ExceptionHandler = { throw it } + +/** + * This instance will be used in all calls of [safelyWithoutExceptions] as an exception handler for [safely] call + */ +var defaultSafelyWithoutExceptionHandler: ExceptionHandler = { + try { + defaultSafelyExceptionHandler(it) + } catch (e: Throwable) { + // do nothing + } +} + +/** + * This key can (and will) be used to get [ContextSafelyExceptionHandler] from [coroutineContext] of suspend functions + * and in [ContextSafelyExceptionHandler] for defining of its [CoroutineContext.Element.key] + * + * @see safelyWithContextExceptionHandler + * @see ContextSafelyExceptionHandler + */ +object ContextSafelyExceptionHandlerKey : CoroutineContext.Key + +/** + * [ExceptionHandler] wrapper which was created to make possible to use [handler] across all coroutines calls + * + * @see safelyWithContextExceptionHandler + * @see ContextSafelyExceptionHandlerKey + */ +class ContextSafelyExceptionHandler( + val handler: ExceptionHandler +) : CoroutineContext.Element { + override val key: CoroutineContext.Key<*> + get() = ContextSafelyExceptionHandlerKey +} \ No newline at end of file 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 33449ca5071..bf104ceaf6c 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 @@ -4,46 +4,17 @@ import kotlinx.coroutines.* import kotlin.coroutines.CoroutineContext import kotlin.coroutines.coroutineContext -typealias ExceptionHandler = suspend (Throwable) -> T - /** - * This instance will be used in all calls of [safely] where exception handler has not been passed - */ -var defaultSafelyExceptionHandler: ExceptionHandler = { throw it } - -/** - * This instance will be used in all calls of [safelyWithoutExceptions] as an exception handler for [safely] call - */ -var defaultSafelyWithoutExceptionHandler: ExceptionHandler = { - try { - defaultSafelyExceptionHandler(it) - } catch (e: Throwable) { - // do nothing - } -} - -/** - * This key can (and will) be used to get [ContextSafelyExceptionHandler] from [coroutineContext] of suspend functions - * and in [ContextSafelyExceptionHandler] for defining of its [CoroutineContext.Element.key] + * Launching [block] in [runCatching]. In case of failure, it will: * - * @see safelyWithContextExceptionHandler - * @see ContextSafelyExceptionHandler - */ -object ContextSafelyExceptionHandlerKey : CoroutineContext.Key - -/** - * [ExceptionHandler] wrapper which was created to make possible to use [handler] across all coroutines calls + * * Try to get [ContextSafelyExceptionHandler] from current [coroutineContext] and call its + * [ContextSafelyExceptionHandler.handler] invoke. **Thrown exception from its handler + * will pass out of [runCatchingSafely]** + * * Execute [onException] inside of new [runCatching] and return its result. Throws exception + * will be caught by [runCatching] and wrapped in [Result] * - * @see safelyWithContextExceptionHandler - * @see ContextSafelyExceptionHandlerKey + * @return [Result] with result of [block] if no exceptions or [Result] from [onException] execution */ -class ContextSafelyExceptionHandler( - val handler: ExceptionHandler -) : CoroutineContext.Element { - override val key: CoroutineContext.Key<*> - get() = ContextSafelyExceptionHandlerKey -} - suspend inline fun runCatchingSafely( onException: ExceptionHandler, block: suspend () -> T @@ -58,10 +29,20 @@ suspend inline fun runCatchingSafely( } } +/** + * Launching [runCatchingSafely] with [defaultSafelyExceptionHandler] as `onException` parameter + */ suspend inline fun runCatchingSafely( block: suspend () -> T ): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) +//suspend inline fun T.runCatchingSafely( +// onException: ExceptionHandler, +// block: suspend T.() -> R +//): Result = runCatchingSafely(onException) { +// block() +//} + /** * @return [ContextSafelyExceptionHandler] from [coroutineContext] by key [ContextSafelyExceptionHandlerKey] if * exists @@ -96,23 +77,9 @@ suspend fun safelyWithContextExceptionHandler( } /** - * It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions + * Calls [runCatchingSafely] and getting the result via [Result.getOrThrow] * - * 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 + * @see runCatchingSafely */ suspend inline fun safely( onException: ExceptionHandler, @@ -120,44 +87,19 @@ suspend inline fun safely( ): T = runCatchingSafely(onException, block).getOrThrow() /** - * It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions + * Calls [safely] with passing of [defaultSafelyExceptionHandler] as `onException` * - * 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 + * @see runCatchingSafely */ suspend inline fun safely( block: suspend () -> T ): T = safely(defaultSafelyExceptionHandler, block) -suspend fun T.runCatchingSafely( - onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend T.() -> R -): Result = runCatching { - safely(onException) { block() } -} - @Deprecated("Renamed", ReplaceWith("runCatchingSafely(block)", "dev.inmo.micro_utils.coroutines.runCatchingSafely")) suspend fun safelyWithResult( block: suspend () -> T ): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) -suspend fun T.safelyWithResult( - block: suspend T.() -> R -): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) - /** * Use this handler in cases you wish to include handling of exceptions by [defaultSafelyWithoutExceptionHandler] and * returning null at one time From d73e4e8e1f203708f6368ba42e06082f1746507f Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 19 Jun 2024 19:30:16 +0600 Subject: [PATCH 05/10] migrate onto 0.21.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7d3b8b20a63..ef1b439b102 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,5 +15,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.20.53 +version=0.21.0 android_code_version=259 From e661185534df6a0c79580ed846be51fe8636953b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 19 Jun 2024 19:36:02 +0600 Subject: [PATCH 06/10] fill changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d186e9231..c0756c4cce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## 0.20.53 +**THIS UPDATE CONTAINS BREAKING CHANGES IN `safely*`-ORIENTED FUNCTIONS** + +* `Coroutines`: + * **All `safely` functions lost their `supervisorScope` in favor to wrapping `runCatching`** + * `runCatchingSafely` is the main handling function of all `safely` functions + * `launchSafely*` and `asyncSafely*` blocks lost `CoroutineScope` as their receiver + ## 0.20.52 * `Coroutines`: From 90247667d193f5d94d7f04281872fefb16dbc514 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 19 Jun 2024 19:50:00 +0600 Subject: [PATCH 07/10] fix of build --- .../micro_utils/coroutines/LaunchInCurrentThread.kt | 2 +- .../inmo/micro_utils/coroutines/LaunchSynchronously.kt | 10 +++++----- safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt index d60e191281e..f3903614434 100644 --- a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt +++ b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.coroutines import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -fun launchInCurrentThread(block: suspend CoroutineScope.() -> T): T { +fun launchInCurrentThread(block: suspend () -> T): T { val scope = CoroutineScope(Dispatchers.Unconfined) return scope.launchSynchronously(block) } diff --git a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt index 7e9bfe5a205..26412f53d38 100644 --- a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt +++ b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt @@ -2,12 +2,12 @@ package dev.inmo.micro_utils.coroutines import kotlinx.coroutines.* -fun CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T): T { +fun CoroutineScope.launchSynchronously(block: suspend () -> T): T { var result: Result? = null val objectToSynchronize = Object() synchronized(objectToSynchronize) { launch(start = CoroutineStart.UNDISPATCHED) { - result = safelyWithResult(block) + result = runCatchingSafely(block) }.invokeOnCompletion { synchronized(objectToSynchronize) { objectToSynchronize.notifyAll() @@ -20,7 +20,7 @@ fun CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T return result!!.getOrThrow() } -fun launchSynchronously(block: suspend CoroutineScope.() -> T): T = CoroutineScope(Dispatchers.Default).launchSynchronously(block) +fun launchSynchronously(block: suspend () -> T): T = CoroutineScope(Dispatchers.Default).launchSynchronously(block) -fun CoroutineScope.doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block) -fun doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block) +fun CoroutineScope.doSynchronously(block: suspend () -> T): T = launchSynchronously(block) +fun doSynchronously(block: suspend () -> T): T = launchSynchronously(block) diff --git a/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt b/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt index 6426ba6703e..2687ac3c3a7 100644 --- a/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt +++ b/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt @@ -5,7 +5,9 @@ import dev.inmo.micro_utils.coroutines.runCatchingSafely interface SafeWrapper { fun safe(block: T.() -> R): Result = unsafeTarget().runCatching(block) fun unsafe(block: T.() -> R): R = unsafeTarget().block() - suspend fun safeS(block: suspend T.() -> R): Result = unsafeTarget().runCatchingSafely(block = block) + suspend fun safeS(block: suspend T.() -> R): Result = unsafeTarget().run { + runCatchingSafely(block = { block() }) + } suspend fun unsafeS(block: suspend T.() -> R): R = unsafeTarget().block() fun unsafeTarget(): T From ab58478686327b2169ed462690179dda51b8a024 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 19 Jun 2024 19:50:19 +0600 Subject: [PATCH 08/10] Revert "fix of build" This reverts commit 90247667d193f5d94d7f04281872fefb16dbc514. --- .../micro_utils/coroutines/LaunchInCurrentThread.kt | 2 +- .../inmo/micro_utils/coroutines/LaunchSynchronously.kt | 10 +++++----- safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt index f3903614434..d60e191281e 100644 --- a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt +++ b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchInCurrentThread.kt @@ -3,7 +3,7 @@ package dev.inmo.micro_utils.coroutines import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -fun launchInCurrentThread(block: suspend () -> T): T { +fun launchInCurrentThread(block: suspend CoroutineScope.() -> T): T { val scope = CoroutineScope(Dispatchers.Unconfined) return scope.launchSynchronously(block) } diff --git a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt index 26412f53d38..7e9bfe5a205 100644 --- a/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt +++ b/coroutines/src/jvmMain/kotlin/dev/inmo/micro_utils/coroutines/LaunchSynchronously.kt @@ -2,12 +2,12 @@ package dev.inmo.micro_utils.coroutines import kotlinx.coroutines.* -fun CoroutineScope.launchSynchronously(block: suspend () -> T): T { +fun CoroutineScope.launchSynchronously(block: suspend CoroutineScope.() -> T): T { var result: Result? = null val objectToSynchronize = Object() synchronized(objectToSynchronize) { launch(start = CoroutineStart.UNDISPATCHED) { - result = runCatchingSafely(block) + result = safelyWithResult(block) }.invokeOnCompletion { synchronized(objectToSynchronize) { objectToSynchronize.notifyAll() @@ -20,7 +20,7 @@ fun CoroutineScope.launchSynchronously(block: suspend () -> T): T { return result!!.getOrThrow() } -fun launchSynchronously(block: suspend () -> T): T = CoroutineScope(Dispatchers.Default).launchSynchronously(block) +fun launchSynchronously(block: suspend CoroutineScope.() -> T): T = CoroutineScope(Dispatchers.Default).launchSynchronously(block) -fun CoroutineScope.doSynchronously(block: suspend () -> T): T = launchSynchronously(block) -fun doSynchronously(block: suspend () -> T): T = launchSynchronously(block) +fun CoroutineScope.doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block) +fun doSynchronously(block: suspend CoroutineScope.() -> T): T = launchSynchronously(block) diff --git a/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt b/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt index 2687ac3c3a7..6426ba6703e 100644 --- a/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt +++ b/safe_wrapper/src/commonMain/kotlin/SafeWrapper.kt @@ -5,9 +5,7 @@ import dev.inmo.micro_utils.coroutines.runCatchingSafely interface SafeWrapper { fun safe(block: T.() -> R): Result = unsafeTarget().runCatching(block) fun unsafe(block: T.() -> R): R = unsafeTarget().block() - suspend fun safeS(block: suspend T.() -> R): Result = unsafeTarget().run { - runCatchingSafely(block = { block() }) - } + suspend fun safeS(block: suspend T.() -> R): Result = unsafeTarget().runCatchingSafely(block = block) suspend fun unsafeS(block: suspend T.() -> R): R = unsafeTarget().block() fun unsafeTarget(): T From ec9802946779794bedcdec5bab2649e19f2886ea Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 19 Jun 2024 20:03:14 +0600 Subject: [PATCH 09/10] get back old function to break less API --- .../micro_utils/coroutines/HandleSafely.kt | 20 ++++++++++++++++ .../micro_utils/coroutines/LaunchSafely.kt | 24 ++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) 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 bf104ceaf6c..ce84e2c71fe 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 @@ -29,6 +29,13 @@ suspend inline fun runCatchingSafely( } } +suspend inline fun R.runCatchingSafely( + onException: ExceptionHandler, + block: suspend R.() -> T +): Result = runCatchingSafely(onException) { + block() +} + /** * Launching [runCatchingSafely] with [defaultSafelyExceptionHandler] as `onException` parameter */ @@ -36,6 +43,12 @@ suspend inline fun runCatchingSafely( block: suspend () -> T ): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) +suspend inline fun R.runCatchingSafely( + block: suspend R.() -> T +): Result = runCatchingSafely { + block() +} + //suspend inline fun T.runCatchingSafely( // onException: ExceptionHandler, // block: suspend T.() -> R @@ -94,11 +107,18 @@ suspend inline fun safely( suspend inline fun safely( block: suspend () -> T ): T = safely(defaultSafelyExceptionHandler, block) +suspend inline fun R.safely( + block: suspend R.() -> T +): T = safely { block() } @Deprecated("Renamed", ReplaceWith("runCatchingSafely(block)", "dev.inmo.micro_utils.coroutines.runCatchingSafely")) suspend fun safelyWithResult( block: suspend () -> T ): Result = runCatchingSafely(defaultSafelyExceptionHandler, block) +@Deprecated("Renamed", ReplaceWith("this.runCatchingSafely(block)", "dev.inmo.micro_utils.coroutines.runCatchingSafely")) +suspend fun R.safelyWithResult( + block: suspend R.() -> T +): Result = safelyWithResult { block() } /** * Use this handler in cases you wish to include handling of exceptions by [defaultSafelyWithoutExceptionHandler] and 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 5e7c6380027..13583d2c622 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 @@ -8,34 +8,42 @@ fun CoroutineScope.launchSafely( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend () -> Unit + block: suspend CoroutineScope.() -> Unit ) = launch(context, start) { - runCatchingSafely(onException, block = block) + runCatchingSafely(onException) { + block() + } } fun CoroutineScope.launchSafelyWithoutExceptions( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend () -> Unit + block: suspend CoroutineScope.() -> Unit ) = launch(context, start) { - runCatchingSafelyWithoutExceptions(onException, block = block) + runCatchingSafelyWithoutExceptions(onException) { + block() + } } fun CoroutineScope.asyncSafely( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyExceptionHandler, - block: suspend () -> T + block: suspend CoroutineScope.() -> T ) = async(context, start) { - runCatchingSafely(onException, block = block) + runCatchingSafely(onException) { + block() + } } fun CoroutineScope.asyncSafelyWithoutExceptions( context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, onException: ExceptionHandler = defaultSafelyWithoutExceptionHandlerWithNull, - block: suspend () -> T + block: suspend CoroutineScope.() -> T ) = async(context, start) { - runCatchingSafelyWithoutExceptions(onException, block = block) + runCatchingSafelyWithoutExceptions(onException) { + block() + } } From 3bfe64f797ddac049534c2769b1559e3ac7d3251 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Thu, 20 Jun 2024 01:53:42 +0600 Subject: [PATCH 10/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0756c4cce4..c2f1f156844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 0.20.53 +## 0.21.0 **THIS UPDATE CONTAINS BREAKING CHANGES IN `safely*`-ORIENTED FUNCTIONS**