All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.squareup.workflow1.internal.RealRenderContext.kt Maven / Gradle / Ivy

package com.squareup.workflow1.internal

import com.squareup.workflow1.BaseRenderContext
import com.squareup.workflow1.Sink
import com.squareup.workflow1.Workflow
import com.squareup.workflow1.WorkflowAction
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.SendChannel

internal class RealRenderContext(
  private val renderer: Renderer,
  private val sideEffectRunner: SideEffectRunner,
  private val eventActionsChannel: SendChannel>
) : BaseRenderContext, Sink> {

  interface Renderer {
    fun  render(
      child: Workflow,
      props: ChildPropsT,
      key: String,
      handler: (ChildOutputT) -> WorkflowAction
    ): ChildRenderingT
  }

  interface SideEffectRunner {
    fun runningSideEffect(
      key: String,
      sideEffect: suspend CoroutineScope.() -> Unit
    )
  }

  /**
   * False during the current render call, set to true once this node is finished rendering.
   *
   * Used to:
   *  - prevent modifications to this object after [freeze] is called.
   *  - prevent sending to sinks before render returns.
   */
  private var frozen = false

  override val actionSink: Sink> get() = this

  override fun send(value: WorkflowAction) {
    if (!frozen) {
      throw UnsupportedOperationException(
        "Expected sink to not be sent to until after the render pass. Received action: $value"
      )
    }
    eventActionsChannel.trySend(value)
  }

  override fun  renderChild(
    child: Workflow,
    props: ChildPropsT,
    key: String,
    handler: (ChildOutputT) -> WorkflowAction
  ): ChildRenderingT {
    checkNotFrozen()
    return renderer.render(child, props, key, handler)
  }

  override fun runningSideEffect(
    key: String,
    sideEffect: suspend CoroutineScope.() -> Unit
  ) {
    checkNotFrozen()
    sideEffectRunner.runningSideEffect(key, sideEffect)
  }

  /**
   * Freezes this context so that any further calls to this context will throw.
   */
  fun freeze() {
    checkNotFrozen()
    frozen = true
  }

  /**
   * Unfreezes when the node is about to render() again.
   */
  fun unfreeze() {
    frozen = false
  }

  private fun checkNotFrozen() = check(!frozen) {
    "RenderContext cannot be used after render method returns."
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy