From f0820a3bedbb2dd08d8bec12b00da3b4443318fd Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 1 May 2022 20:23:37 +0300 Subject: [PATCH] Reify types for action builders --- CHANGELOG.md | 1 + .../kscience/dataforge/actions/MapAction.kt | 9 +++-- .../dataforge/actions/ReduceAction.kt | 34 ++++++++++++------- .../kscience/dataforge/actions/SplitAction.kt | 19 +++++++---- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26208ef7..d3c1b1e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Add `specOrNull` delegate to meta and Scheme - Suspended read methods to the `Binary` - Synchronously accessed `meta` to all `DataSet`s +- More fine-grained types in Action builders. ### Changed - `Factory` is now `fun interface` and uses `build` instead of `invoke`. `invoke moved to an extension. diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt index 08fa97b4..8aae6be8 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt @@ -31,15 +31,20 @@ public class MapActionBuilder( public var name: Name, public var meta: MutableMeta, public val actionMeta: Meta, - public var outputType: KType + @PublishedApi internal var outputType: KType, ) { public lateinit var result: suspend ActionEnv.(T) -> R + internal fun result(outputType: KType, f: suspend ActionEnv.(T) -> R1) { + this.outputType = outputType + result = f; + } + /** * Calculate the result of goal */ - public inline fun result(noinline f: suspend ActionEnv.(T) -> R1) { + public inline fun result(noinline f: suspend ActionEnv.(T) -> R1) { outputType = typeOf() result = f; } diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt index 5bb22bfc..64605ad1 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt @@ -14,13 +14,23 @@ import kotlin.reflect.KType import kotlin.reflect.typeOf -public class JoinGroup(public var name: String, internal val set: DataSet) { +public class JoinGroup( + public var name: String, + internal val set: DataSet, + @PublishedApi internal var outputType: KType, +) { public var meta: MutableMeta = MutableMeta() public lateinit var result: suspend ActionEnv.(Map) -> R - public fun result(f: suspend ActionEnv.(Map) -> R) { + internal fun result(outputType: KType, f: suspend ActionEnv.(Map) -> R1) { + this.outputType = outputType + this.result = f; + } + + public inline fun result(noinline f: suspend ActionEnv.(Map) -> R1) { + outputType = typeOf() this.result = f; } @@ -28,9 +38,9 @@ public class JoinGroup(public var name: String, internal val s @DFBuilder public class ReduceGroupBuilder( - private val inputType: KType, private val scope: CoroutineScope, public val actionMeta: Meta, + private val outputType: KType ) { private val groupRules: MutableList) -> List>> = ArrayList(); @@ -40,7 +50,7 @@ public class ReduceGroupBuilder( public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup.() -> Unit) { groupRules += { node -> GroupRule.byMetaValue(scope, tag, defaultTag).gather(node).map { - JoinGroup(it.key, it.value).apply(action) + JoinGroup(it.key, it.value, outputType).apply(action) } } } @@ -52,7 +62,7 @@ public class ReduceGroupBuilder( ) { groupRules += { source -> listOf( - JoinGroup(groupName, source.filter(filter)).apply(action) + JoinGroup(groupName, source.filter(filter), outputType).apply(action) ) } } @@ -62,19 +72,17 @@ public class ReduceGroupBuilder( */ public fun result(resultName: String, f: suspend ActionEnv.(Map) -> R) { groupRules += { node -> - listOf(JoinGroup(resultName, node).apply { result(f) }) + listOf(JoinGroup(resultName, node, outputType).apply { result(outputType, f) }) } } - internal suspend fun buildGroups(input: DataSet): List> { - return groupRules.flatMap { it.invoke(input) } - } + internal suspend fun buildGroups(input: DataSet): List> = + groupRules.flatMap { it.invoke(input) } } @PublishedApi internal class ReduceAction( - private val inputType: KType, outputType: KType, private val action: ReduceGroupBuilder.() -> Unit, ) : CachingAction(outputType) { @@ -82,7 +90,7 @@ internal class ReduceAction( override fun CoroutineScope.transform(set: DataSet, meta: Meta, key: Name): Flow> = flow { - ReduceGroupBuilder(inputType, this@transform, meta).apply(action).buildGroups(set).forEach { group -> + ReduceGroupBuilder(this@transform, meta, outputType).apply(action).buildGroups(set).forEach { group -> val dataFlow: Map> = group.set.dataSequence().fold(HashMap()) { acc, value -> acc.apply { acc[value.name] = value.data @@ -95,7 +103,7 @@ internal class ReduceAction( val env = ActionEnv(Name.parse(groupName), groupMeta, meta) @OptIn(DFInternal::class) val res: Data = dataFlow.reduceToData( - outputType, + group.outputType, meta = groupMeta ) { group.result.invoke(env, it) } @@ -111,4 +119,4 @@ internal class ReduceAction( @Suppress("FunctionName") public inline fun Action.Companion.reduce( noinline builder: ReduceGroupBuilder.() -> Unit, -): Action = ReduceAction(typeOf(), typeOf(), builder) +): Action = ReduceAction(typeOf(), builder) diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt index 88d047cd..0f7446a5 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt @@ -1,7 +1,6 @@ package space.kscience.dataforge.actions import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.launch import space.kscience.dataforge.data.* import space.kscience.dataforge.meta.Laminate @@ -18,10 +17,15 @@ import kotlin.reflect.typeOf public class SplitBuilder(public val name: Name, public val meta: Meta) { - public class FragmentRule(public val name: Name, public var meta: MutableMeta) { + public class FragmentRule( + public val name: Name, + public var meta: MutableMeta, + @PublishedApi internal var outputType: KType, + ) { public lateinit var result: suspend (T) -> R - public fun result(f: suspend (T) -> R) { + public inline fun result(noinline f: suspend (T) -> R1) { + this.outputType = typeOf() result = f; } } @@ -47,7 +51,6 @@ internal class SplitAction( private val action: SplitBuilder.() -> Unit, ) : Action { - @OptIn(FlowPreview::class) override suspend fun execute( dataSet: DataSet, meta: Meta, @@ -62,7 +65,11 @@ internal class SplitAction( // apply individual fragment rules to result return split.fragments.entries.asSequence().map { (fragmentName, rule) -> - val env = SplitBuilder.FragmentRule(fragmentName, laminate.toMutableMeta()).apply(rule) + val env = SplitBuilder.FragmentRule( + fragmentName, + laminate.toMutableMeta(), + outputType + ).apply(rule) //data.map(outputType, meta = env.meta) { env.result(it) }.named(fragmentName) @OptIn(DFInternal::class) Data(outputType, meta = env.meta, dependencies = listOf(data)) { env.result(data.await()) @@ -71,7 +78,7 @@ internal class SplitAction( } return ActiveDataTree(outputType) { - populateWith(dataSet.dataSequence().flatMap (transform = ::splitOne)) + populateWith(dataSet.dataSequence().flatMap(transform = ::splitOne)) scope?.launch { dataSet.updates.collect { name -> //clear old nodes