Skip to content

Commit 718344d

Browse files
Clean up the AbstractWorkflowNode refactor.
1 parent 44dc3ce commit 718344d

File tree

5 files changed

+45
-52
lines changed

5 files changed

+45
-52
lines changed

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/AbstractWorkflowNode.kt

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ import com.squareup.workflow1.RuntimeConfigOptions
88
import com.squareup.workflow1.TreeSnapshot
99
import com.squareup.workflow1.Workflow
1010
import com.squareup.workflow1.WorkflowExperimentalApi
11-
import com.squareup.workflow1.WorkflowIdentifier
1211
import com.squareup.workflow1.WorkflowInterceptor
1312
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
1413
import com.squareup.workflow1.WorkflowTracer
1514
import com.squareup.workflow1.compose.ComposeWorkflow
1615
import com.squareup.workflow1.internal.compose.ComposeWorkflowNodeAdapter
17-
import com.squareup.workflow1.workflowSessionToString
1816
import kotlinx.coroutines.CancellationException
1917
import kotlinx.coroutines.CoroutineName
2018
import kotlinx.coroutines.CoroutineScope
@@ -40,7 +38,6 @@ internal fun <PropsT, OutputT, RenderingT> createWorkflowNode(
4038
): AbstractWorkflowNode<PropsT, OutputT, RenderingT> = when (workflow) {
4139
is ComposeWorkflow<*, *, *> -> ComposeWorkflowNodeAdapter(
4240
id = id,
43-
workflow = workflow as ComposeWorkflow,
4441
initialProps = initialProps,
4542
snapshot = snapshot,
4643
baseContext = baseContext,
@@ -69,15 +66,15 @@ internal fun <PropsT, OutputT, RenderingT> createWorkflowNode(
6966

7067
internal abstract class AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
7168
val id: WorkflowNodeId,
72-
final override val parent: WorkflowSession?,
73-
final override val workflowTracer: WorkflowTracer?,
74-
final override val runtimeConfig: RuntimeConfig,
7569
protected val interceptor: WorkflowInterceptor,
7670
protected val emitAppliedActionToParent: (ActionApplied<OutputT>) -> ActionProcessingResult,
7771
baseContext: CoroutineContext,
78-
idCounter: IdCounter?,
79-
) : WorkflowSession,
80-
CoroutineScope {
72+
) : CoroutineScope {
73+
74+
/**
75+
* The [WorkflowSession] that represents this node to [WorkflowInterceptor]s.
76+
*/
77+
abstract val session: WorkflowSession
8178

8279
/**
8380
* Context that has a job that will live as long as this node.
@@ -87,13 +84,6 @@ internal abstract class AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
8784
Job(baseContext[Job]) +
8885
CoroutineName(id.toString())
8986

90-
// WorkflowSession properties
91-
final override val identifier: WorkflowIdentifier get() = id.identifier
92-
final override val renderKey: String get() = id.name
93-
final override val sessionId: Long = idCounter.createId()
94-
95-
final override fun toString(): String = workflowSessionToString()
96-
9787
/**
9888
* Walk the tree of workflows, rendering each one and using
9989
* [RenderContext][com.squareup.workflow1.BaseRenderContext] to give its children a chance to
@@ -117,9 +107,9 @@ internal abstract class AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
117107
* Gets the next [result][ActionProcessingResult] from the state machine. This will be an
118108
* [OutputT] or null.
119109
*
120-
* Walk the tree of state machines, asking each one to wait for its next event. If something happen
121-
* that results in an output, that output is returned. Null means something happened that requires
122-
* a re-render, e.g. my state changed or a child state changed.
110+
* Walk the tree of state machines, asking each one to wait for its next event. If something
111+
* happen that results in an output, that output is returned. Null means something happened that
112+
* requires a re-render, e.g. my state changed or a child state changed.
123113
*
124114
* It is an error to call this method after calling [cancel].
125115
*
@@ -131,8 +121,8 @@ internal abstract class AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
131121
/**
132122
* Cancels this state machine host, and any coroutines started as children of it.
133123
*
134-
* This must be called when the caller will no longer call [onNextAction]. It is an error to call [onNextAction]
135-
* after calling this method.
124+
* This must be called when the caller will no longer call [onNextAction]. It is an error to call
125+
* [onNextAction] after calling this method.
136126
*/
137127
open fun cancel(cause: CancellationException? = null) {
138128
coroutineContext.cancel(cause)

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/StatefulWorkflowNode.kt

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.squareup.workflow1.Workflow
1414
import com.squareup.workflow1.WorkflowAction
1515
import com.squareup.workflow1.WorkflowExperimentalApi
1616
import com.squareup.workflow1.WorkflowExperimentalRuntime
17+
import com.squareup.workflow1.WorkflowIdentifier
1718
import com.squareup.workflow1.WorkflowInterceptor
1819
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
1920
import com.squareup.workflow1.WorkflowTracer
@@ -22,6 +23,7 @@ import com.squareup.workflow1.intercept
2223
import com.squareup.workflow1.internal.RealRenderContext.RememberStore
2324
import com.squareup.workflow1.internal.RealRenderContext.SideEffectRunner
2425
import com.squareup.workflow1.trace
26+
import com.squareup.workflow1.workflowSessionToString
2527
import kotlinx.coroutines.CancellationException
2628
import kotlinx.coroutines.CoroutineName
2729
import kotlinx.coroutines.CoroutineScope
@@ -56,28 +58,32 @@ internal class StatefulWorkflowNode<PropsT, StateT, OutputT, RenderingT>(
5658
snapshot: TreeSnapshot?,
5759
baseContext: CoroutineContext,
5860
// Providing default value so we don't need to specify in test.
59-
runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG,
60-
workflowTracer: WorkflowTracer? = null,
61+
override val runtimeConfig: RuntimeConfig = RuntimeConfigOptions.DEFAULT_CONFIG,
62+
override val workflowTracer: WorkflowTracer? = null,
6163
emitAppliedActionToParent: (ActionApplied<OutputT>) -> ActionProcessingResult = { it },
62-
parent: WorkflowSession? = null,
64+
override val parent: WorkflowSession? = null,
6365
interceptor: WorkflowInterceptor = NoopWorkflowInterceptor,
6466
idCounter: IdCounter? = null
6567
) : AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
6668
id = id,
67-
runtimeConfig = runtimeConfig,
68-
workflowTracer = workflowTracer,
69-
parent = parent,
7069
baseContext = baseContext,
71-
idCounter = idCounter,
7270
interceptor = interceptor,
7371
emitAppliedActionToParent = emitAppliedActionToParent,
7472
),
7573
SideEffectRunner,
76-
RememberStore {
74+
RememberStore,
75+
WorkflowSession {
7776

77+
// WorkflowSession properties
78+
override val identifier: WorkflowIdentifier get() = id.identifier
79+
override val renderKey: String get() = id.name
80+
override val sessionId: Long = idCounter.createId()
7881
private var cachedWorkflowInstance: StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>
7982
private var interceptedWorkflowInstance: StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>
8083

84+
override val session: WorkflowSession
85+
get() = this
86+
8187
private val subtreeManager = SubtreeManager(
8288
snapshotCache = snapshot?.childTreeSnapshots,
8389
contextForChildren = coroutineContext,
@@ -115,6 +121,8 @@ internal class StatefulWorkflowNode<PropsT, StateT, OutputT, RenderingT>(
115121
state = interceptedWorkflowInstance.initialState(initialProps, snapshot?.workflowSnapshot, this)
116122
}
117123

124+
override fun toString(): String = workflowSessionToString()
125+
118126
/**
119127
* Walk the tree of workflows, rendering each one and using
120128
* [RenderContext][com.squareup.workflow1.BaseRenderContext] to give its children a chance to

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/WorkflowRunner.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,15 @@ internal class WorkflowRunner<PropsT, OutputT, RenderingT>(
6969
* between every subsequent call to [processAction].
7070
*/
7171
fun nextRendering(): RenderingAndSnapshot<RenderingT> {
72-
return interceptor.onRenderAndSnapshot(currentProps, { props ->
73-
val rendering = rootNode.render(workflow, props)
74-
val snapshot = rootNode.snapshot()
75-
RenderingAndSnapshot(rendering, snapshot)
76-
}, rootNode)
72+
return interceptor.onRenderAndSnapshot(
73+
renderProps = currentProps,
74+
proceed = { props ->
75+
val rendering = rootNode.render(workflow, props)
76+
val snapshot = rootNode.snapshot()
77+
RenderingAndSnapshot(rendering, snapshot)
78+
},
79+
session = rootNode.session,
80+
)
7781
}
7882

7983
/**

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/compose/ComposeWorkflowChildNode.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ internal class ComposeWorkflowChildNode<PropsT, OutputT, RenderingT>(
5656
override val id: WorkflowNodeId,
5757
initialProps: PropsT,
5858
snapshot: TreeSnapshot?,
59-
baseContext: CoroutineContext,
59+
// We don't need to create our own job because unlike for WorkflowNode, the baseContext already
60+
// has a dedicated job: either from the adapter (for root compose workflow), or from
61+
// rememberCoroutineScope().
62+
override val coroutineContext: CoroutineContext,
6063
override val parent: WorkflowSession?,
6164
override val workflowTracer: WorkflowTracer?,
6265
override val runtimeConfig: RuntimeConfig,
@@ -69,12 +72,6 @@ internal class ComposeWorkflowChildNode<PropsT, OutputT, RenderingT>(
6972
WorkflowComposableRenderer,
7073
CoroutineScope {
7174

72-
// We don't need to create our own job because unlike for WorkflowNode, the baseContext already
73-
// has a dedicated job: either from the adapter (for root compose workflow), or from
74-
// rememberCoroutineScope().
75-
override val coroutineContext: CoroutineContext = baseContext +
76-
CoroutineName(id.toString())
77-
7875
// WorkflowSession properties
7976
override val identifier: WorkflowIdentifier get() = id.identifier
8077
override val renderKey: String get() = id.name
@@ -289,7 +286,7 @@ internal class ComposeWorkflowChildNode<PropsT, OutputT, RenderingT>(
289286
id = childId,
290287
initialProps = initialProps,
291288
snapshot = childSnapshot,
292-
baseContext = childCoroutineScope.coroutineContext,
289+
coroutineContext = childCoroutineScope.coroutineContext + CoroutineName(id.toString()),
293290
parent = this,
294291
workflowTracer = workflowTracer,
295292
runtimeConfig = runtimeConfig,

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/compose/ComposeWorkflowNodeAdapter.kt

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import com.squareup.workflow1.RuntimeConfig
88
import com.squareup.workflow1.RuntimeConfigOptions
99
import com.squareup.workflow1.TreeSnapshot
1010
import com.squareup.workflow1.Workflow
11-
import com.squareup.workflow1.WorkflowExperimentalApi
1211
import com.squareup.workflow1.WorkflowInterceptor
1312
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
1413
import com.squareup.workflow1.WorkflowTracer
@@ -34,10 +33,8 @@ internal fun log(message: String) = message.lines().forEach {
3433
* [ComposeWorkflowChildNode]. [ComposeWorkflow]s nested directly under this one do not have their
3534
* own composition, they share this one.
3635
*/
37-
@OptIn(WorkflowExperimentalApi::class)
3836
internal class ComposeWorkflowNodeAdapter<PropsT, OutputT, RenderingT>(
3937
id: WorkflowNodeId,
40-
workflow: ComposeWorkflow<PropsT, OutputT, RenderingT>,
4138
initialProps: PropsT,
4239
snapshot: TreeSnapshot?,
4340
baseContext: CoroutineContext,
@@ -48,15 +45,9 @@ internal class ComposeWorkflowNodeAdapter<PropsT, OutputT, RenderingT>(
4845
parent: WorkflowSession? = null,
4946
interceptor: WorkflowInterceptor = NoopWorkflowInterceptor,
5047
idCounter: IdCounter? = null
51-
// TODO AbstractWorkflowNode should not implement WorkflowSession, since only StatefulWorkflowNode
52-
// needs that. The composable session is implemented by ComposeWorkflowChildNode.
5348
) : AbstractWorkflowNode<PropsT, OutputT, RenderingT>(
5449
id = id,
55-
runtimeConfig = runtimeConfig,
56-
workflowTracer = workflowTracer,
57-
parent = parent,
5850
baseContext = baseContext,
59-
idCounter = idCounter,
6051
interceptor = interceptor,
6152
emitAppliedActionToParent = emitAppliedActionToParent,
6253
) {
@@ -70,7 +61,7 @@ internal class ComposeWorkflowNodeAdapter<PropsT, OutputT, RenderingT>(
7061
id = id,
7162
initialProps = initialProps,
7263
snapshot = snapshot,
73-
baseContext = coroutineContext,
64+
coroutineContext = coroutineContext,
7465
parent = parent,
7566
workflowTracer = workflowTracer,
7667
runtimeConfig = runtimeConfig,
@@ -109,6 +100,9 @@ internal class ComposeWorkflowNodeAdapter<PropsT, OutputT, RenderingT>(
109100
}
110101
)
111102

103+
override val session: WorkflowSession
104+
get() = childNode
105+
112106
/**
113107
* Function invoked when [onNextAction] receives a recompose request.
114108
* This handles the case where some state read by the composition is changed but emitOutput is

0 commit comments

Comments
 (0)