This commit is contained in:
Andrew Golovashevich 2025-03-22 14:29:02 +03:00
commit f15c03fa2b
7 changed files with 195 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
/.idea/
gradle/
.gradle/
build/
*.class
*.jar
/out/
/gradlew*
.kotlin/

36
build.gradle.kts Normal file
View File

@ -0,0 +1,36 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk
buildscript {
repositories {
mavenCentral()
maven("https://maven.landgrafhomyak.ru/")
}
dependencies {
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build:v0.3k2.1.10")
}
}
group = "ru.landgrafhomyak.utility"
version = "0.4"
repositories {
mavenCentral()
}
xomrk {
kotlin {
setCompatibilityWithKotlin(KotlinVersion.KOTLIN_2_0)
optInContracts()
defineAllMultiplatformTargets()
}
publishing {
repositories {
defineXomrkGiteaMavenRepo()
}
}
}

1
gradle.properties Normal file
View File

@ -0,0 +1 @@
kotlin.code.style=official

1
settings.gradle.kts Normal file
View File

@ -0,0 +1 @@
rootProject.name = "highlevel-try-finally"

View File

@ -0,0 +1,25 @@
package ru.landgrafhomyak.utility.highlevel_try_finally
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
class TryFinallyChainScope @PublishedApi internal constructor() {
@PublishedApi
internal var _actualException: Throwable? = null
@PublishedApi
internal fun _throw() {
this._actualException?.let { e -> throw e }
}
inline fun action(fn: () -> Unit) {
contract {
callsInPlace(fn, InvocationKind.EXACTLY_ONCE)
}
safeAutoClose3e(
onCrossReturn = { throw Error("Cross return not allowed in tryFinallyChain{action{}}") },
onError = { err -> this._actualException?.addSuppressed(err) ?: run { this._actualException = err } },
action = fn
)
}
}

View File

@ -0,0 +1,101 @@
@file:Suppress("unused")
@file:JvmName("SafeAutocloseKt")
package ru.landgrafhomyak.utility.highlevel_try_finally
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
@Suppress("WRONG_INVOCATION_KIND")
inline fun <R> safeAutoClose1(
finally: () -> Unit,
action: () -> R
): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(finally, InvocationKind.EXACTLY_ONCE)
}
return safeAutoClose3(onError = finally, onSuccess = finally, onCrossReturn = finally, action = action)
}
@Suppress("WRONG_INVOCATION_KIND")
inline fun <R> safeAutoClose2(
onError: () -> Unit = {},
onSuccess: () -> Unit = {},
action: () -> R
): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onError, InvocationKind.AT_MOST_ONCE)
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
}
return safeAutoClose3(onError = onError, onSuccess = onSuccess, onCrossReturn = onSuccess, action = action)
}
@Suppress("WRONG_INVOCATION_KIND")
inline fun <R> safeAutoClose2e(
onError: (Throwable) -> Unit = { _ -> },
onSuccess: () -> Unit = {},
action: () -> R
): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onError, InvocationKind.AT_MOST_ONCE)
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
}
return safeAutoClose3e(onError = onError, onSuccess = onSuccess, onCrossReturn = onSuccess, action = action)
}
inline fun <R> safeAutoClose3(
onError: () -> Unit = {},
onSuccess: () -> Unit = {},
onCrossReturn: () -> Unit = {},
action: () -> R
): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onError, InvocationKind.AT_MOST_ONCE)
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
callsInPlace(onCrossReturn, InvocationKind.AT_MOST_ONCE)
}
return safeAutoClose3e(onError = { t -> onError() }, onSuccess = onSuccess, onCrossReturn = onCrossReturn, action = action)
}
inline fun <R> safeAutoClose3e(
onError: (Throwable) -> Unit = { _ -> },
onSuccess: () -> Unit = {},
onCrossReturn: () -> Unit = {},
action: () -> R
): R {
contract {
callsInPlace(action, InvocationKind.EXACTLY_ONCE)
callsInPlace(onError, InvocationKind.AT_MOST_ONCE)
callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE)
callsInPlace(onCrossReturn, InvocationKind.AT_MOST_ONCE)
}
val ret: R
var wasError = false
var crossReturned = true
try {
ret = action()
crossReturned = false
} catch (e1: Throwable) {
wasError = true
try {
onError(e1)
} catch (e2: Throwable) {
e1.addSuppressed(e2)
}
throw e1
} finally {
if (!wasError) {
if (crossReturned)
onCrossReturn()
else
onSuccess()
}
}
return ret
}

View File

@ -0,0 +1,22 @@
@file:Suppress("unused")
@file:JvmName("TryFinallyChainKt")
package ru.landgrafhomyak.utility.highlevel_try_finally
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.jvm.JvmName
inline fun tryFinallyChain(chains: TryFinallyChainScope.() -> Unit) {
contract {
callsInPlace(chains, InvocationKind.EXACTLY_ONCE)
}
val scope = TryFinallyChainScope()
safeAutoClose3e(
onCrossReturn = { throw Error("Cross return not allowed in tryFinallyChain{}") },
onError = { err -> throw Error("Unexpected exception in tryFinallyChain{}; calling anything outside action{} block isn't allowed", err) },
onSuccess = { scope._throw() },
action = { chains(scope) }
)
}