@@ -23,6 +23,7 @@ import com.squareup.workflow1.intercept
23
23
import com.squareup.workflow1.internal.RealRenderContext.RememberStore
24
24
import com.squareup.workflow1.internal.RealRenderContext.SideEffectRunner
25
25
import com.squareup.workflow1.trace
26
+ import com.squareup.workflow1.workflowSessionToString
26
27
import kotlinx.coroutines.CancellationException
27
28
import kotlinx.coroutines.CoroutineName
28
29
import kotlinx.coroutines.CoroutineScope
@@ -50,38 +51,42 @@ import kotlin.reflect.KType
50
51
* structured concurrency).
51
52
*/
52
53
@OptIn(WorkflowExperimentalApi ::class , WorkflowExperimentalRuntime ::class )
53
- internal class WorkflowNode <PropsT , StateT , OutputT , RenderingT >(
54
- val id : WorkflowNodeId ,
54
+ internal class StatefulWorkflowNode <PropsT , StateT , OutputT , RenderingT >(
55
+ id : WorkflowNodeId ,
55
56
workflow : StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >,
56
57
initialProps : PropsT ,
57
58
snapshot : TreeSnapshot ? ,
58
59
baseContext : CoroutineContext ,
59
60
// Providing default value so we don't need to specify in test.
60
61
override val runtimeConfig : RuntimeConfig = RuntimeConfigOptions .DEFAULT_CONFIG ,
61
62
override val workflowTracer : WorkflowTracer ? = null ,
62
- private val emitAppliedActionToParent : (ActionApplied <OutputT >) -> ActionProcessingResult =
63
- { it },
63
+ emitAppliedActionToParent : (ActionApplied <OutputT >) -> ActionProcessingResult = { it },
64
64
override val parent : WorkflowSession ? = null ,
65
- private val interceptor : WorkflowInterceptor = NoopWorkflowInterceptor ,
65
+ interceptor : WorkflowInterceptor = NoopWorkflowInterceptor ,
66
66
idCounter : IdCounter ? = null
67
- ) : CoroutineScope, SideEffectRunner, RememberStore, WorkflowSession {
67
+ ) : AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
68
+ id = id,
69
+ baseContext = baseContext,
70
+ interceptor = interceptor,
71
+ emitAppliedActionToParent = emitAppliedActionToParent,
72
+ ),
73
+ SideEffectRunner ,
74
+ RememberStore ,
75
+ WorkflowSession {
68
76
69
- /* *
70
- * Context that has a job that will live as long as this node.
71
- * Also adds a debug name to this coroutine based on its ID.
72
- */
73
- override val coroutineContext = baseContext + Job (baseContext[Job ]) + CoroutineName (id.toString())
74
-
75
- // WorkflowInstance properties
77
+ // WorkflowSession properties
76
78
override val identifier: WorkflowIdentifier get() = id.identifier
77
79
override val renderKey: String get() = id.name
78
80
override val sessionId: Long = idCounter.createId()
79
81
private var cachedWorkflowInstance: StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >
80
82
private var interceptedWorkflowInstance: StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >
81
83
84
+ override val session: WorkflowSession
85
+ get() = this
86
+
82
87
private val subtreeManager = SubtreeManager (
83
88
snapshotCache = snapshot?.childTreeSnapshots,
84
- contextForChildren = coroutineContext,
89
+ contextForChildren = scope. coroutineContext,
85
90
emitActionToParent = ::applyAction,
86
91
runtimeConfig = runtimeConfig,
87
92
workflowTracer = workflowTracer,
@@ -109,52 +114,54 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
109
114
private val context = RenderContext (baseRenderContext, workflow)
110
115
111
116
init {
112
- interceptor.onSessionStarted(this , this )
117
+ interceptor.onSessionStarted(workflowScope = scope, session = this )
113
118
114
119
cachedWorkflowInstance = workflow
115
- interceptedWorkflowInstance = interceptor.intercept(cachedWorkflowInstance, this )
116
- state = interceptedWorkflowInstance.initialState(initialProps, snapshot?.workflowSnapshot, this )
120
+ interceptedWorkflowInstance = interceptor.intercept(
121
+ workflow = cachedWorkflowInstance,
122
+ workflowSession = this
123
+ )
124
+ state = interceptedWorkflowInstance.initialState(
125
+ props = initialProps,
126
+ snapshot = snapshot?.workflowSnapshot,
127
+ workflowScope = scope
128
+ )
117
129
}
118
130
119
- override fun toString (): String {
120
- val parentDescription = parent?.let { " WorkflowInstance(…)" }
121
- return " WorkflowInstance(" +
122
- " identifier=$identifier , " +
123
- " renderKey=$renderKey , " +
124
- " instanceId=$sessionId , " +
125
- " parent=$parentDescription " +
126
- " )"
127
- }
131
+ override fun toString (): String = workflowSessionToString()
128
132
129
133
/* *
130
134
* Walk the tree of workflows, rendering each one and using
131
135
* [RenderContext][com.squareup.workflow1.BaseRenderContext] to give its children a chance to
132
136
* render themselves and aggregate those child renderings.
133
137
*/
134
138
@Suppress(" UNCHECKED_CAST" )
135
- fun render (
136
- workflow : StatefulWorkflow <PropsT , * , OutputT , RenderingT >,
139
+ override fun render (
140
+ workflow : Workflow <PropsT , OutputT , RenderingT >,
137
141
input : PropsT
138
- ): RenderingT =
139
- renderWithStateType(workflow as StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >, input)
142
+ ): RenderingT = renderWithStateType(
143
+ workflow = workflow.asStatefulWorkflow() as
144
+ StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >,
145
+ props = input
146
+ )
140
147
141
148
/* *
142
149
* Walk the tree of state machines again, this time gathering snapshots and aggregating them
143
150
* automatically.
144
151
*/
145
- fun snapshot (workflow : StatefulWorkflow < * , * , * , * > ): TreeSnapshot {
146
- @Suppress( " UNCHECKED_CAST " )
147
- val typedWorkflow = workflow as StatefulWorkflow < PropsT , StateT , OutputT , RenderingT >
148
- maybeUpdateCachedWorkflowInstance(typedWorkflow )
149
- return interceptor.onSnapshotStateWithChildren({
150
- val childSnapshots = subtreeManager.createChildSnapshots()
151
- val rootSnapshot = interceptedWorkflowInstance.snapshotState(state)
152
- TreeSnapshot (
153
- workflowSnapshot = rootSnapshot,
154
- // Create the snapshots eagerly since subtreeManager is mutable.
155
- childTreeSnapshots = { childSnapshots }
156
- )
157
- }, this )
152
+ override fun snapshot (): TreeSnapshot {
153
+ return interceptor.onSnapshotStateWithChildren(
154
+ proceed = {
155
+ val childSnapshots = subtreeManager.createChildSnapshots( )
156
+ val rootSnapshot = interceptedWorkflowInstance.snapshotState(state)
157
+ TreeSnapshot (
158
+ workflowSnapshot = rootSnapshot,
159
+ // Create the snapshots eagerly since subtreeManager is mutable.
160
+ childTreeSnapshots = { childSnapshots }
161
+ )
162
+ },
163
+ session = this
164
+ )
158
165
}
159
166
160
167
override fun runningSideEffect (
@@ -212,7 +219,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
212
219
* time of suspending.
213
220
*/
214
221
@OptIn(ExperimentalCoroutinesApi ::class , DelicateCoroutinesApi ::class )
215
- fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
222
+ override fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
216
223
// Listen for any child workflow updates.
217
224
var empty = subtreeManager.onNextChildAction(selector)
218
225
@@ -230,11 +237,11 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
230
237
/* *
231
238
* Cancels this state machine host, and any coroutines started as children of it.
232
239
*
233
- * This must be called when the caller will no longer call [onNextAction]. It is an error to call [onNextAction]
234
- * after calling this method.
240
+ * This must be called when the caller will no longer call [onNextAction]. It is an error to call
241
+ * [onNextAction] after calling this method.
235
242
*/
236
- fun cancel (cause : CancellationException ? = null ) {
237
- coroutineContext .cancel(cause)
243
+ override fun cancel (cause : CancellationException ? ) {
244
+ super .cancel(cause)
238
245
lastRendering = NullableInitBox ()
239
246
}
240
247
@@ -314,7 +321,6 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
314
321
* Applies [action] to this workflow's [state] and then passes the resulting [ActionApplied]
315
322
* via [emitAppliedActionToParent] to the parent, with additional information as to whether or
316
323
* not this action has changed the current node's state.
317
- *
318
324
*/
319
325
private fun applyAction (
320
326
action : WorkflowAction <PropsT , StateT , OutputT >,
@@ -353,7 +359,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
353
359
sideEffect : suspend CoroutineScope .() -> Unit
354
360
): SideEffectNode {
355
361
return workflowTracer.trace(" CreateSideEffectNode" ) {
356
- val scope = this + CoroutineName (" sideEffect[$key ] for $id " )
362
+ val scope = scope + CoroutineName (" sideEffect[$key ] for $id " )
357
363
val job = scope.launch(start = LAZY , block = sideEffect)
358
364
SideEffectNode (key, job)
359
365
}
0 commit comments