mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-11-29 21:48:45 +00:00
commit
17821bd094
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.15
|
||||||
|
|
||||||
|
* `Coroutines`:
|
||||||
|
* `safely`:
|
||||||
|
* `SafelyExceptionHandlerKey` has been deprecated
|
||||||
|
* `SafelyExceptionHandler` has been deprecated
|
||||||
|
* `ContextSafelyExceptionHandlerKey` has been added
|
||||||
|
* `ContextSafelyExceptionHandler` has been added
|
||||||
|
* `safelyWithContextExceptionHandler` has been added
|
||||||
|
|
||||||
## 0.4.14
|
## 0.4.14
|
||||||
|
|
||||||
* `Versions`:
|
* `Versions`:
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package dev.inmo.micro_utils.coroutines
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.supervisorScope
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.coroutineContext
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
@ -16,12 +15,14 @@ var defaultSafelyExceptionHandler: ExceptionHandler<Nothing> = { throw it }
|
|||||||
* Key for [SafelyExceptionHandler] which can be used in [CoroutineContext.get] to get current default
|
* Key for [SafelyExceptionHandler] which can be used in [CoroutineContext.get] to get current default
|
||||||
* [SafelyExceptionHandler]
|
* [SafelyExceptionHandler]
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This method will be useless in future major update", ReplaceWith("ContextSafelyExceptionHandlerKey", "dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler"))
|
||||||
class SafelyExceptionHandlerKey<T> : CoroutineContext.Key<SafelyExceptionHandler<T>>
|
class SafelyExceptionHandlerKey<T> : CoroutineContext.Key<SafelyExceptionHandler<T>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for creating instance of [SafelyExceptionHandlerKey]
|
* Shortcut for creating instance of [SafelyExceptionHandlerKey]
|
||||||
*/
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
@Deprecated("This method will be useless in future major update", ReplaceWith("ContextSafelyExceptionHandlerKey", "dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler"))
|
||||||
inline fun <T> safelyExceptionHandlerKey() = SafelyExceptionHandlerKey<T>()
|
inline fun <T> safelyExceptionHandlerKey() = SafelyExceptionHandlerKey<T>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,13 +32,68 @@ inline fun <T> safelyExceptionHandlerKey() = SafelyExceptionHandlerKey<T>()
|
|||||||
* @see SafelyExceptionHandlerKey
|
* @see SafelyExceptionHandlerKey
|
||||||
* @see ExceptionHandler
|
* @see ExceptionHandler
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("This method will be useless in future major update", ReplaceWith("ContextSafelyExceptionHandler", "dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler"))
|
||||||
class SafelyExceptionHandler<T>(
|
class SafelyExceptionHandler<T>(
|
||||||
val handler: ExceptionHandler<T>
|
val handler: ExceptionHandler<T>
|
||||||
) : CoroutineContext.Element {
|
) : CoroutineContext.Element {
|
||||||
|
|
||||||
override val key: CoroutineContext.Key<*> = safelyExceptionHandlerKey<T>()
|
override val key: CoroutineContext.Key<*> = safelyExceptionHandlerKey<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<ContextSafelyExceptionHandler>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [ExceptionHandler] wrapper which was created to make possible to use [handler] across all coroutines calls
|
||||||
|
*
|
||||||
|
* @see safelyWithContextExceptionHandler
|
||||||
|
* @see ContextSafelyExceptionHandlerKey
|
||||||
|
*/
|
||||||
|
class ContextSafelyExceptionHandler(
|
||||||
|
val handler: ExceptionHandler<Unit>
|
||||||
|
) : CoroutineContext.Element {
|
||||||
|
override val key: CoroutineContext.Key<*>
|
||||||
|
get() = ContextSafelyExceptionHandlerKey
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return [ContextSafelyExceptionHandler] from [coroutineContext] by key [ContextSafelyExceptionHandlerKey] if
|
||||||
|
* exists
|
||||||
|
*
|
||||||
|
* @see ContextSafelyExceptionHandler
|
||||||
|
* @see ContextSafelyExceptionHandlerKey
|
||||||
|
*/
|
||||||
|
suspend inline fun contextSafelyExceptionHandler() = coroutineContext[ContextSafelyExceptionHandlerKey]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will set new [coroutineContext] with [ContextSafelyExceptionHandler]. In case if [coroutineContext]
|
||||||
|
* already contains [ContextSafelyExceptionHandler], [ContextSafelyExceptionHandler.handler] will be used BEFORE
|
||||||
|
* [contextExceptionHandler] in case of exception.
|
||||||
|
*
|
||||||
|
* After all, will be called [withContext] method with created [ContextSafelyExceptionHandler] and block which will call
|
||||||
|
* [safely] method with [safelyExceptionHandler] as onException parameter and [block] as execution block
|
||||||
|
*/
|
||||||
|
suspend fun <T> safelyWithContextExceptionHandler(
|
||||||
|
contextExceptionHandler: ExceptionHandler<Unit>,
|
||||||
|
safelyExceptionHandler: ExceptionHandler<T> = defaultSafelyExceptionHandler,
|
||||||
|
block: suspend CoroutineScope.() -> T
|
||||||
|
): T {
|
||||||
|
val contextSafelyExceptionHandler = contextSafelyExceptionHandler() ?.handler ?.let { oldHandler ->
|
||||||
|
ContextSafelyExceptionHandler {
|
||||||
|
oldHandler(it)
|
||||||
|
contextExceptionHandler(it)
|
||||||
|
}
|
||||||
|
} ?: ContextSafelyExceptionHandler(contextExceptionHandler)
|
||||||
|
return withContext(contextSafelyExceptionHandler) {
|
||||||
|
safely(safelyExceptionHandler, block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
|
* It will run [block] inside of [supervisorScope] to avoid problems with catching of exceptions
|
||||||
*
|
*
|
||||||
@ -52,8 +108,7 @@ class SafelyExceptionHandler<T>(
|
|||||||
*
|
*
|
||||||
* @see defaultSafelyExceptionHandler
|
* @see defaultSafelyExceptionHandler
|
||||||
* @see safelyWithoutExceptions
|
* @see safelyWithoutExceptions
|
||||||
* @see SafelyExceptionHandlerKey
|
* @see safelyWithContextExceptionHandler
|
||||||
* @see SafelyExceptionHandler
|
|
||||||
*/
|
*/
|
||||||
suspend inline fun <T> safely(
|
suspend inline fun <T> safely(
|
||||||
noinline onException: ExceptionHandler<T> = defaultSafelyExceptionHandler,
|
noinline onException: ExceptionHandler<T> = defaultSafelyExceptionHandler,
|
||||||
@ -62,12 +117,8 @@ suspend inline fun <T> safely(
|
|||||||
return try {
|
return try {
|
||||||
supervisorScope(block)
|
supervisorScope(block)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
val handler = if (onException == defaultSafelyExceptionHandler) {
|
coroutineContext[ContextSafelyExceptionHandlerKey] ?.handler ?.invoke(e)
|
||||||
coroutineContext[safelyExceptionHandlerKey<T>()] ?.handler ?: onException
|
onException(e)
|
||||||
} else {
|
|
||||||
onException
|
|
||||||
}
|
|
||||||
handler(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
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
|
||||||
|
var defaultHandlerHappen = false
|
||||||
|
defaultSafelyExceptionHandler = {
|
||||||
|
defaultHandlerHappen = true
|
||||||
|
throw it
|
||||||
|
}
|
||||||
|
val contextHandler: ExceptionHandler<Unit> = {
|
||||||
|
contextHandlerHappen = true
|
||||||
|
}
|
||||||
|
val checkJob = scope.launch {
|
||||||
|
safelyWithContextExceptionHandler(contextHandler) {
|
||||||
|
safely(
|
||||||
|
{
|
||||||
|
localHandlerHappen = true
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
error("That must happen :)")
|
||||||
|
}
|
||||||
|
println(coroutineContext)
|
||||||
|
error("That must happen too:)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
launchSynchronously { checkJob.join() }
|
||||||
|
assert(contextHandlerHappen)
|
||||||
|
assert(localHandlerHappen)
|
||||||
|
assert(defaultHandlerHappen)
|
||||||
|
}
|
||||||
|
}
|
@ -40,5 +40,5 @@ dokka_version=1.4.20
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.4.14
|
version=0.4.15
|
||||||
android_code_version=18
|
android_code_version=19
|
||||||
|
Loading…
Reference in New Issue
Block a user