55 * All rights reserved.
66 */
77
8+ @file:OptIn(ExperimentalContracts ::class )
9+
810package ru.nsk.kstatemachine.state
911
10- import ru.nsk.kstatemachine.event.DataExtractor
11- import ru.nsk.kstatemachine.event.defaultDataExtractor
1212import ru.nsk.kstatemachine.metainfo.MetaInfo
13- import ru.nsk.kstatemachine.state.pseudo.DefaultChoiceDataState
14- import ru.nsk.kstatemachine.state.pseudo.DefaultChoiceState
15- import ru.nsk.kstatemachine.state.pseudo.DefaultHistoryState
1613import ru.nsk.kstatemachine.statemachine.StateMachine
1714import ru.nsk.kstatemachine.statemachine.StateMachineDslMarker
18- import ru.nsk.kstatemachine.transition.EventAndArgument
1915import ru.nsk.kstatemachine.transition.TransitionDirection
2016import ru.nsk.kstatemachine.transition.TransitionDirectionProducerPolicy
2117import ru.nsk.kstatemachine.transition.TransitionParams
2218import ru.nsk.kstatemachine.visitors.CoVisitor
2319import ru.nsk.kstatemachine.visitors.GetActiveStatesVisitor
2420import ru.nsk.kstatemachine.visitors.Visitor
2521import ru.nsk.kstatemachine.visitors.VisitorAcceptor
22+ import kotlin.contracts.ExperimentalContracts
23+ import kotlin.contracts.InvocationKind
24+ import kotlin.contracts.contract
2625import kotlin.reflect.KClass
2726
2827/* *
@@ -41,6 +40,7 @@ interface IState : TransitionStateApi, VisitorAcceptor {
4140 val isFinished: Boolean
4241 val listeners: Collection <Listener >
4342 val childMode: ChildMode
43+
4444 /* *
4545 * Might be changed only during machine setup.
4646 */
@@ -91,9 +91,12 @@ interface IState : TransitionStateApi, VisitorAcceptor {
9191 }
9292}
9393
94- suspend fun <S : IState > IState.addState (state : S , init : StateBlock <S >? = null): S {
94+ suspend inline fun <S : IState > IState.addState (state : S , init : StateBlock <S >): S {
95+ contract {
96+ callsInPlace(init , InvocationKind .EXACTLY_ONCE )
97+ }
9598 addState(state)
96- if ( init != null ) state.init ()
99+ state.init ()
97100 return state
98101}
99102
@@ -238,104 +241,4 @@ inline fun <reified S : IState> IState.requireState(recursive: Boolean = true) =
238241
239242suspend operator fun <S : IState > S.invoke (block : StateBlock <S >) = block()
240243
241- fun IState.machineOrNull (): StateMachine ? = if (this is StateMachine ) this else parent?.machineOrNull()
242-
243- /* *
244- * @param name is optional and is useful for getting state instance after state machine setup
245- * with [IState.findState] and for debugging.
246- */
247- suspend fun IState.state (
248- name : String? = null,
249- childMode : ChildMode = ChildMode .EXCLUSIVE ,
250- init : StateBlock <State >? = null
251- ) = addState(DefaultState (name, childMode), init )
252-
253- suspend inline fun <reified D : Any > IState.dataState (
254- name : String? = null,
255- defaultData : D ? = null,
256- childMode : ChildMode = ChildMode .EXCLUSIVE ,
257- dataExtractor : DataExtractor <D > = defaultDataExtractor(),
258- noinline init : StateBlock <DataState <D >>? = null
259- ) = addState(defaultDataState(name, defaultData, childMode, dataExtractor), init )
260-
261- /* *
262- * A shortcut for [state] and [IState.setInitialState] calls
263- */
264- suspend fun IState.initialState (
265- name : String? = null,
266- childMode : ChildMode = ChildMode .EXCLUSIVE ,
267- init : StateBlock <State >? = null
268- ) = addInitialState(DefaultState (name, childMode), init )
269-
270- /* *
271- * @param defaultData is necessary for initial [DataState]
272- */
273- suspend inline fun <reified D : Any > IState.initialDataState (
274- name : String? = null,
275- defaultData : D ,
276- childMode : ChildMode = ChildMode .EXCLUSIVE ,
277- dataExtractor : DataExtractor <D > = defaultDataExtractor(),
278- noinline init : StateBlock <DataState <D >>? = null
279- ) = addInitialState(defaultDataState(name, defaultData, childMode, dataExtractor), init )
280-
281- /* *
282- * A shortcut for [IState.addState] and [IState.setInitialState] calls
283- */
284- suspend fun <S : IState > IState.addInitialState (state : S , init : StateBlock <S >? = null): S {
285- addState(state, init )
286- setInitialState(state)
287- return state
288- }
289-
290- /* *
291- * Helper dsl method for adding final states. This is exactly the same as simply call [IState.addState] but makes
292- * code more self expressive.
293- */
294- suspend fun <S : IFinalState > IState.addFinalState (state : S , init : StateBlock <S >? = null) =
295- addState(state, init )
296-
297- suspend fun IState.finalState (name : String? = null, init : StateBlock <FinalState >? = null) =
298- addFinalState(DefaultFinalState (name), init )
299-
300- suspend fun IState.initialFinalState (name : String? = null, init : StateBlock <FinalState >? = null) =
301- addInitialState(DefaultFinalState (name), init )
302-
303- suspend inline fun <reified D : Any > IState.finalDataState (
304- name : String? = null,
305- defaultData : D ? = null,
306- dataExtractor : DataExtractor <D > = defaultDataExtractor(),
307- noinline init : StateBlock <FinalDataState <D >>? = null
308- ) = addFinalState(defaultFinalDataState(name, defaultData, dataExtractor), init )
309-
310- suspend inline fun <reified D : Any > IState.initialFinalDataState (
311- name : String? = null,
312- defaultData : D ? = null,
313- dataExtractor : DataExtractor <D > = defaultDataExtractor(),
314- noinline init : StateBlock <FinalDataState <D >>? = null
315- ) = addInitialState(defaultFinalDataState(name, defaultData, dataExtractor), init )
316-
317- fun IState.choiceState (
318- name : String? = null,
319- choiceAction : suspend EventAndArgument <* >.() -> State
320- ) = addState(DefaultChoiceState (name, choiceAction = choiceAction))
321-
322- suspend fun IState.initialChoiceState (
323- name : String? = null,
324- choiceAction : suspend EventAndArgument <* >.() -> State
325- ) = addInitialState(DefaultChoiceState (name, choiceAction = choiceAction))
326-
327- inline fun <reified D : Any > IState.choiceDataState (
328- name : String? = null,
329- noinline choiceAction : suspend EventAndArgument <* >.() -> DataState <D >
330- ) = addState(DefaultChoiceDataState (name, D ::class , choiceAction = choiceAction))
331-
332- suspend inline fun <reified D : Any > IState.initialChoiceDataState (
333- name : String? = null,
334- noinline choiceAction : suspend EventAndArgument <* >.() -> DataState <D >
335- ) = addInitialState(DefaultChoiceDataState (name, D ::class , choiceAction = choiceAction))
336-
337- fun IState.historyState (
338- name : String? = null,
339- defaultState : IState ? = null,
340- historyType : HistoryType = HistoryType .SHALLOW ,
341- ) = addState(DefaultHistoryState (name, defaultState, historyType))
244+ fun IState.machineOrNull (): StateMachine ? = this as ? StateMachine ? : parent?.machineOrNull()
0 commit comments