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

commonMain.space.kscience.dataforge.actions.MapAction.kt Maven / Gradle / Ivy

There is a newer version: 0.7.0
Show newest version
package space.kscience.dataforge.actions

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name
import kotlin.reflect.KType
import kotlin.reflect.typeOf

/**
 * Action environment includes data name, data meta and action configuration meta
 */
public data class ActionEnv(
    val name: Name,
    val meta: Meta,
    val actionMeta: Meta,
)

/**
 * Action environment
 */
@DFBuilder
public class MapActionBuilder(public var name: Name, public var meta: MutableMeta, public val actionMeta: Meta) {
    public lateinit var result: suspend ActionEnv.(T) -> R

    /**
     * Calculate the result of goal
     */
    public fun result(f: suspend ActionEnv.(T) -> R) {
        result = f;
    }
}

@PublishedApi
internal class MapAction(
    private val outputType: KType,
    private val block: MapActionBuilder.() -> Unit,
) : Action {

    override suspend fun execute(
        dataSet: DataSet,
        meta: Meta,
        scope: CoroutineScope?,
    ): DataSet {
        suspend fun mapOne(data: NamedData): NamedData {
            // Creating a new environment for action using **old** name, old meta and task meta
            val env = ActionEnv(data.name, data.meta, meta)

            //applying transformation from builder
            val builder = MapActionBuilder(
                data.name,
                data.meta.toMutableMeta(), // using data meta
                meta
            ).apply(block)

            //getting new name
            val newName = builder.name

            //getting new meta
            val newMeta = builder.meta.seal()

            @OptIn(DFInternal::class)
            val newData = Data(outputType, newMeta, dependencies = listOf(data)) {
                builder.result(env, data.await())
            }
            //setting the data node
            return newData.named(newName)
        }

        val flow = dataSet.flow().map(::mapOne)

        return ActiveDataTree(outputType) {
            populate(flow)
            scope?.launch {
                dataSet.updates.collect { name ->
                    //clear old nodes
                    remove(name)
                    //collect new items
                    populate(dataSet.flowChildren(name).map(::mapOne))
                }
            }
        }
    }
}


/**
 * A one-to-one mapping action
 */
@DFExperimental
@Suppress("FunctionName")
public inline fun  Action.Companion.map(
    noinline builder: MapActionBuilder.() -> Unit,
): Action = MapAction(typeOf(), builder)






© 2015 - 2025 Weber Informatics LLC | Privacy Policy