@@ -23,6 +23,7 @@ import com.squareup.workflow1.intercept
2323import com.squareup.workflow1.internal.RealRenderContext.RememberStore
2424import com.squareup.workflow1.internal.RealRenderContext.SideEffectRunner
2525import com.squareup.workflow1.trace
26+ import com.squareup.workflow1.workflowSessionToString
2627import kotlinx.coroutines.CancellationException
2728import kotlinx.coroutines.CoroutineName
2829import kotlinx.coroutines.CoroutineScope
@@ -50,38 +51,42 @@ import kotlin.reflect.KType
5051 * structured concurrency).
5152 */
5253@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 ,
5556 workflow : StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >,
5657 initialProps : PropsT ,
5758 snapshot : TreeSnapshot ? ,
5859 baseContext : CoroutineContext ,
5960 // Providing default value so we don't need to specify in test.
6061 override val runtimeConfig : RuntimeConfig = RuntimeConfigOptions .DEFAULT_CONFIG ,
6162 override val workflowTracer : WorkflowTracer ? = null ,
62- private val emitAppliedActionToParent : (ActionApplied <OutputT >) -> ActionProcessingResult =
63- { it },
63+ emitAppliedActionToParent : (ActionApplied <OutputT >) -> ActionProcessingResult = { it },
6464 override val parent : WorkflowSession ? = null ,
65- private val interceptor : WorkflowInterceptor = NoopWorkflowInterceptor ,
65+ interceptor : WorkflowInterceptor = NoopWorkflowInterceptor ,
6666 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 {
6876
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
7678 override val identifier: WorkflowIdentifier get() = id.identifier
7779 override val renderKey: String get() = id.name
7880 override val sessionId: Long = idCounter.createId()
7981 private var cachedWorkflowInstance: StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >
8082 private var interceptedWorkflowInstance: StatefulWorkflow <PropsT , StateT , OutputT , RenderingT >
8183
84+ override val session: WorkflowSession
85+ get() = this
86+
8287 private val subtreeManager = SubtreeManager (
8388 snapshotCache = snapshot?.childTreeSnapshots,
84- contextForChildren = coroutineContext,
89+ contextForChildren = scope. coroutineContext,
8590 emitActionToParent = ::applyAction,
8691 runtimeConfig = runtimeConfig,
8792 workflowTracer = workflowTracer,
@@ -109,52 +114,54 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
109114 private val context = RenderContext (baseRenderContext, workflow)
110115
111116 init {
112- interceptor.onSessionStarted(this , this )
117+ interceptor.onSessionStarted(workflowScope = scope, session = this )
113118
114119 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+ )
117129 }
118130
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()
128132
129133 /* *
130134 * Walk the tree of workflows, rendering each one and using
131135 * [RenderContext][com.squareup.workflow1.BaseRenderContext] to give its children a chance to
132136 * render themselves and aggregate those child renderings.
133137 */
134138 @Suppress(" UNCHECKED_CAST" )
135- fun render (
136- workflow : StatefulWorkflow <PropsT , * , OutputT , RenderingT >,
139+ override fun render (
140+ workflow : Workflow <PropsT , OutputT , RenderingT >,
137141 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+ )
140147
141148 /* *
142149 * Walk the tree of state machines again, this time gathering snapshots and aggregating them
143150 * automatically.
144151 */
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+ )
158165 }
159166
160167 override fun runningSideEffect (
@@ -212,7 +219,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
212219 * time of suspending.
213220 */
214221 @OptIn(ExperimentalCoroutinesApi ::class , DelicateCoroutinesApi ::class )
215- fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
222+ override fun onNextAction (selector : SelectBuilder <ActionProcessingResult >): Boolean {
216223 // Listen for any child workflow updates.
217224 var empty = subtreeManager.onNextChildAction(selector)
218225
@@ -230,11 +237,11 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
230237 /* *
231238 * Cancels this state machine host, and any coroutines started as children of it.
232239 *
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.
235242 */
236- fun cancel (cause : CancellationException ? = null ) {
237- coroutineContext .cancel(cause)
243+ override fun cancel (cause : CancellationException ? ) {
244+ super .cancel(cause)
238245 lastRendering = NullableInitBox ()
239246 }
240247
@@ -314,7 +321,6 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
314321 * Applies [action] to this workflow's [state] and then passes the resulting [ActionApplied]
315322 * via [emitAppliedActionToParent] to the parent, with additional information as to whether or
316323 * not this action has changed the current node's state.
317- *
318324 */
319325 private fun applyAction (
320326 action : WorkflowAction <PropsT , StateT , OutputT >,
@@ -353,7 +359,7 @@ internal class WorkflowNode<PropsT, StateT, OutputT, RenderingT>(
353359 sideEffect : suspend CoroutineScope .() -> Unit
354360 ): SideEffectNode {
355361 return workflowTracer.trace(" CreateSideEffectNode" ) {
356- val scope = this + CoroutineName (" sideEffect[$key ] for $id " )
362+ val scope = scope + CoroutineName (" sideEffect[$key ] for $id " )
357363 val job = scope.launch(start = LAZY , block = sideEffect)
358364 SideEffectNode (key, job)
359365 }
0 commit comments