Created
August 22, 2025 17:36
-
-
Save BugInMyHEAD/a85aa7599eef1de9bae89ff5ba5fe7ef to your computer and use it in GitHub Desktop.
Revisions
-
BugInMyHEAD created this gist
Aug 22, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,75 @@ package com.buginmyhead.chatter.fundamental.architecture /** * Trans-state is a coinage to indicate transition and state together in the state machine concept. * * Example for [GenericTransState], [GenericTransition], [GenericTransition.Disposal]: * ```kotlin * sealed interface Event * sealed interface TransState : GenericTransState<TransState, State, Event> * sealed interface State : TransState * * data class Transition( * override val state: State, * val sideEffect1: Any, * val sideEffect2: Any, * ) : TransState, GenericTransition<TransState, State, Event> { * * data object Disposal : Event, GenericTransition.Disposal * * } * ``` * * @param TS trans-state: the runtime type is either [GenericTransState] or [GenericTransition]. * @param S state * @param E event */ @Suppress("UNCHECKED_CAST") interface GenericTransState<TS : GenericTransState<TS, S, E>, S : TS, E> { fun transitByEvent(event: E): TS companion object { /** * @return * [GenericTransition.state] if the receiver is [GenericTransition], * or the receiver itself otherwise. */ @JvmStatic val <TS : GenericTransState<TS, S, E>, S : TS, E> TS.state: S get() = (if (this is GenericTransition<*, *, *>) state else this) as S } } /** * Transition in the state machine concept. * * Read the documentation of [GenericTransState] for an example. * * @param S state * @param E event */ interface GenericTransition<TS : GenericTransState<TS, S, E>, S : TS, E> : GenericTransState<TS, S, E> { val state: S /** * @return [state] for [Disposal] event, or `[transitByEvent]` of [state] for other events. */ override fun transitByEvent(event: E): TS = if (event is Disposal) state else state.transitByEvent(event) /** * Implement with the custom event interface. * The meaning of this event is to reset side effect state to default * by calling [transitByEvent]. * * Read the documentation of [GenericTransState] for an example. */ interface Disposal } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,68 @@ package com.buginmyhead.chatter.fundamental.architecture import com.buginmyhead.chatter.fundamental.architecture.GenericTransState.Companion.state import io.kotest.core.spec.style.FreeSpec import io.kotest.matchers.shouldBe internal class GenericTransStateTest : FreeSpec({ "state of State should be itself" { val state = StateA state.state shouldBe state } "state of Transition should be state inside Transition" { val state = StateA val transition = Transition( state = state, ) transition.state shouldBe state } "transitByEvent of Transition with ordinary event works on state inside Transition" { val state = StateA val transition = Transition( state = state, ) transition.transitByEvent(EventA) shouldBe StateA.transitByEvent(EventA) } "transitByEvent of Transition with Disposal event returns state inside Transition" { val state = StateA val transition = Transition( state = state, ) transition.transitByEvent(Transition.Disposal) shouldBe state } }) private sealed interface Event private sealed interface TransState : GenericTransState<TransState, State, Event> private sealed interface State : TransState private data object EventA : Event private data object StateA : State { override fun transitByEvent(event: Event): TransState = Transition( state = StateB ) } private data object StateB : State { override fun transitByEvent(event: Event): TransState = Transition( state = StateA ) } private data class Transition( override val state: State ) : TransState, GenericTransition<TransState, State, Event> { data object Disposal : Event, GenericTransition.Disposal }