From 761b14dc65d539e09f0d6f9aadd15bb35a33e574 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 10 Oct 2026 14:25:54 +0600 Subject: [PATCH] preserve concurrency constructor validation --- CHANGELOG.md | 10 ++++++++++ .../inmo/micro_utils/coroutines/SmartKeyRWLocker.kt | 5 +++++ .../dev/inmo/micro_utils/coroutines/SmartRWLocker.kt | 4 ++++ .../inmo/micro_utils/coroutines/SmartSemaphore.kt | 12 ++++++++++-- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5578a57df60..3ab9c7ad471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ## 0.32.0 +* `Coroutines`: + * `SmartSemaphore`: + * Rewrite docs for `freePermits` property. + * Add constructor arguments requirements to fail on invalid `permits` and `acquiredPermits` values. + * `SmartRWLocker`: + * Add constructor arguments requirements to fail on invalid `readPermits` values. + * `SmartKeyRWLocker`: + * Add constructor arguments requirements to fail on invalid `globalLockerReadPermits` and `perKeyReadPermits` values. + + ## 0.31.1 * `Coroutines`: diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartKeyRWLocker.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartKeyRWLocker.kt index 1f92ed2651b..e29ce3d077b 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartKeyRWLocker.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartKeyRWLocker.kt @@ -28,6 +28,11 @@ class SmartKeyRWLocker( globalLockerWriteIsLocked: Boolean = false, private val perKeyReadPermits: Int = Int.MAX_VALUE ) { + init { + require(globalLockerReadPermits > 0) { "The maximal number 'globalLockerReadPermits' of global permits on reading ($globalLockerReadPermits) must be positive." } + require(perKeyReadPermits > 0) { "The maximal number 'perKeyReadPermits' of permits on reading per key ($perKeyReadPermits) must be positive." } + } + private val globalRWLocker: SmartRWLocker = SmartRWLocker( readPermits = globalLockerReadPermits, writeIsLocked = globalLockerWriteIsLocked diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartRWLocker.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartRWLocker.kt index f1f74e7b59f..79d925f2752 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartRWLocker.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartRWLocker.kt @@ -17,6 +17,10 @@ import kotlin.contracts.contract * * [unlockWrite] will just unlock [writeMutex] */ class SmartRWLocker(private val readPermits: Int = Int.MAX_VALUE, writeIsLocked: Boolean = false) { + init { + require(readPermits > 0) { "The maximal number 'readPermits' of permits on reading ($readPermits) must be positive." } + } + private val _readSemaphore = SmartSemaphore.Mutable(permits = readPermits, acquiredPermits = if (writeIsLocked) readPermits else 0) private val _writeMutex = SmartMutex.Mutable(locked = writeIsLocked) diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartSemaphore.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartSemaphore.kt index 43f0550e4fc..c3e8a0a869c 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartSemaphore.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/SmartSemaphore.kt @@ -29,8 +29,10 @@ sealed interface SmartSemaphore { val permitsStateFlow: StateFlow /** - * * True - locked - * * False - unlocked + * The number of the available permits. + * + * If returns `0`, it is fully acquired (locked). + * If it returns the same value as `maxPermits`, it is fully released (unlocked). */ val freePermits: Int get() = permitsStateFlow.value @@ -47,6 +49,12 @@ sealed interface SmartSemaphore { * @param locked Preset state of [freePermits] and its internal [_freePermitsStateFlow] */ class Mutable(permits: Int, acquiredPermits: Int = 0) : SmartSemaphore { + init { + require(permits > 0) { "The maximal number 'permits' of permits ($permits) must be positive." } + require(acquiredPermits >= 0) { "The number 'acquiredPermits' of initially acquired permits ($acquiredPermits) must be non-negative." } + require(permits >= acquiredPermits) { "The number 'acquiredPermits' of acquired initially permits ($acquiredPermits) must not exceed the maximal number 'permits' of permits ($permits)." } + } + override val maxPermits: Int = permits private val _freePermitsStateFlow = MutableRedeliverStateFlow(permits - acquiredPermits) override val permitsStateFlow: StateFlow = _freePermitsStateFlow.asStateFlow()