From 72bc8da1e755582573e031975da21b1aa686550d Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 16 Mar 2022 17:59:29 +0600 Subject: [PATCH 1/3] start 0.9.15 --- CHANGELOG.md | 2 ++ gradle.properties | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7d29a3cd4..63d6ee395de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.9.15 + ## 0.9.14 * `Versions`: diff --git a/gradle.properties b/gradle.properties index 1b5a7190bbd..da7f43bbd8f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ crypto_js_version=4.1.1 # Project data group=dev.inmo -version=0.9.14 -android_code_version=104 +version=0.9.15 +android_code_version=105 From 8f928e16e1b44059dba124ebb18785d1e4515b8b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 16 Mar 2022 18:40:21 +0600 Subject: [PATCH 2/3] FSM updates --- CHANGELOG.md | 4 ++++ .../fsm/common/UpdatableStatesMachine.kt | 14 +++++++++++++- .../common/managers/DefaultStatesManager.kt | 18 +++++++++--------- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d6ee395de..5a34dbc6b2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 0.9.15 +* `FSM`: + * Rename `DefaultUpdatableStatesMachine#compare` to `DefaultUpdatableStatesMachine#shouldReplaceJob` + * `DefaultStatesManager` now is extendable + ## 0.9.14 * `Versions`: diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt index 8d5a53f41bb..09fc45b506f 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/UpdatableStatesMachine.kt @@ -26,6 +26,12 @@ open class DefaultUpdatableStatesMachine( ), UpdatableStatesMachine { protected val jobsStates = mutableMapOf() + /** + * Realization of this update will use the [Job] of [previousState] in [statesJobs] and [jobsStates] if + * [previousState] is [Optional.presented] and [shouldReplaceJob] has returned true for [previousState] and [actualState]. In + * other words, [Job] of [previousState] WILL NOT be replaced with the new one if they are "equal". Equality of + * states is solved in [shouldReplaceJob] and can be rewritten in subclasses + */ override suspend fun performStateUpdate(previousState: Optional, actualState: T, scope: CoroutineScope) { statesJobsMutex.withLock { if (compare(previousState, actualState)) { @@ -52,7 +58,13 @@ open class DefaultUpdatableStatesMachine( } } - protected open suspend fun compare(previous: Optional, new: T): Boolean = previous.dataOrNull() != new + /** + * Compare if [previous] potentially lead to the same behaviour with [new] + */ + protected open suspend fun shouldReplaceJob(previous: Optional, new: T): Boolean = previous.dataOrNull() != new + + @Deprecated("Overwrite shouldReplaceJob instead") + protected open suspend fun compare(previous: Optional, new: T): Boolean = shouldReplaceJob(previous, new) override suspend fun updateChain(currentState: T, newState: T) { statesManager.update(currentState, newState) diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt index f1ded976fb9..426b70fd5d6 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt @@ -37,24 +37,24 @@ interface DefaultStatesManagerRepo { /** * @param repo This repo will be used as repository for storing states. All operations with this repo will happen BEFORE - * any event will be sent to [onChainStateUpdated], [onStartChain] or [onEndChain]. By default will be used + * any event will be sent to [onChainStateUpdated], [onStartChain] or [onEndChain]. By default, will be used * [InMemoryDefaultStatesManagerRepo] or you may create custom [DefaultStatesManagerRepo] and pass as [repo] parameter * @param onContextsConflictResolver Receive old [State], new one and the state currently placed on new [State.context] * key. In case when this callback will returns true, the state placed on [State.context] of new will be replaced by * new state by using [endChain] with that state */ -class DefaultStatesManager( - private val repo: DefaultStatesManagerRepo = InMemoryDefaultStatesManagerRepo(), - private val onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } +open class DefaultStatesManager( + protected val repo: DefaultStatesManagerRepo = InMemoryDefaultStatesManagerRepo(), + protected val onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true } ) : StatesManager { - private val _onChainStateUpdated = MutableSharedFlow>(0) + protected val _onChainStateUpdated = MutableSharedFlow>(0) override val onChainStateUpdated: Flow> = _onChainStateUpdated.asSharedFlow() - private val _onStartChain = MutableSharedFlow(0) + protected val _onStartChain = MutableSharedFlow(0) override val onStartChain: Flow = _onStartChain.asSharedFlow() - private val _onEndChain = MutableSharedFlow(0) + protected val _onEndChain = MutableSharedFlow(0) override val onEndChain: Flow = _onEndChain.asSharedFlow() - private val mapMutex = Mutex() + protected val mapMutex = Mutex() override suspend fun update(old: T, new: T) = mapMutex.withLock { val stateByOldContext: T? = repo.getContextState(old.context) @@ -83,7 +83,7 @@ class DefaultStatesManager( } } - private suspend fun endChainWithoutLock(state: T) { + protected open suspend fun endChainWithoutLock(state: T) { if (repo.getContextState(state.context) == state) { repo.removeState(state) _onEndChain.emit(state) From 0a615e6d788d8b741948f6039f2f20208be4be64 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 16 Mar 2022 19:35:14 +0600 Subject: [PATCH 3/3] cancel jobs of completed states in DefaultStatesMachine --- CHANGELOG.md | 1 + .../dev/inmo/micro_utils/fsm/common/StatesMachine.kt | 10 ++++++++++ .../fsm/common/managers/DefaultStatesManager.kt | 1 + 3 files changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a34dbc6b2c..aea19450f9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * `FSM`: * Rename `DefaultUpdatableStatesMachine#compare` to `DefaultUpdatableStatesMachine#shouldReplaceJob` * `DefaultStatesManager` now is extendable + * `DefaultStatesMachine` will stop all jobs of states which was removed from `statesManager` ## 0.9.14 diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt index 4a72a715784..cc8fe265ef4 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/StatesMachine.kt @@ -105,6 +105,16 @@ open class DefaultStatesMachine ( statesManager.onChainStateUpdated.subscribeSafelyWithoutExceptions(this) { launch { performStateUpdate(Optional.presented(it.first), it.second, scope.LinkedSupervisorScope()) } } + statesManager.onEndChain.subscribeSafelyWithoutExceptions(this) { removedState -> + launch { + statesJobsMutex.withLock { + val stateInMap = statesJobs.keys.firstOrNull { stateInMap -> stateInMap == removedState } + if (stateInMap === removedState) { + statesJobs[stateInMap] ?.cancel() + } + } + } + } statesManager.getActiveStates().forEach { launch { performStateUpdate(Optional.absent(), it, scope.LinkedSupervisorScope()) } diff --git a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt index 426b70fd5d6..4c67a5fbd31 100644 --- a/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt +++ b/fsm/common/src/commonMain/kotlin/dev/inmo/micro_utils/fsm/common/managers/DefaultStatesManager.kt @@ -61,6 +61,7 @@ open class DefaultStatesManager( when { stateByOldContext != old -> return@withLock stateByOldContext == null || old.context == new.context -> { + repo.removeState(old) repo.set(new) _onChainStateUpdated.emit(old to new) }