Skip to content

Commit 1f49514

Browse files
committed
[fix] Fix setting of DataState::lastData field from FinishedEvent
Add sample of using FinishedEvent along with DataState.
1 parent ade82e1 commit 1f49514

File tree

6 files changed

+67
-7
lines changed

6 files changed

+67
-7
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ fun main() {
109109
</p>
110110

111111
* [Transition on FinishedEvent sample](./samples/src/main/kotlin/ru/nsk/samples/FinishedEventSample.kt)
112+
* [FinishedEvent using with DataState sample](./samples/src/main/kotlin/ru/nsk/samples/FinishedEventDataStateSample.kt)
112113
* [Undo transition sample](./samples/src/main/kotlin/ru/nsk/samples/UndoTransitionSample.kt)
113114
* [PlantUML nested states export sample](./samples/src/main/kotlin/ru/nsk/samples/PlantUmlExportSample.kt)
114115
* [Inherit transitions by grouping states sample](./samples/src/main/kotlin/ru/nsk/samples/InheritTransitionsSample.kt)

kstatemachine/src/main/kotlin/ru/nsk/kstatemachine/DefaultDataState.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,28 @@ open class DefaultDataState<D : Any>(
2626
}
2727

2828
override fun onDoEnter(transitionParams: TransitionParams<*>) {
29+
fun assign(data: D?) {
30+
if (data != null) {
31+
_data = data
32+
_lastData = data
33+
} else {
34+
_data = lastData
35+
}
36+
}
37+
2938
if (this == transitionParams.direction.targetState) {
3039
when (val event = transitionParams.event) {
31-
is DataEvent<*> -> assignEvent(event)
32-
is WrappedEvent -> assignEvent(event.event)
33-
is FinishedEvent -> _data = dataExtractor.extractFinishedEvent(transitionParams, event) ?: lastData
34-
else -> _data = dataExtractor.extract(transitionParams) ?: lastData
40+
is DataEvent<*> -> assignData(event)
41+
is WrappedEvent -> assignData(event.event)
42+
is FinishedEvent -> assign(dataExtractor.extractFinishedEvent(transitionParams, event))
43+
else -> assign(dataExtractor.extract(transitionParams))
3544
}
3645
} else { // implicit activation
3746
_data = lastData
3847
}
3948
}
4049

41-
private fun assignEvent(event: Event) {
50+
private fun assignData(event: Event) {
4251
@Suppress("UNCHECKED_CAST")
4352
event as DataEvent<D>
4453
with(event.data) {

kstatemachine/src/main/kotlin/ru/nsk/kstatemachine/PendingEventHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private class QueuePendingEventHandlerImpl(private val machine: StateMachine) :
2424
override fun checkEmpty() = check(queue.isEmpty()) { "Event queue is not empty, internal error" }
2525

2626
override fun onPendingEvent(pendingEvent: Event, argument: Any?) {
27-
machine.log { "$machine queued event $pendingEvent with argument $argument " }
27+
machine.log { "$machine queued event ${pendingEvent::class.simpleName} with argument $argument" }
2828
queue.add(EventAndArgument(pendingEvent, argument))
2929
}
3030

kstatemachine/src/test/kotlin/ru/nsk/kstatemachine/TypesafeTransitionTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ class TypesafeTransitionTest : StringSpec({
272272
dataState = dataState(defaultData = 42)
273273
}
274274
dataState.data shouldBe 0
275+
dataState.lastData shouldBe 0
275276
}
276277

277278
"targeting DataState by conditionalTransition() with custom extractor" {
@@ -294,6 +295,7 @@ class TypesafeTransitionTest : StringSpec({
294295
}
295296
machine.processEvent(CustomDataEvent(42))
296297
dataState.data shouldBe 42
298+
dataState.lastData shouldBe 42
297299
}
298300
}) {
299301
class CustomDataEvent(val value: Int) : Event
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package ru.nsk.samples
2+
3+
import ru.nsk.kstatemachine.*
4+
import ru.nsk.samples.FinishedEventDataStateSample.IntEvent
5+
import ru.nsk.samples.FinishedEventDataStateSample.States.*
6+
7+
private object FinishedEventDataStateSample {
8+
data class IntEvent(override val data: Int) : DataEvent<Int>
9+
10+
sealed interface States {
11+
object State1 : States, DefaultState()
12+
object State2 : States, DefaultFinalDataState<Int>(dataExtractor = defaultDataExtractor())
13+
object State11 : States, DefaultState()
14+
object State12 : States, DefaultFinalDataState<Int>(dataExtractor = defaultDataExtractor())
15+
}
16+
}
17+
18+
private const val DATA = 42
19+
20+
/**
21+
* [FinishedEvent] is generated when state enters its child final state.
22+
* If final state is [DataState] the event will receive its data field value.
23+
* This data may be passed to another [DataState]
24+
*/
25+
fun main() {
26+
val machine = createStateMachine {
27+
logger = StateMachine.Logger { println(it) }
28+
29+
addInitialState(State1) {
30+
addInitialState(State11) {
31+
dataTransition<IntEvent, Int>(targetState = State12)
32+
}
33+
// State1 finished when reaches its child final state
34+
addFinalState(State12)
35+
// FinishedEvent containing data value from FinalState is generated by the library when State1 finishes
36+
transitionConditionally<FinishedEvent> {
37+
direction = { targetState(State2) }
38+
onTriggered { check(it.event.data == DATA) }
39+
}
40+
}
41+
addState(State2)
42+
}
43+
44+
machine.processEvent(IntEvent(DATA))
45+
46+
check(State2 in machine.activeStates())
47+
check(State2.lastData == DATA)
48+
}

samples/src/main/kotlin/ru/nsk/samples/FinishedEventSample.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ private object FinishedEventSample {
1616
}
1717

1818
/**
19-
* FinishedEvent is generated when state enters its child final state
19+
* [FinishedEvent] is generated when state enters its child final state
2020
*/
2121
fun main() {
2222
val machine = createStateMachine {

0 commit comments

Comments
 (0)