Reify types for action builders

This commit is contained in:
Alexander Nozik 2022-05-01 20:23:37 +03:00
parent 665f317e4e
commit f0820a3bed
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
4 changed files with 42 additions and 21 deletions

View File

@ -5,6 +5,7 @@
- Add `specOrNull` delegate to meta and Scheme - Add `specOrNull` delegate to meta and Scheme
- Suspended read methods to the `Binary` - Suspended read methods to the `Binary`
- Synchronously accessed `meta` to all `DataSet`s - Synchronously accessed `meta` to all `DataSet`s
- More fine-grained types in Action builders.
### Changed ### Changed
- `Factory` is now `fun interface` and uses `build` instead of `invoke`. `invoke moved to an extension. - `Factory` is now `fun interface` and uses `build` instead of `invoke`. `invoke moved to an extension.

View File

@ -31,15 +31,20 @@ public class MapActionBuilder<T, R>(
public var name: Name, public var name: Name,
public var meta: MutableMeta, public var meta: MutableMeta,
public val actionMeta: Meta, public val actionMeta: Meta,
public var outputType: KType @PublishedApi internal var outputType: KType,
) { ) {
public lateinit var result: suspend ActionEnv.(T) -> R public lateinit var result: suspend ActionEnv.(T) -> R
internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(T) -> R1) {
this.outputType = outputType
result = f;
}
/** /**
* Calculate the result of goal * Calculate the result of goal
*/ */
public inline fun <reified R1: R> result(noinline f: suspend ActionEnv.(T) -> R1) { public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(T) -> R1) {
outputType = typeOf<R1>() outputType = typeOf<R1>()
result = f; result = f;
} }

View File

@ -14,13 +14,23 @@ import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
public class JoinGroup<T : Any, R : Any>(public var name: String, internal val set: DataSet<T>) { public class JoinGroup<T : Any, R : Any>(
public var name: String,
internal val set: DataSet<T>,
@PublishedApi internal var outputType: KType,
) {
public var meta: MutableMeta = MutableMeta() public var meta: MutableMeta = MutableMeta()
public lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R public lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R
public fun result(f: suspend ActionEnv.(Map<Name, T>) -> R) { internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(Map<Name, T>) -> R1) {
this.outputType = outputType
this.result = f;
}
public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(Map<Name, T>) -> R1) {
outputType = typeOf<R1>()
this.result = f; this.result = f;
} }
@ -28,9 +38,9 @@ public class JoinGroup<T : Any, R : Any>(public var name: String, internal val s
@DFBuilder @DFBuilder
public class ReduceGroupBuilder<T : Any, R : Any>( public class ReduceGroupBuilder<T : Any, R : Any>(
private val inputType: KType,
private val scope: CoroutineScope, private val scope: CoroutineScope,
public val actionMeta: Meta, public val actionMeta: Meta,
private val outputType: KType
) { ) {
private val groupRules: MutableList<suspend (DataSet<T>) -> List<JoinGroup<T, R>>> = ArrayList(); private val groupRules: MutableList<suspend (DataSet<T>) -> List<JoinGroup<T, R>>> = ArrayList();
@ -40,7 +50,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) { public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) {
groupRules += { node -> groupRules += { node ->
GroupRule.byMetaValue(scope, tag, defaultTag).gather(node).map { GroupRule.byMetaValue(scope, tag, defaultTag).gather(node).map {
JoinGroup<T, R>(it.key, it.value).apply(action) JoinGroup<T, R>(it.key, it.value, outputType).apply(action)
} }
} }
} }
@ -52,7 +62,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
) { ) {
groupRules += { source -> groupRules += { source ->
listOf( listOf(
JoinGroup<T, R>(groupName, source.filter(filter)).apply(action) JoinGroup<T, R>(groupName, source.filter(filter), outputType).apply(action)
) )
} }
} }
@ -62,19 +72,17 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
*/ */
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) { public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) {
groupRules += { node -> groupRules += { node ->
listOf(JoinGroup<T, R>(resultName, node).apply { result(f) }) listOf(JoinGroup<T, R>(resultName, node, outputType).apply { result(outputType, f) })
} }
} }
internal suspend fun buildGroups(input: DataSet<T>): List<JoinGroup<T, R>> { internal suspend fun buildGroups(input: DataSet<T>): List<JoinGroup<T, R>> =
return groupRules.flatMap { it.invoke(input) } groupRules.flatMap { it.invoke(input) }
}
} }
@PublishedApi @PublishedApi
internal class ReduceAction<T : Any, R : Any>( internal class ReduceAction<T : Any, R : Any>(
private val inputType: KType,
outputType: KType, outputType: KType,
private val action: ReduceGroupBuilder<T, R>.() -> Unit, private val action: ReduceGroupBuilder<T, R>.() -> Unit,
) : CachingAction<T, R>(outputType) { ) : CachingAction<T, R>(outputType) {
@ -82,7 +90,7 @@ internal class ReduceAction<T : Any, R : Any>(
override fun CoroutineScope.transform(set: DataSet<T>, meta: Meta, key: Name): Flow<NamedData<R>> = flow { override fun CoroutineScope.transform(set: DataSet<T>, meta: Meta, key: Name): Flow<NamedData<R>> = flow {
ReduceGroupBuilder<T, R>(inputType, this@transform, meta).apply(action).buildGroups(set).forEach { group -> ReduceGroupBuilder<T, R>(this@transform, meta, outputType).apply(action).buildGroups(set).forEach { group ->
val dataFlow: Map<Name, Data<T>> = group.set.dataSequence().fold(HashMap()) { acc, value -> val dataFlow: Map<Name, Data<T>> = group.set.dataSequence().fold(HashMap()) { acc, value ->
acc.apply { acc.apply {
acc[value.name] = value.data acc[value.name] = value.data
@ -95,7 +103,7 @@ internal class ReduceAction<T : Any, R : Any>(
val env = ActionEnv(Name.parse(groupName), groupMeta, meta) val env = ActionEnv(Name.parse(groupName), groupMeta, meta)
@OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData( @OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData(
outputType, group.outputType,
meta = groupMeta meta = groupMeta
) { group.result.invoke(env, it) } ) { group.result.invoke(env, it) }
@ -111,4 +119,4 @@ internal class ReduceAction<T : Any, R : Any>(
@Suppress("FunctionName") @Suppress("FunctionName")
public inline fun <reified T : Any, reified R : Any> Action.Companion.reduce( public inline fun <reified T : Any, reified R : Any> Action.Companion.reduce(
noinline builder: ReduceGroupBuilder<T, R>.() -> Unit, noinline builder: ReduceGroupBuilder<T, R>.() -> Unit,
): Action<T, R> = ReduceAction(typeOf<T>(), typeOf<R>(), builder) ): Action<T, R> = ReduceAction(typeOf<R>(), builder)

View File

@ -1,7 +1,6 @@
package space.kscience.dataforge.actions package space.kscience.dataforge.actions
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import space.kscience.dataforge.data.* import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Laminate
@ -18,10 +17,15 @@ import kotlin.reflect.typeOf
public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) { public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) {
public class FragmentRule<T : Any, R : Any>(public val name: Name, public var meta: MutableMeta) { public class FragmentRule<T : Any, R : Any>(
public val name: Name,
public var meta: MutableMeta,
@PublishedApi internal var outputType: KType,
) {
public lateinit var result: suspend (T) -> R public lateinit var result: suspend (T) -> R
public fun result(f: suspend (T) -> R) { public inline fun <reified R1 : R> result(noinline f: suspend (T) -> R1) {
this.outputType = typeOf<R1>()
result = f; result = f;
} }
} }
@ -47,7 +51,6 @@ internal class SplitAction<T : Any, R : Any>(
private val action: SplitBuilder<T, R>.() -> Unit, private val action: SplitBuilder<T, R>.() -> Unit,
) : Action<T, R> { ) : Action<T, R> {
@OptIn(FlowPreview::class)
override suspend fun execute( override suspend fun execute(
dataSet: DataSet<T>, dataSet: DataSet<T>,
meta: Meta, meta: Meta,
@ -62,7 +65,11 @@ internal class SplitAction<T : Any, R : Any>(
// apply individual fragment rules to result // apply individual fragment rules to result
return split.fragments.entries.asSequence().map { (fragmentName, rule) -> return split.fragments.entries.asSequence().map { (fragmentName, rule) ->
val env = SplitBuilder.FragmentRule<T, R>(fragmentName, laminate.toMutableMeta()).apply(rule) val env = SplitBuilder.FragmentRule<T, R>(
fragmentName,
laminate.toMutableMeta(),
outputType
).apply(rule)
//data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName) //data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
@OptIn(DFInternal::class) Data(outputType, meta = env.meta, dependencies = listOf(data)) { @OptIn(DFInternal::class) Data(outputType, meta = env.meta, dependencies = listOf(data)) {
env.result(data.await()) env.result(data.await())
@ -71,7 +78,7 @@ internal class SplitAction<T : Any, R : Any>(
} }
return ActiveDataTree<R>(outputType) { return ActiveDataTree<R>(outputType) {
populateWith(dataSet.dataSequence().flatMap (transform = ::splitOne)) populateWith(dataSet.dataSequence().flatMap(transform = ::splitOne))
scope?.launch { scope?.launch {
dataSet.updates.collect { name -> dataSet.updates.collect { name ->
//clear old nodes //clear old nodes