@@ -21,7 +21,22 @@ private val logger = KotlinLogging.logger {}
2121
2222private const val VAR_PREFIX = " $"
2323
24- private data class ActiveTransition (val transition : Transition , val isOr : Boolean )
24+ @JvmInline
25+ value class ActiveTransition (private val wrapped : Any ) {
26+ val transition: Transition
27+ get() = if (wrapped is OrMarker ) wrapped.t else wrapped as Transition
28+
29+ val isOr: Boolean
30+ get() = wrapped is OrMarker
31+
32+ private class OrMarker (val t : Transition )
33+
34+ companion object {
35+ fun standard (t : Transition ) = ActiveTransition (t)
36+
37+ fun or (t : Transition ) = ActiveTransition (OrMarker (t))
38+ }
39+ }
2540
2641class StateMachine
2742@AssistedInject
@@ -80,15 +95,19 @@ internal constructor(
8095
8196 override val extent: Extent
8297
98+ private val eventExtent: Extent
99+
83100 private val eventTimer: Timer = runtime.metricRegistry.timer(" event.latency" )
84101
85102 init {
86- val transientContext = Context .from(specification.transient)
87103 val instanceData = Context .from(instance.data).getAll()
104+ val transientContext = Context .from(specification.transient)
105+ val eventContext = Context .empty()
88106
89107 instanceData.forEach { transientContext.create(it.name, it.value) }
90108
91109 extent = (parent?.extent ? : runtime.extent).extend(transientContext)
110+ eventExtent = extent.extend(eventContext)
92111 }
93112
94113 fun start (): Job {
@@ -149,12 +168,18 @@ internal constructor(
149168
150169 if (candidates.isEmpty()) return null
151170
152- val evalExtent =
153- activeState!! .extent.with (event.data.associate { VAR_PREFIX + it.name to it.value })
171+ val eventContext = eventExtent.high!!
154172
155- return trySelect(candidates, evalExtent)?.also {
156- event.data.forEach { d -> extent.setOrCreate(VAR_PREFIX + d.name, d.value) }
157- }
173+ event.data.forEach { eventContext.create(VAR_PREFIX + it.name, it.value) }
174+
175+ val selected =
176+ trySelect(candidates, eventExtent)?.also {
177+ event.data.forEach { d -> extent.setOrCreate(VAR_PREFIX + d.name, d.value) }
178+ }
179+
180+ eventContext.clear()
181+
182+ return selected
158183 }
159184
160185 private fun Event.isValid (): Boolean {
@@ -188,21 +213,13 @@ internal constructor(
188213 }
189214
190215 private fun trySelect (transitions : List <Transition >, evalExtent : Extent ): ActiveTransition ? {
191- val selected =
192- transitions.mapNotNull { transition ->
193- val spec = transition.specification
194- when {
195- spec.evaluate(evalExtent) -> ActiveTransition (transition, isOr = false )
196- spec.or != null -> ActiveTransition (transition, isOr = true )
197- else -> null
198- }
199- }
200-
201- return when (selected.size) {
202- 0 -> null
203- 1 -> selected.first()
204- else -> error(" non-determinism detected with selected transitions '$selected '" )
216+ for (i in transitions.indices) {
217+ val transition = transitions[i]
218+ val spec = transition.specification
219+ if (spec.evaluate(evalExtent)) return ActiveTransition .standard(transition)
220+ if (spec.or != null ) return ActiveTransition .or (transition)
205221 }
222+ return null
206223 }
207224
208225 private fun doEnter (state : State ): ActiveTransition ? {
@@ -234,13 +251,22 @@ internal constructor(
234251 private tailrec fun execute (actions : List <Action >, scope : Scope ) {
235252 if (actions.isEmpty()) return
236253
237- val next =
238- actions.flatMap { action ->
239- if (action is TimeoutResetAction ) stopTimeout(action.action)
240- actionExecutor.execute(action, scope)
254+ val nextActions = mutableListOf<Action >()
255+
256+ for (i in actions.indices) {
257+ val action = actions[i]
258+
259+ if (action is TimeoutResetAction ) {
260+ stopTimeout(action.action)
241261 }
242262
243- execute(next, scope)
263+ val result = actionExecutor.execute(action, scope)
264+ if (result.isNotEmpty()) {
265+ nextActions.addAll(result)
266+ }
267+ }
268+
269+ execute(nextActions, scope)
244270 }
245271
246272 private fun startTimeout (timeout : TimeoutAction ) {
0 commit comments