commonMain.pro.respawn.flowmvi.plugins.TimeTravelPlugin.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-jvm Show documentation
Show all versions of core-jvm Show documentation
A Kotlin Multiplatform MVI library based on plugins that is simple, fast, powerful & flexible
package pro.respawn.flowmvi.plugins
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.CoroutineScope
import pro.respawn.flowmvi.api.MVIAction
import pro.respawn.flowmvi.api.MVIIntent
import pro.respawn.flowmvi.api.MVIState
import pro.respawn.flowmvi.api.PipelineContext
import pro.respawn.flowmvi.dsl.StoreBuilder
import pro.respawn.flowmvi.util.CappedMutableList
/**
* A plugin that keeps track of changes in the store.
* It keeps references to last `maxStates` (inclusive) states and so on for other properties.
* Keep a reference to this plugin and use it to enable custom time travel support or validate the store's behavior
* in tests.
*/
public class TimeTravelPlugin internal constructor(
name: String,
maxStates: Int,
maxIntents: Int,
maxActions: Int,
maxExceptions: Int,
) : AbstractStorePlugin(name) {
private val _states by atomic(CappedMutableList(maxStates))
/**
* States emitted by the store, capped at [maxStates]
* The last value is the most recent.
*/
public val states: Collection get() = _states
private val _intents by atomic(CappedMutableList(maxIntents))
/**
* Intents processed by the store, capped at [maxIntents].
* The last value is the most recent.
*/
public val intents: Collection get() = _intents
private val _actions by atomic(CappedMutableList(maxActions))
/**
* Actions sent by the store, capped at [maxActions].
* The last value is the most recent.
*/
public val actions: Collection get() = _actions
private val _exceptions by atomic(CappedMutableList(maxExceptions))
/**
* Last exceptions caught by store, capped at [maxExceptions].
* The last value is the most recent.
*/
public val exceptions: Collection get() = _exceptions
/**
* Number of subscription events of the store. Never decreases.
* The last value is the most recent.
*/
public var subscriptions: Int by atomic(0)
internal set
/**
* Number of times the store was launched. Never decreases.
*/
public var starts: Int by atomic(0)
internal set
/**
* Number of the times the store was stopped. Never decreases.
*/
public var stops: Int by atomic(0)
internal set
/**
* Number of times the store has been unsubscribed from. Never decreases.
*/
public var unsubscriptions: Int by atomic(0)
private set
/**
* Reset all values of this plugin and start from scratch.
*/
public fun reset() {
_states.clear()
_intents.clear()
_actions.clear()
_exceptions.clear()
subscriptions = 0
unsubscriptions = 0
starts = 0
stops = 0
}
override suspend fun PipelineContext.onState(old: S, new: S): S = new.also { _states.add(it) }
override suspend fun PipelineContext.onIntent(intent: I): I = intent.also { _intents.add(it) }
override suspend fun PipelineContext.onAction(action: A): A = action.also { _actions.add(it) }
override suspend fun PipelineContext.onException(e: Exception): Exception = e.also { _exceptions.add(it) }
override suspend fun PipelineContext.onStart() {
starts += 1
}
override fun PipelineContext.onSubscribe(subscriberScope: CoroutineScope, subscriberCount: Int) {
subscriptions += 1
}
override fun PipelineContext.onUnsubscribe(subscriberCount: Int) {
unsubscriptions += 1
}
override fun onStop(e: Exception?) {
stops += 1
}
public companion object {
/**
* The default max size for time travel holders
*/
public const val DefaultHistorySize: Int = 64
/**
* Default time travel plugin name. Hardcoded to prevent multiple plugins from being installed.
*/
public const val Name: String = "TimeTravelPlugin"
}
}
/**
* Create a new [TimeTravelPlugin]. Keep a reference to the plugin to use its properties.
* @return the plugin.
*/
public fun timeTravelPlugin(
name: String = TimeTravelPlugin.Name,
maxStates: Int = TimeTravelPlugin.DefaultHistorySize,
maxIntents: Int = TimeTravelPlugin.DefaultHistorySize,
maxActions: Int = TimeTravelPlugin.DefaultHistorySize,
maxExceptions: Int = TimeTravelPlugin.DefaultHistorySize,
): TimeTravelPlugin = TimeTravelPlugin(name, maxStates, maxIntents, maxActions, maxExceptions)
/**
* Create a new [TimeTravelPlugin] and installs it. Keep a reference to the plugin to use its properties.
* @return the plugin.
*/
public fun StoreBuilder.timeTravel(
name: String = TimeTravelPlugin.Name,
maxStates: Int = TimeTravelPlugin.DefaultHistorySize,
maxIntents: Int = TimeTravelPlugin.DefaultHistorySize,
maxActions: Int = TimeTravelPlugin.DefaultHistorySize,
maxExceptions: Int = TimeTravelPlugin.DefaultHistorySize,
): TimeTravelPlugin = timeTravelPlugin(
name = name,
maxStates = maxStates,
maxIntents = maxIntents,
maxActions = maxActions,
maxExceptions = maxExceptions,
).also { install(it) }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy