POSIX error asserters and minor improvements in other classes

This commit is contained in:
Andrew Golovashevich 2025-09-05 19:10:41 +03:00
parent bcb2ba3dee
commit 53db2f0d71
6 changed files with 90 additions and 12 deletions

@ -1 +1 @@
Subproject commit 4b799c0ecfac0d501ce335147c2ed021e5d4bea9 Subproject commit e57851782134ca0613646efdf7b44d2e5a23de08

View File

@ -2,7 +2,7 @@ package ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.posix
import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKStringFromUtf8 import kotlinx.cinterop.toKStringFromUtf8
import platform.posix.errno import platform.posix.errno as native_errnoVar
import platform.posix.strerror import platform.posix.strerror
import ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.OsException import ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.OsException
@ -31,20 +31,22 @@ public class PosixApiException : OsException {
} }
override fun toString(): String = override fun toString(): String =
"<windows api exception errno=${this.errno}>" "<posix api exception errno=${this.errno}>"
public companion object { public companion object {
public fun throwFromLastWindowsErr(): Nothing { public fun getLastErrno(): Int = native_errnoVar
throw this.formatFromLastWindowsErr()
public fun throwFromLastPosixErr(): Nothing {
throw this.formatFromLastPosixErr()
} }
public fun throwFromWindowsErrCode(code: Int): Nothing { public fun throwFromPosixErrCode(code: Int): Nothing {
throw this.formatFromWindowsErrCode(code) throw this.formatFromPosixErrCode(code)
} }
public fun formatFromLastWindowsErr(): PosixApiException = this.formatFromWindowsErrCode(errno) public fun formatFromLastPosixErr(): PosixApiException = this.formatFromPosixErrCode(native_errnoVar)
public fun formatFromWindowsErrCode(code: Int): PosixApiException { public fun formatFromPosixErrCode(code: Int): PosixApiException {
var err = PosixApiException(errno = code, nativeMessage = null, customMessage = "[errno=${code}]") var err = PosixApiException(errno = code, nativeMessage = null, customMessage = "[errno=${code}]")
try { try {
val nativeMessage = this.getNativeMessageByErrno(code) val nativeMessage = this.getNativeMessageByErrno(code)
@ -61,7 +63,7 @@ public class PosixApiException : OsException {
if (raw != null) { if (raw != null) {
return raw.toKStringFromUtf8() return raw.toKStringFromUtf8()
} else { } else {
val strerrErrno = errno val strerrErrno = native_errnoVar
throw PosixApiException(errno = strerrErrno, nativeMessage = null, "[errno=${strerrErrno}]") throw PosixApiException(errno = strerrErrno, nativeMessage = null, "[errno=${strerrErrno}]")
} }
} }

View File

@ -0,0 +1,56 @@
@file:OptIn(ExperimentalContracts::class)
package ru.landgrafhomyak.utility.kotlin_native_interop_stdlib_0.posix
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlinx.cinterop.ExperimentalForeignApi
private fun _checkErrnoAndThrow(): Nothing {
val code = PosixApiException.getLastErrno()
if (code == 0)
throw RuntimeException("Function returned error status, but no error set")
PosixApiException.throwFromLastPosixErr()
}
public fun Int.zeroToWinApiErr(): Int {
if (this != 0)
return this
_checkErrnoAndThrow()
}
public fun zeroToWinApiErr(call: () -> Int): Int {
contract {
callsInPlace(call, InvocationKind.EXACTLY_ONCE)
}
val status = call()
if (status != 0)
return status
_checkErrnoAndThrow()
}
@OptIn(ExperimentalForeignApi::class)
public fun <R : Any> R?.nullToWinApiErr(): R {
if (this != null)
return this
_checkErrnoAndThrow()
}
@OptIn(ExperimentalForeignApi::class)
public fun <R : Any> nullToWinApiErr(call: () -> R?): R {
contract {
callsInPlace(call, InvocationKind.EXACTLY_ONCE)
}
val ref = call()
if (ref != null)
return ref
_checkErrnoAndThrow()
}

View File

@ -9,6 +9,7 @@ import kotlinx.cinterop.ptr
import kotlinx.cinterop.reinterpret import kotlinx.cinterop.reinterpret
import kotlinx.cinterop.toKString import kotlinx.cinterop.toKString
import kotlinx.cinterop.value import kotlinx.cinterop.value
import platform.posix.errno
import platform.windows.FORMAT_MESSAGE_ALLOCATE_BUFFER import platform.windows.FORMAT_MESSAGE_ALLOCATE_BUFFER
import platform.windows.FORMAT_MESSAGE_FROM_SYSTEM import platform.windows.FORMAT_MESSAGE_FROM_SYSTEM
import platform.windows.FORMAT_MESSAGE_IGNORE_INSERTS import platform.windows.FORMAT_MESSAGE_IGNORE_INSERTS
@ -46,6 +47,8 @@ public class WindowsApiException : OsException {
"<windows api exception errno=${this.errno}>" "<windows api exception errno=${this.errno}>"
public companion object { public companion object {
public fun getLastErrno(): UInt = GetLastError()
public fun throwFromLastWindowsErr(): Nothing { public fun throwFromLastWindowsErr(): Nothing {
throw this.formatFromLastWindowsErr() throw this.formatFromLastWindowsErr()
} }

View File

@ -9,6 +9,7 @@ import platform.windows.HANDLE
import ru.landgrafhomyak.utility.closeable_state_1.CloseableState import ru.landgrafhomyak.utility.closeable_state_1.CloseableState
import ru.landgrafhomyak.utility.closeable_state_1.HandleWrapper import ru.landgrafhomyak.utility.closeable_state_1.HandleWrapper
import ru.landgrafhomyak.utility.closeable_state_1.ManualStateManipulation import ru.landgrafhomyak.utility.closeable_state_1.ManualStateManipulation
import ru.landgrafhomyak.utility.highlevel_try_finally.safeAutoClose1
@OptIn(ExperimentalForeignApi::class) @OptIn(ExperimentalForeignApi::class)
public class WindowsHandleWrapper( public class WindowsHandleWrapper(
@ -32,4 +33,21 @@ public class WindowsHandleWrapper(
this._orig.close() this._orig.close()
zeroToWinApiErr { CloseHandle(this._orig.handle) } zeroToWinApiErr { CloseHandle(this._orig.handle) }
} }
public companion object {
@OptIn(ExperimentalContracts::class, ManualStateManipulation::class)
public fun <R> autoClosed(state: () -> CloseableState, constructor: () -> HANDLE, block: (WindowsHandleWrapper) -> R) {
contract {
callsInPlace(state, InvocationKind.EXACTLY_ONCE)
callsInPlace(constructor, InvocationKind.EXACTLY_ONCE)
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
val wrapper = WindowsHandleWrapper(constructor(), state())
safeAutoClose1(
action = { block(wrapper) },
finally = { wrapper.close() }
)
}
}
} }

View File

@ -7,11 +7,10 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.ExperimentalForeignApi
import platform.windows.ERROR_SUCCESS import platform.windows.ERROR_SUCCESS
import platform.windows.GetLastError
import platform.windows.NULL import platform.windows.NULL
private fun _checkErrnoAndThrow(): Nothing { private fun _checkErrnoAndThrow(): Nothing {
val code = GetLastError() val code = WindowsApiException.getLastErrno()
if (code == ERROR_SUCCESS.toUInt()) if (code == ERROR_SUCCESS.toUInt())
throw RuntimeException("Function returned error status, but no error set") throw RuntimeException("Function returned error status, but no error set")
WindowsApiException.throwFromLastWindowsErr() WindowsApiException.throwFromLastWindowsErr()