Re-implement MergedTimeline
This commit is contained in:
parent
203a8c1570
commit
f708bb93e2
@ -22,11 +22,11 @@ public fun <E : TimelineEvent> Flow<E>.withTimeThreshold(
|
|||||||
* @param lookaheadInterval an interval for generated events ahead of the last observed event.
|
* @param lookaheadInterval an interval for generated events ahead of the last observed event.
|
||||||
*/
|
*/
|
||||||
public class GeneratingTimeline<E : TimelineEvent>(
|
public class GeneratingTimeline<E : TimelineEvent>(
|
||||||
private val origin: E,
|
origin: E,
|
||||||
private val lookaheadInterval: Duration,
|
private val lookaheadInterval: Duration,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
private val generator: suspend FlowCollector<E>.(E) -> Unit
|
private val generator: suspend FlowCollector<E>.(E) -> Unit
|
||||||
) : AbstractTimeline<E>(origin.time, coroutineContext) {
|
) : ProducerTimeline<E>(origin.time, coroutineContext) {
|
||||||
|
|
||||||
private val startEventFlow = MutableStateFlow(origin)
|
private val startEventFlow = MutableStateFlow(origin)
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package space.kscience.simulation
|
package space.kscience.simulation
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.flow
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
@ -9,18 +13,70 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||||||
public class MergedTimeline<E : TimelineEvent>(
|
public class MergedTimeline<E : TimelineEvent>(
|
||||||
private val timelines: List<Timeline<E>>,
|
private val timelines: List<Timeline<E>>,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
) : AbstractTimeline<E>(timelines.minOf { it.time.value }, coroutineContext) {
|
) : Timeline<E> {
|
||||||
|
|
||||||
override fun events(): Flow<E> = flow {
|
protected val timelineScope: CoroutineScope = CoroutineScope(
|
||||||
val buffer = TODO()
|
coroutineContext +
|
||||||
//
|
SupervisorJob(coroutineContext[Job]) +
|
||||||
// timelines.forEach { timeline ->
|
CoroutineExceptionHandler{ _, throwable -> throwable.printStackTrace() } +
|
||||||
// timeline.observe {
|
CoroutineName("MergedTimeline")
|
||||||
// collect{
|
)
|
||||||
// buffer.add(it)
|
|
||||||
// }
|
override val time: StateFlow<Instant> = combine(timelines.map { it.time }){ array->
|
||||||
// }
|
array.max()
|
||||||
// }
|
}.stateIn(timelineScope, SharingStarted.Lazily, timelines.maxOf { it.time.value })
|
||||||
|
|
||||||
|
override suspend fun advance(toTime: Instant) {
|
||||||
|
observers.forEach {
|
||||||
|
it.collect(toTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val observers: MutableSet<TimelineObserver> = mutableSetOf()
|
||||||
|
|
||||||
|
override suspend fun observe(collector: suspend Flow<E>.() -> Unit): TimelineObserver {
|
||||||
|
val context = currentCoroutineContext()
|
||||||
|
val buffer = mutableListOf<E>()
|
||||||
|
|
||||||
|
val timelineObservers = timelines.map {
|
||||||
|
it.observeEach { event ->
|
||||||
|
buffer.add(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val observer = object : TimelineObserver {
|
||||||
|
|
||||||
|
private val channel = Channel<E>()
|
||||||
|
|
||||||
|
override val time = MutableStateFlow(this@MergedTimeline.time.value)
|
||||||
|
|
||||||
|
private val collectJob = timelineScope.launch(context) {
|
||||||
|
channel.consumeAsFlow().onEach {
|
||||||
|
time.emit(it.time)
|
||||||
|
}.collector()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
override suspend fun collect(upTo: Instant) = mutex.withLock{
|
||||||
|
timelineObservers.forEach {
|
||||||
|
it.collect(upTo)
|
||||||
|
}
|
||||||
|
buffer.sortedBy { it.time }.forEach {
|
||||||
|
channel.send(it)
|
||||||
|
buffer.remove(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
collectJob.cancel()
|
||||||
|
observers.remove(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
observers.add(observer)
|
||||||
|
return observer
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -4,10 +4,12 @@ import kotlinx.coroutines.*
|
|||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.datetime.Instant
|
import kotlinx.datetime.Instant
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
public abstract class AbstractTimeline<E : TimelineEvent>(
|
public abstract class ProducerTimeline<E : TimelineEvent>(
|
||||||
protected var startTime: Instant,
|
protected var startTime: Instant,
|
||||||
coroutineContext: CoroutineContext
|
coroutineContext: CoroutineContext
|
||||||
) : Timeline<E>, AutoCloseable {
|
) : Timeline<E>, AutoCloseable {
|
||||||
@ -53,8 +55,9 @@ public abstract class AbstractTimeline<E : TimelineEvent>(
|
|||||||
}.collector()
|
}.collector()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
override suspend fun collect(upTo: Instant) = coroutineScope {
|
override suspend fun collect(upTo: Instant) = mutex.withLock {
|
||||||
require(upTo >= time.value) { "Requested time $upTo is lower than observed ${time.value}" }
|
require(upTo >= time.value) { "Requested time $upTo is lower than observed ${time.value}" }
|
||||||
events().takeWhile {
|
events().takeWhile {
|
||||||
it.time <= upTo
|
it.time <= upTo
|
@ -13,7 +13,7 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||||||
public class SharedTimeline<E : TimelineEvent>(
|
public class SharedTimeline<E : TimelineEvent>(
|
||||||
startTime: Instant,
|
startTime: Instant,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
coroutineContext: CoroutineContext = EmptyCoroutineContext
|
||||||
) : AbstractTimeline<E>(startTime, coroutineContext) {
|
) : ProducerTimeline<E>(startTime, coroutineContext) {
|
||||||
|
|
||||||
private val events = MutableSharedFlow<E>(replay = Channel.UNLIMITED)
|
private val events = MutableSharedFlow<E>(replay = Channel.UNLIMITED)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user