Created
October 30, 2020 14:04
-
-
Save happy-bracket/8626f5a387d51c289097ea9fd3758934 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Traced<E, S : Trace.Stage> { | |
val trace: Trace<E, S> | |
} | |
data class EffectTracer<E : Traced<E, Trace.Stage.Out>, M : Traced<E, Trace.Stage.In>> internal constructor( | |
private val state: State, | |
private val factory: (Trace<E, Trace.Stage.Out>) -> E | |
) { | |
fun launch(): Pair<EffectTracer<E, M>, Set<E>> { | |
val trace = Trace<E, Trace.Stage.Out>(if (state is State.Running) Restart else Launch) | |
val effect = factory(trace) | |
return this to setOf(effect) | |
} | |
fun cancel(): Pair<EffectTracer<E, M>, Set<E>> { | |
if (state is State.Idle) return this to emptySet() | |
val newTracer = copy(state = State.Idle) | |
val trace = Trace<E, Trace.Stage.Out>(Cancel) | |
return newTracer to setOf(factory(trace)) | |
} | |
fun checkResponse(tracedMutation: M): EffectTracer<E, M> { | |
return when (tracedMutation.trace.stage) { | |
is Finished -> copy(state = State.Idle) | |
is HoldOn -> copy(state = State.Running) | |
} | |
} | |
fun isIdle(): Boolean = state is State.Idle | |
sealed class State { | |
object Running : State() | |
object Idle : State() | |
} | |
companion object { | |
operator fun <E : Traced<E, Trace.Stage.Out>, M : Traced<E, Trace.Stage.In>> invoke(factory: (Trace<E, Trace.Stage.Out>) -> E): EffectTracer<E, M> { | |
return EffectTracer(State.Idle, factory) | |
} | |
} | |
} | |
data class Trace<Tag, S : Trace.Stage> internal constructor(val stage: S) { | |
sealed class Stage { | |
sealed class Out : Stage() { | |
object Launch : Out() | |
object Restart : Out() | |
object Cancel : Out() | |
} | |
sealed class In : Stage() { | |
object Finished : In() | |
object HoldOn : In() | |
} | |
} | |
} | |
fun <E> Trace<E, Trace.Stage.Out>.nextStage(isFinished: Boolean): Trace<E, Trace.Stage.In> = Trace(if (isFinished) Finished else HoldOn) | |
class TraceSubHandler<E : Traced<E, Trace.Stage.Out>, M : Traced<E, Trace.Stage.In>>(private val executingHandler: Handler<E, M>) { | |
private val semaphore: Channel<Red> = Channel() | |
fun handle(effect: E): Flow<M> { | |
semaphore.consumeAsFlow() | |
semaphore.offer(Red) | |
return if (effect.trace.stage is Cancel) { | |
emptyFlow() | |
} else { | |
val originalFlow = executingHandler.handle(effect) | |
return merge(semaphore.receiveAsFlow(), originalFlow.map { Green(it) }) | |
.takeWhile { it !is Red } | |
.transform { if (it is Green) emit(it.value) } | |
} | |
} | |
private sealed class Semaphore<out T> { | |
class Green<T>(val value: T) : Semaphore<T>() | |
object Red : Semaphore<Nothing>() | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment