
commonMain.space.kscience.dataforge.data.DataSet.kt Maven / Gradle / Ivy
package space.kscience.dataforge.data
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import space.kscience.dataforge.data.Data.Companion.TYPE_OF_NOTHING
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.*
import kotlin.reflect.KType
public interface DataSet {
/**
* The minimal common ancestor to all data in the node
*/
public val dataType: KType
/**
* Traverse this provider or its child. The order is not guaranteed.
* [root] points to a root name for traversal. If it is empty, traverse this source, if it points to a [Data],
* return flow, that contains single [Data], if it points to a node with children, return children.
*/
public fun flow(): Flow>
/**
* Get data with given name.
*/
public suspend fun getData(name: Name): Data?
/**
* Get a snapshot of names of top level children of given node. Empty if node does not exist or is a leaf.
*/
public suspend fun listTop(prefix: Name = Name.EMPTY): List =
flow().map { it.name }.filter { it.startsWith(prefix) && (it.length == prefix.length + 1) }.toList()
// By default traverses the whole tree. Could be optimized in descendants
public companion object {
public val META_KEY: Name = "@meta".asName()
/**
* An empty [DataSet] that suits all types
*/
public val EMPTY: DataSet = object : DataSet {
override val dataType: KType = TYPE_OF_NOTHING
private val nothing: Nothing get() = error("this is nothing")
override fun flow(): Flow> = emptyFlow()
override suspend fun getData(name: Name): Data? = null
}
}
}
public interface ActiveDataSet : DataSet {
/**
* A flow of updated item names. Updates are propagated in a form of [Flow] of names of updated nodes.
* Those can include new data items and replacement of existing ones. The replaced items could update existing data content
* and replace it completely, so they should be pulled again.
*
*/
public val updates: Flow
}
public val DataSet.updates: Flow get() = if (this is ActiveDataSet) updates else emptyFlow()
/**
* Flow all data nodes with names starting with [branchName]
*/
public fun DataSet.flowChildren(branchName: Name): Flow> = [email protected]().filter {
it.name.startsWith(branchName)
}
/**
* Start computation for all goals in data node and return a job for the whole node
*/
public fun DataSet.startAll(coroutineScope: CoroutineScope): Job = coroutineScope.launch {
flow().map {
it.launch(this@launch)
}.toList().joinAll()
}
public suspend fun DataSet.join(): Unit = coroutineScope { startAll(this).join() }
public suspend fun DataSet<*>.toMeta(): Meta = Meta {
flow().collect {
if (it.name.endsWith(DataSet.META_KEY)) {
set(it.name, it.meta)
} else {
it.name put {
"type" put it.type.toString()
"meta" put it.meta
}
}
}
}
public val DataSet.updatesWithData: Flow> get() = updates.mapNotNull { getData(it)?.named(it) }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy