1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-25 21:23:55 +08:00

Add trySafely

This commit is contained in:
Him188 2021-07-06 18:43:30 +08:00
parent 25ddb41544
commit f239192677
2 changed files with 93 additions and 0 deletions
mirai-core-utils/src
commonMain/kotlin
commonTest/kotlin/net/mamoe/mirai/utils

View File

@ -87,6 +87,36 @@ public inline fun Throwable.findCause(maxDepth: Int = 20, filter: (Throwable) ->
}
}
/**
* Run [block] and do [finally], catching exception thrown in [finally] and add it to the exception from [block].
*/
public inline fun <R> trySafely(
block: () -> R,
finally: () -> Unit,
): R {
// contract {
// callsInPlace(block, InvocationKind.EXACTLY_ONCE)
// callsInPlace(finally, InvocationKind.EXACTLY_ONCE)
// }
var eInBlock: Throwable? = null
try {
return block()
} catch (e: Throwable) {
eInBlock = e
} finally {
try {
finally()
} catch (eInFinally: Throwable) {
if (eInBlock != null) {
eInBlock.addSuppressed(eInFinally)
throw eInBlock
} else throw eInFinally
}
if (eInBlock != null) throw eInBlock
}
throw AssertionError()
}
public inline fun Throwable.findCauseOrSelf(maxDepth: Int = 20, filter: (Throwable) -> Boolean): Throwable =
findCause(maxDepth, filter) ?: this

View File

@ -0,0 +1,63 @@
/*
* Copyright 2019-2021 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.utils
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import java.io.IOException
import kotlin.test.assertEquals
import kotlin.test.assertIs
internal class TrySafelyTest {
@Test
fun `can run block`() {
assertEquals(
1,
trySafely(
block = { 1 },
finally = { }
)
)
}
@Test
fun `can run finally when no exception in block`() {
var x = 0
trySafely(
block = { },
finally = { x = 1 }
)
assertEquals(1, x)
}
@Test
fun `can run finally when exception in block`() {
var x = 0
assertThrows<Exception> {
trySafely(
block = { throw Exception() },
finally = { x = 1 }
)
}
assertEquals(1, x)
}
@Test
fun `can run finally catching`() {
assertThrows<NoSuchElementException> {
trySafely(
block = { throw NoSuchElementException() },
finally = { throw IOException() }
)
}.let { e ->
assertIs<IOException>(e.suppressed.single())
}
}
}