Skip to content

Commit fa508f9

Browse files
committed
Add methods for lazy state evaluation to hint api
1 parent aaa74ad commit fa508f9

File tree

5 files changed

+47
-19
lines changed

5 files changed

+47
-19
lines changed

docs/pages/export.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,12 @@ transitionConditionally<ValueEvent> {
127127
metaInfo = buildExportMetaInfo {
128128
// the library does not need to call "direction" lambda, this hint provides the result (state1) directly
129129
addStateResolutionHint("when 1", state1)
130+
// same, but uses lazy initialization for state (if the reference is not initializied yet)
131+
addLazyStateResolutionHint("when 1", lazy { state1 } )
130132
// calls "direction" lambda during export with specified Event and optional argument (lambda will return state2)
131133
addEventAndArgumentResolutionHint("when 2", ValueEvent(2))
132134
// you can specify set of states that represents parallel target states
133-
addStateResolutionHint("when 3", setOf(state1, state2))
135+
addParallelStatesResolutionHint("when 3", setOf(state1, state2))
134136
// describes stay() behaviour without calling "direction" lambda
135137
addStateResolutionHint("when 4", this@createStateMachine)
136138
// resolves to stay() by calling "direction" lambda

kstatemachine/api/kstatemachine.api

+3-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ public abstract interface class ru/nsk/kstatemachine/metainfo/ExportMetaInfo : r
106106

107107
public abstract interface class ru/nsk/kstatemachine/metainfo/ExportMetaInfoBuilder : ru/nsk/kstatemachine/metainfo/ExportMetaInfo {
108108
public abstract fun addEventAndArgumentResolutionHint (Ljava/lang/String;Lru/nsk/kstatemachine/event/Event;Ljava/lang/Object;)V
109-
public abstract fun addStateResolutionHint (Ljava/lang/String;Ljava/util/Set;)V
109+
public abstract fun addLazyParallelStatesResolutionHint (Ljava/lang/String;Ljava/util/Set;)V
110+
public abstract fun addLazyStateResolutionHint (Ljava/lang/String;Lkotlin/Lazy;)V
111+
public abstract fun addParallelStatesResolutionHint (Ljava/lang/String;Ljava/util/Set;)V
110112
public abstract fun addStateResolutionHint (Ljava/lang/String;Lru/nsk/kstatemachine/state/IState;)V
111113
}
112114

kstatemachine/src/commonMain/kotlin/ru/nsk/kstatemachine/metainfo/ExportMetaInfo.kt

+34-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import ru.nsk.kstatemachine.event.Event
1111
import ru.nsk.kstatemachine.state.IState
1212
import ru.nsk.kstatemachine.state.RedirectPseudoState
1313
import ru.nsk.kstatemachine.transition.EventAndArgument
14+
import kotlin.jvm.JvmName
1415

1516
/**
1617
* Hint to be used with [ExportMetaInfo]
@@ -27,13 +28,15 @@ sealed interface ResolutionHint
2728
internal class StateResolutionHint(
2829
val description: String,
2930
/** Allows to specify parallel target states. Must be non-empty */
30-
val targetStates: Set<IState>,
31+
lazyTargetStates: Set<Lazy<IState>>,
3132
) : ResolutionHint {
3233
init {
33-
require(targetStates.isNotEmpty()) {
34+
require(lazyTargetStates.isNotEmpty()) {
3435
"targetStates must be non-empty, use single state or multiple states for parallel transitions"
3536
}
3637
}
38+
39+
val targetStates: Set<IState> by lazy { lazyTargetStates.map { it.value }.toSet() }
3740
}
3841

3942
/**
@@ -77,8 +80,24 @@ interface ExportMetaInfoBuilder : ExportMetaInfo {
7780
/** See [StateResolutionHint] */
7881
fun addStateResolutionHint(description: String, targetState: IState)
7982

83+
/**
84+
* Allows to specify state as lazy value.
85+
* Lazy initializer should not be used to dynamically calculate a state.
86+
* Use it only to delay state's variable access.
87+
* See [StateResolutionHint]
88+
*/
89+
fun addLazyStateResolutionHint(description: String, targetState: Lazy<IState>)
90+
8091
/** See [StateResolutionHint] */
81-
fun addStateResolutionHint(description: String, targetStates: Set<IState>)
92+
fun addParallelStatesResolutionHint(description: String, targetStates: Set<IState>)
93+
94+
/**
95+
* Allows to specify parallel states as lazy values.
96+
* Lazy initializer should not be used to dynamically calculate state.
97+
* Use it only to delay state's variable access.
98+
* See [StateResolutionHint]
99+
*/
100+
fun addLazyParallelStatesResolutionHint(description: String, targetStates: Set<Lazy<IState>>)
82101

83102
/** See [EventAndArgumentResolutionHint] */
84103
fun addEventAndArgumentResolutionHint(description: String, event: Event, argument: Any? = null)
@@ -87,17 +106,22 @@ interface ExportMetaInfoBuilder : ExportMetaInfo {
87106
private data class ExportMetaInfoBuilderImpl(
88107
override val resolutionHints: MutableSet<ResolutionHint> = mutableSetOf<ResolutionHint>(),
89108
) : ExportMetaInfoBuilder {
90-
override fun addEventAndArgumentResolutionHint(description: String, event: Event, argument: Any?) {
91-
resolutionHints += EventAndArgumentResolutionHint(description, event, argument)
92-
}
109+
override fun addStateResolutionHint(description: String, targetState: IState) =
110+
addLazyStateResolutionHint(description, lazyOf(targetState))
93111

94-
override fun addStateResolutionHint(description: String, targetState: IState) {
95-
resolutionHints += StateResolutionHint(description, setOf(targetState))
96-
}
112+
override fun addLazyStateResolutionHint(description: String, targetState: Lazy<IState>) =
113+
addLazyParallelStatesResolutionHint(description, setOf(targetState))
114+
115+
override fun addParallelStatesResolutionHint(description: String, targetStates: Set<IState>) =
116+
addLazyParallelStatesResolutionHint(description, targetStates.map { lazyOf(it) }.toSet())
97117

98-
override fun addStateResolutionHint(description: String, targetStates: Set<IState>) {
118+
override fun addLazyParallelStatesResolutionHint(description: String, targetStates: Set<Lazy<IState>>) {
99119
resolutionHints += StateResolutionHint(description, targetStates)
100120
}
121+
122+
override fun addEventAndArgumentResolutionHint(description: String, event: Event, argument: Any?) {
123+
resolutionHints += EventAndArgumentResolutionHint(description, event, argument)
124+
}
101125
}
102126

103127
fun buildExportMetaInfo(builder: ExportMetaInfoBuilder.() -> Unit): ExportMetaInfo =

samples/src/commonMain/kotlin/ru/nsk/samples/PlantUmlUnsafeExportWithExportMetaInfoSample.kt

+5-5
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ fun main() = runBlocking {
3434
lateinit var state2: State
3535
lateinit var state3: State
3636
val machine = createStateMachine(this) {
37-
state2 = finalState("State2")
38-
state3 = finalState("State3")
39-
4037
initialState("State1") {
4138
transitionOn<FirstEvent> {
4239
metaInfo = buildExportMetaInfo {
@@ -50,12 +47,15 @@ fun main() = runBlocking {
5047
transitionOn<SecondEvent> {
5148
metaInfo = buildExportMetaInfo {
5249
// using StateResolutionHint does not require targetState lambda call
53-
addStateResolutionHint("data == 123", state2)
54-
addStateResolutionHint("else", state3)
50+
addLazyStateResolutionHint("data == 123", lazy { state2 })
51+
addLazyStateResolutionHint("else", lazy { state3 })
5552
}
5653
targetState = { if (event.data == 123) state2 else state3 }
5754
}
5855
}
56+
57+
state2 = finalState("State2")
58+
state3 = finalState("State3")
5959
}
6060

6161
println(machine.exportToPlantUml(showEventLabels = true, unsafeCallConditionalLambdas = true))

tests/src/commonTest/kotlin/ru/nsk/kstatemachine/metainfo/ExportMetaInfoTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,15 @@ private suspend fun createTestMachine(coroutineStarterType: CoroutineStarterType
134134
metaInfo = buildExportMetaInfo {
135135
addStateResolutionHint("when 1", state1)
136136
addEventAndArgumentResolutionHint("when 2", ValueEvent2(2))
137-
addStateResolutionHint("when 3", setOf(state1, state2))
137+
addParallelStatesResolutionHint("when 3", setOf(state1, state2))
138138
addStateResolutionHint("when 4", this@createTestStateMachine)
139139
addEventAndArgumentResolutionHint("else", ValueEvent2(5))
140140
}
141141
}
142142
val choiceState = choiceState("choiceState") { if (true) state1 else state2 }
143143
choiceState.metaInfo = buildExportMetaInfo {
144144
addStateResolutionHint("if (true)", state1)
145-
addStateResolutionHint(" ", state2)
145+
addLazyStateResolutionHint(" ", lazy { state2 })
146146
}
147147
}
148148
}

0 commit comments

Comments
 (0)