mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-03 21:51:59 +00:00 
			
		
		
		
	FSM updates
This commit is contained in:
		@@ -2,6 +2,10 @@
 | 
			
		||||
 | 
			
		||||
## 0.9.15
 | 
			
		||||
 | 
			
		||||
* `FSM`:
 | 
			
		||||
    * Rename `DefaultUpdatableStatesMachine#compare` to `DefaultUpdatableStatesMachine#shouldReplaceJob`
 | 
			
		||||
    * `DefaultStatesManager` now is extendable
 | 
			
		||||
 | 
			
		||||
## 0.9.14
 | 
			
		||||
 | 
			
		||||
* `Versions`:
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,12 @@ open class DefaultUpdatableStatesMachine<T : State>(
 | 
			
		||||
), UpdatableStatesMachine<T> {
 | 
			
		||||
    protected val jobsStates = mutableMapOf<Job, T>()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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<T>, actualState: T, scope: CoroutineScope) {
 | 
			
		||||
        statesJobsMutex.withLock {
 | 
			
		||||
            if (compare(previousState, actualState)) {
 | 
			
		||||
@@ -52,7 +58,13 @@ open class DefaultUpdatableStatesMachine<T : State>(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected open suspend fun compare(previous: Optional<T>, new: T): Boolean = previous.dataOrNull() != new
 | 
			
		||||
    /**
 | 
			
		||||
     * Compare if [previous] potentially lead to the same behaviour with [new]
 | 
			
		||||
     */
 | 
			
		||||
    protected open suspend fun shouldReplaceJob(previous: Optional<T>, new: T): Boolean = previous.dataOrNull() != new
 | 
			
		||||
 | 
			
		||||
    @Deprecated("Overwrite shouldReplaceJob instead")
 | 
			
		||||
    protected open suspend fun compare(previous: Optional<T>, new: T): Boolean = shouldReplaceJob(previous, new)
 | 
			
		||||
 | 
			
		||||
    override suspend fun updateChain(currentState: T, newState: T) {
 | 
			
		||||
        statesManager.update(currentState, newState)
 | 
			
		||||
 
 | 
			
		||||
@@ -37,24 +37,24 @@ interface DefaultStatesManagerRepo<T : State> {
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @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<T : State>(
 | 
			
		||||
    private val repo: DefaultStatesManagerRepo<T> = InMemoryDefaultStatesManagerRepo(),
 | 
			
		||||
    private val onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true }
 | 
			
		||||
open class DefaultStatesManager<T : State>(
 | 
			
		||||
    protected val repo: DefaultStatesManagerRepo<T> = InMemoryDefaultStatesManagerRepo(),
 | 
			
		||||
    protected val onContextsConflictResolver: suspend (old: T, new: T, currentNew: T) -> Boolean = { _, _, _ -> true }
 | 
			
		||||
) : StatesManager<T> {
 | 
			
		||||
    private val _onChainStateUpdated = MutableSharedFlow<Pair<T, T>>(0)
 | 
			
		||||
    protected val _onChainStateUpdated = MutableSharedFlow<Pair<T, T>>(0)
 | 
			
		||||
    override val onChainStateUpdated: Flow<Pair<T, T>> = _onChainStateUpdated.asSharedFlow()
 | 
			
		||||
    private val _onStartChain = MutableSharedFlow<T>(0)
 | 
			
		||||
    protected val _onStartChain = MutableSharedFlow<T>(0)
 | 
			
		||||
    override val onStartChain: Flow<T> = _onStartChain.asSharedFlow()
 | 
			
		||||
    private val _onEndChain = MutableSharedFlow<T>(0)
 | 
			
		||||
    protected val _onEndChain = MutableSharedFlow<T>(0)
 | 
			
		||||
    override val onEndChain: Flow<T> = _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<T : State>(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user