diff --git a/src/commonMain/kotlin/ru/landgrafhomyak/utility/highlevel_try_finally/safe_autoclose.kt b/src/commonMain/kotlin/ru/landgrafhomyak/utility/highlevel_try_finally/safe_autoclose.kt index 024ee8b..70d532f 100644 --- a/src/commonMain/kotlin/ru/landgrafhomyak/utility/highlevel_try_finally/safe_autoclose.kt +++ b/src/commonMain/kotlin/ru/landgrafhomyak/utility/highlevel_try_finally/safe_autoclose.kt @@ -1,4 +1,4 @@ -@file:Suppress("unused") +@file:Suppress("unused", "DuplicatedCode") @file:JvmName("SafeAutocloseKt") package ru.landgrafhomyak.utility.highlevel_try_finally @@ -9,49 +9,97 @@ import kotlin.jvm.JvmName @Suppress("WRONG_INVOCATION_KIND") inline fun safeAutoClose1( - finally: () -> Unit, - action: () -> R + `finally`: () -> Unit, + action: () -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) - callsInPlace(finally, InvocationKind.EXACTLY_ONCE) + callsInPlace(`finally`, InvocationKind.EXACTLY_ONCE) } - return safeAutoClose3(onError = finally, onSuccess = finally, onCrossReturn = finally, action = action) + val ret: R + var wasError = false + try { + ret = action() + } catch (e1: Throwable) { + wasError = true + try { + `finally`() + } catch (e2: Throwable) { + ExceptionsKt.addSuppressed(e1, e2) + } + throw e1; + } finally { + if (!wasError) + `finally`() + } + return ret } @Suppress("WRONG_INVOCATION_KIND") inline fun safeAutoClose2( onError: () -> Unit = {}, onSuccess: () -> Unit = {}, - action: () -> R + 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) + val ret: R + var wasError = false + try { + ret = action() + } catch (e1: Throwable) { + wasError = true + try { + onError() + } catch (e2: Throwable) { + ExceptionsKt.addSuppressed(e1, e2) + } + throw e1; + } finally { + if (!wasError) + onSuccess() + } + return ret } @Suppress("WRONG_INVOCATION_KIND") inline fun safeAutoClose2e( onError: (Throwable) -> Unit = { _ -> }, onSuccess: () -> Unit = {}, - action: () -> R + 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) + val ret: R + var wasError = false + try { + ret = action() + } catch (e1: Throwable) { + wasError = true + try { + onError(e1) + } catch (e2: Throwable) { + ExceptionsKt.addSuppressed(e1, e2) + } + throw e1; + } finally { + if (!wasError) + onSuccess() + } + return ret } inline fun safeAutoClose3( onError: () -> Unit = {}, onSuccess: () -> Unit = {}, onCrossReturn: () -> Unit = {}, - action: () -> R + action: () -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE) @@ -59,14 +107,36 @@ inline fun safeAutoClose3( callsInPlace(onSuccess, InvocationKind.AT_MOST_ONCE) callsInPlace(onCrossReturn, InvocationKind.AT_MOST_ONCE) } - return safeAutoClose3e(onError = { t -> onError() }, onSuccess = onSuccess, onCrossReturn = onCrossReturn, action = action) + val ret: R + var wasError = false + var crossReturned = true + try { + ret = action() + crossReturned = false + } catch (e1: Throwable) { + wasError = true + try { + onError() + } catch (e2: Throwable) { + ExceptionsKt.addSuppressed(e1, e2) + } + throw e1 + } finally { + if (!wasError) { + if (crossReturned) + onCrossReturn() + else + onSuccess() + } + } + return ret } inline fun safeAutoClose3e( onError: (Throwable) -> Unit = { _ -> }, onSuccess: () -> Unit = {}, onCrossReturn: () -> Unit = {}, - action: () -> R + action: () -> R, ): R { contract { callsInPlace(action, InvocationKind.EXACTLY_ONCE)