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

commonMain.space.kscience.dataforge.data.DataSet.kt Maven / Gradle / Ivy

There is a newer version: 0.7.0
Show newest version
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