Skip to content

Commit

Permalink
Remove non-null upper bound for OutputT.
Browse files Browse the repository at this point in the history
Fixes #59.
  • Loading branch information
zach-klippenstein committed Jun 27, 2020
1 parent 4963e61 commit 9216a69
Show file tree
Hide file tree
Showing 40 changed files with 656 additions and 193 deletions.
2 changes: 1 addition & 1 deletion workflow-core/api/workflow-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ public final class com/squareup/workflow/WorkflowActionKt {
public static final fun action (Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lcom/squareup/workflow/WorkflowAction;
public static final fun action (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;)Lcom/squareup/workflow/WorkflowAction;
public static synthetic fun action$default (Ljava/lang/String;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/squareup/workflow/WorkflowAction;
public static final fun applyTo (Lcom/squareup/workflow/WorkflowAction;Ljava/lang/Object;)Lkotlin/Pair;
public static final fun applyTo (Lcom/squareup/workflow/WorkflowAction;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Lkotlin/Pair;
}

public final class com/squareup/workflow/WorkflowIdentifier {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import com.squareup.workflow.WorkflowAction.Updater
*
* See [renderChild].
*/
interface RenderContext<StateT, in OutputT : Any> {
interface RenderContext<StateT, in OutputT> {

/**
* Accepts a single [WorkflowAction], invokes that action by calling [WorkflowAction.apply]
Expand Down Expand Up @@ -94,7 +94,7 @@ interface RenderContext<StateT, in OutputT : Any> {
* @param key An optional string key that is used to distinguish between workflows of the same
* type.
*/
fun <ChildPropsT, ChildOutputT : Any, ChildRenderingT> renderChild(
fun <ChildPropsT, ChildOutputT, ChildRenderingT> renderChild(
child: Workflow<ChildPropsT, ChildOutputT, ChildRenderingT>,
props: ChildPropsT,
key: String = "",
Expand Down Expand Up @@ -144,7 +144,7 @@ interface RenderContext<StateT, in OutputT : Any> {
* Convenience alias of [RenderContext.renderChild] for workflows that don't take props.
*/
/* ktlint-disable parameter-list-wrapping */
fun <StateT, OutputT : Any, ChildOutputT : Any, ChildRenderingT>
fun <StateT, OutputT, ChildOutputT, ChildRenderingT>
RenderContext<StateT, OutputT>.renderChild(
child: Workflow<Unit, ChildOutputT, ChildRenderingT>,
key: String = "",
Expand All @@ -157,7 +157,7 @@ fun <StateT, OutputT : Any, ChildOutputT : Any, ChildRenderingT>
* output.
*/
/* ktlint-disable parameter-list-wrapping */
fun <PropsT, StateT, OutputT : Any, ChildRenderingT>
fun <PropsT, StateT, OutputT, ChildRenderingT>
RenderContext<StateT, OutputT>.renderChild(
child: Workflow<PropsT, Nothing, ChildRenderingT>,
props: PropsT,
Expand All @@ -170,7 +170,7 @@ fun <PropsT, StateT, OutputT : Any, ChildRenderingT>
* output.
*/
/* ktlint-disable parameter-list-wrapping */
fun <StateT, OutputT : Any, ChildRenderingT>
fun <StateT, OutputT, ChildRenderingT>
RenderContext<StateT, OutputT>.renderChild(
child: Workflow<Unit, Nothing, ChildRenderingT>,
key: String = ""
Expand All @@ -185,7 +185,7 @@ fun <StateT, OutputT : Any, ChildRenderingT>
*
* @param key An optional string key that is used to distinguish between identical [Worker]s.
*/
fun <StateT, OutputT : Any> RenderContext<StateT, OutputT>.runningWorker(
fun <StateT, OutputT> RenderContext<StateT, OutputT>.runningWorker(
worker: Worker<Nothing>,
key: String = ""
) {
Expand All @@ -199,7 +199,7 @@ fun <StateT, OutputT : Any> RenderContext<StateT, OutputT>.runningWorker(
* Alternative to [RenderContext.actionSink] that allows externally defined
* event types to be mapped to anonymous [WorkflowAction]s.
*/
fun <EventT, StateT, OutputT : Any> RenderContext<StateT, OutputT>.makeEventSink(
fun <EventT, StateT, OutputT> RenderContext<StateT, OutputT>.makeEventSink(
update: Updater<StateT, OutputT>.(EventT) -> Unit
): Sink<EventT> = actionSink.contraMap { event ->
action({ "eventSink($event)" }) { update(event) }
Expand All @@ -216,7 +216,7 @@ fun <EventT, StateT, OutputT : Any> RenderContext<StateT, OutputT>.makeEventSink
"Use runningWorker",
ReplaceWith("runningWorker(worker, key, handler)", "com.squareup.workflow.runningWorker")
)
fun <StateT, OutputT : Any, T> RenderContext<StateT, OutputT>.onWorkerOutput(
fun <StateT, OutputT, T> RenderContext<StateT, OutputT>.onWorkerOutput(
worker: Worker<T>,
key: String = "",
handler: (T) -> WorkflowAction<StateT, OutputT>
Expand Down
4 changes: 2 additions & 2 deletions workflow-core/src/main/java/com/squareup/workflow/Sink.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fun <T1, T2> Sink<T1>.contraMap(transform: (T2) -> T1): Sink<T2> {
* ```
*/
@ExperimentalWorkflowApi
suspend fun <T, StateT, OutputT : Any> Flow<T>.collectToSink(
suspend fun <T, StateT, OutputT> Flow<T>.collectToSink(
actionSink: Sink<WorkflowAction<StateT, OutputT>>,
handler: (T) -> WorkflowAction<StateT, OutputT>
) {
Expand All @@ -93,7 +93,7 @@ suspend fun <T, StateT, OutputT : Any> Flow<T>.collectToSink(
* This method is intended to be used from [RenderContext.runningSideEffect].
*/
@ExperimentalWorkflowApi
suspend fun <StateT, OutputT : Any> Sink<WorkflowAction<StateT, OutputT>>.sendAndAwaitApplication(
suspend fun <StateT, OutputT> Sink<WorkflowAction<StateT, OutputT>>.sendAndAwaitApplication(
action: WorkflowAction<StateT, OutputT>
) {
suspendCancellableCoroutine<Unit> { continuation ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ import com.squareup.workflow.WorkflowAction.Updater
abstract class StatefulWorkflow<
in PropsT,
StateT,
out OutputT : Any,
out OutputT,
out RenderingT
> : Workflow<PropsT, OutputT, RenderingT> {

Expand Down Expand Up @@ -164,7 +164,7 @@ abstract class StatefulWorkflow<
/**
* Returns a stateful [Workflow] implemented via the given functions.
*/
inline fun <PropsT, StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
inline fun <PropsT, StateT, OutputT, RenderingT> Workflow.Companion.stateful(
crossinline initialState: (PropsT, Snapshot?) -> StateT,
crossinline render: RenderContext<StateT, OutputT>.(props: PropsT, state: StateT) -> RenderingT,
crossinline snapshot: (StateT) -> Snapshot,
Expand Down Expand Up @@ -198,7 +198,7 @@ inline fun <PropsT, StateT, OutputT : Any, RenderingT> Workflow.Companion.statef
/**
* Returns a stateful [Workflow], with no props, implemented via the given functions.
*/
inline fun <StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
inline fun <StateT, OutputT, RenderingT> Workflow.Companion.stateful(
crossinline initialState: (Snapshot?) -> StateT,
crossinline render: RenderContext<StateT, OutputT>.(state: StateT) -> RenderingT,
crossinline snapshot: (StateT) -> Snapshot
Expand All @@ -213,7 +213,7 @@ inline fun <StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
*
* This overload does not support snapshotting, but there are other overloads that do.
*/
inline fun <PropsT, StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
inline fun <PropsT, StateT, OutputT, RenderingT> Workflow.Companion.stateful(
crossinline initialState: (PropsT) -> StateT,
crossinline render: RenderContext<StateT, OutputT>.(props: PropsT, state: StateT) -> RenderingT,
crossinline onPropsChanged: (
Expand All @@ -233,7 +233,7 @@ inline fun <PropsT, StateT, OutputT : Any, RenderingT> Workflow.Companion.statef
*
* This overload does not support snapshots, but there are others that do.
*/
inline fun <StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
inline fun <StateT, OutputT, RenderingT> Workflow.Companion.stateful(
initialState: StateT,
crossinline render: RenderContext<StateT, OutputT>.(state: StateT) -> RenderingT
): StatefulWorkflow<Unit, StateT, OutputT, RenderingT> = stateful(
Expand All @@ -249,7 +249,7 @@ inline fun <StateT, OutputT : Any, RenderingT> Workflow.Companion.stateful(
* @param name A string describing the update for debugging, included in [toString].
* @param update Function that defines the workflow update.
*/
fun <PropsT, StateT, OutputT : Any, RenderingT>
fun <PropsT, StateT, OutputT, RenderingT>
StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>.action(
name: String = "",
update: Updater<StateT, OutputT>.() -> Unit
Expand All @@ -264,7 +264,7 @@ fun <PropsT, StateT, OutputT : Any, RenderingT>
* in [toString].
* @param update Function that defines the workflow update.
*/
fun <PropsT, StateT, OutputT : Any, RenderingT>
fun <PropsT, StateT, OutputT, RenderingT>
StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>.action(
name: () -> String,
update: Updater<StateT, OutputT>.() -> Unit
Expand All @@ -280,7 +280,7 @@ fun <PropsT, StateT, OutputT : Any, RenderingT>
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <PropsT, StateT, OutputT : Any, RenderingT>
fun <PropsT, StateT, OutputT, RenderingT>
StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>.workflowAction(
name: String = "",
block: Mutator<StateT>.() -> OutputT?
Expand All @@ -294,7 +294,7 @@ fun <PropsT, StateT, OutputT : Any, RenderingT>
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <PropsT, StateT, OutputT : Any, RenderingT>
fun <PropsT, StateT, OutputT, RenderingT>
StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>.workflowAction(
name: () -> String,
block: Mutator<StateT>.() -> OutputT?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import com.squareup.workflow.WorkflowAction.Updater
*
* @see StatefulWorkflow
*/
abstract class StatelessWorkflow<in PropsT, out OutputT : Any, out RenderingT> :
abstract class StatelessWorkflow<in PropsT, out OutputT, out RenderingT> :
Workflow<PropsT, OutputT, RenderingT> {

@Suppress("UNCHECKED_CAST")
Expand Down Expand Up @@ -82,7 +82,7 @@ abstract class StatelessWorkflow<in PropsT, out OutputT : Any, out RenderingT> :
* [props][PropsT] received from its parent, and it may render child workflows that do have
* their own internal state.
*/
inline fun <PropsT, OutputT : Any, RenderingT> Workflow.Companion.stateless(
inline fun <PropsT, OutputT, RenderingT> Workflow.Companion.stateless(
crossinline render: RenderContext<Nothing, OutputT>.(props: PropsT) -> RenderingT
): Workflow<PropsT, OutputT, RenderingT> =
object : StatelessWorkflow<PropsT, OutputT, RenderingT>() {
Expand All @@ -108,7 +108,7 @@ fun <RenderingT> Workflow.Companion.rendering(
* @param name A string describing the update for debugging, included in [toString].
* @param update Function that defines the workflow update.
*/
fun <PropsT, OutputT : Any, RenderingT>
fun <PropsT, OutputT, RenderingT>
StatelessWorkflow<PropsT, OutputT, RenderingT>.action(
name: String = "",
update: Updater<Nothing, OutputT>.() -> Unit
Expand All @@ -123,7 +123,7 @@ fun <PropsT, OutputT : Any, RenderingT>
* [toString].
* @param update Function that defines the workflow update.
*/
fun <PropsT, OutputT : Any, RenderingT>
fun <PropsT, OutputT, RenderingT>
StatelessWorkflow<PropsT, OutputT, RenderingT>.action(
name: () -> String,
update: Updater<Nothing, OutputT>.() -> Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ interface Worker<out OutputT> {
* The returned [Worker] will equate to any other workers created with any of the [Worker]
* builder functions that have the same output type.
*/
inline fun <reified OutputT : Any> fromNullable(
inline fun <reified OutputT> fromNullable(
// This could be crossinline, but there's a coroutines bug that will cause the coroutine
// to immediately resume on suspension inside block when it is crossinline.
// See https://youtrack.jetbrains.com/issue/KT-31197.
Expand Down
4 changes: 2 additions & 2 deletions workflow-core/src/main/java/com/squareup/workflow/Workflow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ package com.squareup.workflow
* @see StatefulWorkflow
* @see StatelessWorkflow
*/
interface Workflow<in PropsT, out OutputT : Any, out RenderingT> {
interface Workflow<in PropsT, out OutputT, out RenderingT> {

/**
* Provides a [StatefulWorkflow] view of this workflow. Necessary because [StatefulWorkflow] is
Expand All @@ -125,7 +125,7 @@ interface Workflow<in PropsT, out OutputT : Any, out RenderingT> {
*/
/* ktlint-disable parameter-list-wrapping */
@OptIn(ExperimentalWorkflowApi::class)
fun <PropsT, OutputT : Any, FromRenderingT, ToRenderingT>
fun <PropsT, OutputT, FromRenderingT, ToRenderingT>
Workflow<PropsT, OutputT, FromRenderingT>.mapRendering(
transform: (FromRenderingT) -> ToRenderingT
): Workflow<PropsT, OutputT, ToRenderingT> =
Expand Down
45 changes: 30 additions & 15 deletions workflow-core/src/main/java/com/squareup/workflow/WorkflowAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import com.squareup.workflow.WorkflowAction.Updater
/**
* An atomic operation that updates the state of a [Workflow], and also optionally emits an output.
*/
interface WorkflowAction<StateT, out OutputT : Any> {
interface WorkflowAction<StateT, out OutputT> {
@Deprecated("Use Updater")
class Mutator<S>(var state: S)

Expand All @@ -31,16 +31,22 @@ interface WorkflowAction<StateT, out OutputT : Any> {
*
* @param nextState the state that the workflow should move to. Default is the current state.
*/
class Updater<S, in O : Any>(var nextState: S) {
internal var output: @UnsafeVariance O? = null
class Updater<S, in O>(var nextState: S) {
private var output: @UnsafeVariance O? = null
private var isOutputSet = false

/**
* Sets the value the workflow will emit as output when this action is applied.
* If this method is not called, there will be no output.
*/
fun setOutput(output: O) {
this.output = output
isOutputSet = true
}

@Suppress("UNCHECKED_CAST")
internal fun <T : Any> mapOutput(mapper: (@UnsafeVariance O) -> T): T? =
if (isOutputSet) mapper(output as O) else null
}

/**
Expand Down Expand Up @@ -69,7 +75,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
* Use this to, for example, ignore the output of a child workflow or worker.
*/
@Suppress("UNCHECKED_CAST")
fun <StateT, OutputT : Any> noAction(): WorkflowAction<StateT, OutputT> =
fun <StateT, OutputT> noAction(): WorkflowAction<StateT, OutputT> =
NO_ACTION as WorkflowAction<StateT, OutputT>

/**
Expand All @@ -83,7 +89,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <StateT, OutputT : Any> enterState(
fun <StateT, OutputT> enterState(
newState: StateT,
emittingOutput: OutputT? = null
): WorkflowAction<StateT, OutputT> =
Expand All @@ -103,7 +109,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <StateT, OutputT : Any> enterState(
fun <StateT, OutputT> enterState(
name: String,
newState: StateT,
emittingOutput: OutputT? = null
Expand All @@ -123,7 +129,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <StateT, OutputT : Any> modifyState(
fun <StateT, OutputT> modifyState(
name: () -> String,
emittingOutput: OutputT? = null,
modify: (StateT) -> StateT
Expand All @@ -143,7 +149,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <StateT, OutputT : Any> emitOutput(output: OutputT): WorkflowAction<StateT, OutputT> =
fun <StateT, OutputT> emitOutput(output: OutputT): WorkflowAction<StateT, OutputT> =
action({ "emitOutput($output)" }) { setOutput(output) }

/**
Expand All @@ -156,7 +162,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
imports = arrayOf("com.squareup.workflow.action")
)
)
fun <StateT, OutputT : Any> emitOutput(
fun <StateT, OutputT> emitOutput(
name: String,
output: OutputT
): WorkflowAction<StateT, OutputT> =
Expand All @@ -179,7 +185,7 @@ interface WorkflowAction<StateT, out OutputT : Any> {
* @see StatelessWorkflow.action
* @see StatefulWorkflow.action
*/
inline fun <StateT, OutputT : Any> action(
inline fun <StateT, OutputT> action(
name: String = "",
crossinline apply: Updater<StateT, OutputT>.() -> Unit
) = action({ name }, apply)
Expand All @@ -197,18 +203,27 @@ inline fun <StateT, OutputT : Any> action(
* @see StatelessWorkflow.action
* @see StatefulWorkflow.action
*/
inline fun <StateT, OutputT : Any> action(
inline fun <StateT, OutputT> action(
crossinline name: () -> String,
crossinline apply: Updater<StateT, OutputT>.() -> Unit
): WorkflowAction<StateT, OutputT> = object : WorkflowAction<StateT, OutputT> {
override fun Updater<StateT, OutputT>.apply() = apply.invoke(this)
override fun toString(): String = "WorkflowAction(${name()})@${hashCode()}"
}

fun <StateT, OutputT : Any> WorkflowAction<StateT, OutputT>.applyTo(
state: StateT
): Pair<StateT, OutputT?> {
/**
* Applies this [WorkflowAction] to [state]. If the action sets an output, the output will be
* transformed by [mapOutput], and then both the new state and the transformed output will be
* returned.
*
* If the action sets the output multiple times, only the last one will be used.
*/
fun <StateT, OutputT, T : Any> WorkflowAction<StateT, OutputT>.applyTo(
state: StateT,
mapOutput: (OutputT) -> T
): Pair<StateT, T?> {
val updater = Updater<StateT, OutputT>(state)
updater.apply()
return Pair(updater.nextState, updater.output)
val output = updater.mapOutput(mapOutput)
return Pair(updater.nextState, output)
}
Loading

0 comments on commit 9216a69

Please sign in to comment.