diff --git a/workflow-core/api/workflow-core.api b/workflow-core/api/workflow-core.api index 80307d96a..a419493fc 100644 --- a/workflow-core/api/workflow-core.api +++ b/workflow-core/api/workflow-core.api @@ -254,6 +254,7 @@ public final class com/squareup/workflow1/WorkflowIdentifier { public static final field Companion Lcom/squareup/workflow1/WorkflowIdentifier$Companion; public fun equals (Ljava/lang/Object;)Z public final fun getRealIdentifierType ()Lcom/squareup/workflow1/WorkflowIdentifierType; + public final fun getRealType ()Lcom/squareup/workflow1/WorkflowIdentifierType; public fun hashCode ()I public final fun toByteStringOrNull ()Lokio/ByteString; public fun toString ()Ljava/lang/String; diff --git a/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowIdentifier.kt b/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowIdentifier.kt index 06ebb9392..56e744b84 100644 --- a/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowIdentifier.kt +++ b/workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowIdentifier.kt @@ -9,6 +9,7 @@ import okio.Buffer import okio.ByteString import okio.EOFException import kotlin.LazyThreadSafetyMode.PUBLICATION +import kotlin.concurrent.Volatile import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName import kotlin.reflect.KClass @@ -58,6 +59,17 @@ public class WorkflowIdentifier internal constructor( private val proxiedIdentifiers = generateSequence(this) { it.proxiedIdentifier } + @Volatile + private var cachedToString: String? = null + + /** + * Either a [KClass] or [KType] representing the "real" type that this identifier + * identifies – i.e. which is not an [ImpostorWorkflow]. + */ + public val realType: WorkflowIdentifierType by lazy(PUBLICATION) { + proxiedIdentifiers.last().type + } + /** * If this identifier is snapshottable, returns the serialized form of the identifier. * If it is not snapshottable, returns null. @@ -83,11 +95,8 @@ public class WorkflowIdentifier internal constructor( } } - /** - * Returns either a [KClass] or [KType] representing the "real" type that this identifier - * identifies – i.e. which is not an [ImpostorWorkflow]. - */ - public fun getRealIdentifierType(): WorkflowIdentifierType = proxiedIdentifiers.last().type + @Deprecated("This is now a lazily computed val", ReplaceWith("realType")) + public fun getRealIdentifierType(): WorkflowIdentifierType = realType /** * If this identifier identifies an [ImpostorWorkflow], returns the result of that workflow's @@ -95,11 +104,17 @@ public class WorkflowIdentifier internal constructor( * identifier including the name of its workflow type and any [ImpostorWorkflow.realIdentifier]s. * */ - override fun toString(): String = - description?.invoke() - ?: proxiedIdentifiers - .joinToString { it.typeName } - .let { "WorkflowIdentifier($it)" } + override fun toString(): String { + return cachedToString ?: ( + description?.invoke() + ?: proxiedIdentifiers + .joinToString { it.typeName } + .let { "WorkflowIdentifier($it)" } + ) + .also { + cachedToString = it + } + } override fun equals(other: Any?): Boolean = when { this === other -> true diff --git a/workflow-core/src/commonTest/kotlin/com/squareup/workflow1/WorkflowIdentifierTest.kt b/workflow-core/src/commonTest/kotlin/com/squareup/workflow1/WorkflowIdentifierTest.kt index e83db8820..4e822ee63 100644 --- a/workflow-core/src/commonTest/kotlin/com/squareup/workflow1/WorkflowIdentifierTest.kt +++ b/workflow-core/src/commonTest/kotlin/com/squareup/workflow1/WorkflowIdentifierTest.kt @@ -153,22 +153,22 @@ internal class WorkflowIdentifierTest { @Test fun getRealIdentifierType_returns_self_for_non_impostor_workflow() { val id = TestWorkflow1.identifier - assertEquals(Snapshottable(TestWorkflow1::class), id.getRealIdentifierType()) + assertEquals(Snapshottable(TestWorkflow1::class), id.realType) } @Test fun getRealIdentifierType_returns_real_identifier_for_impostor_workflow() { val id = TestImpostor1(TestWorkflow1).identifier - assertEquals(Snapshottable(TestWorkflow1::class), id.getRealIdentifierType()) + assertEquals(Snapshottable(TestWorkflow1::class), id.realType) } @Test fun getRealIdentifierType_returns_leaf_real_identifier_for_impostor_workflow_chain() { val id = TestImpostor2(TestImpostor1(TestWorkflow1)).identifier - assertEquals(Snapshottable(TestWorkflow1::class), id.getRealIdentifierType()) + assertEquals(Snapshottable(TestWorkflow1::class), id.realType) } @Test fun getRealIdentifierType_returns_KType_of_unsnapshottable_identifier() { val id = TestUnsnapshottableImpostor(typeOf>()).identifier - assertEquals(Unsnapshottable(typeOf>()), id.getRealIdentifierType()) + assertEquals(Unsnapshottable(typeOf>()), id.realType) } public object TestWorkflow1 : Workflow { diff --git a/workflow-runtime/api/workflow-runtime.api b/workflow-runtime/api/workflow-runtime.api index f177256f2..42f8d1f00 100644 --- a/workflow-runtime/api/workflow-runtime.api +++ b/workflow-runtime/api/workflow-runtime.api @@ -104,5 +104,10 @@ public abstract interface class com/squareup/workflow1/WorkflowInterceptor$Workf public abstract fun getRenderKey ()Ljava/lang/String; public abstract fun getRuntimeConfig ()Ljava/util/Set; public abstract fun getSessionId ()J + public abstract fun isRootWorkflow ()Z +} + +public final class com/squareup/workflow1/WorkflowInterceptor$WorkflowSession$DefaultImpls { + public static fun isRootWorkflow (Lcom/squareup/workflow1/WorkflowInterceptor$WorkflowSession;)Z } diff --git a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt index 742ac38a2..2363b7ad9 100644 --- a/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt +++ b/workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/WorkflowInterceptor.kt @@ -152,6 +152,12 @@ public interface WorkflowInterceptor { /** The parent [WorkflowSession] of this workflow, or null if this is the root workflow. */ public val parent: WorkflowSession? + /** + * true if this is the root workflow, in which case [parent] is null. + */ + public val isRootWorkflow: Boolean + get() = parent == null + /** The [RuntimeConfig] of the runtime this session is executing in. */ public val runtimeConfig: RuntimeConfig } diff --git a/workflow-testing/src/main/java/com/squareup/workflow1/testing/RealRenderTester.kt b/workflow-testing/src/main/java/com/squareup/workflow1/testing/RealRenderTester.kt index efe4b1233..067d1dca2 100644 --- a/workflow-testing/src/main/java/com/squareup/workflow1/testing/RealRenderTester.kt +++ b/workflow-testing/src/main/java/com/squareup/workflow1/testing/RealRenderTester.kt @@ -360,8 +360,8 @@ internal fun createRenderChildInvocation( internal fun WorkflowIdentifier.realTypeMatchesExpectation( expected: WorkflowIdentifier ): Boolean { - val expectedType = expected.getRealIdentifierType() - val actualType = getRealIdentifierType() + val expectedType = expected.realType + val actualType = realType return actualType.matchesExpectation(expectedType) } diff --git a/workflow-tracing/src/main/java/com/squareup/workflow1/diagnostic/tracing/TracingWorkflowInterceptor.kt b/workflow-tracing/src/main/java/com/squareup/workflow1/diagnostic/tracing/TracingWorkflowInterceptor.kt index d17a73a58..a81b3e5ad 100644 --- a/workflow-tracing/src/main/java/com/squareup/workflow1/diagnostic/tracing/TracingWorkflowInterceptor.kt +++ b/workflow-tracing/src/main/java/com/squareup/workflow1/diagnostic/tracing/TracingWorkflowInterceptor.kt @@ -494,7 +494,7 @@ public class TracingWorkflowInterceptor internal constructor( } private fun WorkflowIdentifier.toLoggingName(): String { - val type = getRealIdentifierType() + val type = realType return when { type is Snapshottable && type.kClass != null -> type.kClass!!.toLoggingName() type is Unsnapshottable -> type.kType.toLoggingName()