Refactored TaskBuilder to be more predictable

This commit is contained in:
Alexander Nozik 2019-09-04 09:50:56 +03:00
parent 7045f34c2c
commit 418e1c2134
6 changed files with 51 additions and 42 deletions

View File

@ -227,4 +227,6 @@ fun <T : Any> DataNode<T>.first(): Data<T>? = dataSequence().first().second
/** /**
* Check that node is compatible with given type meaning that each element could be cast to the type * Check that node is compatible with given type meaning that each element could be cast to the type
*/ */
expect fun DataNode<*>.checkType(type: KClass<*>) expect fun <T : Any> DataNode<*>.checkType(type: KClass<out T>)
//expect fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R>

View File

@ -1,10 +0,0 @@
package hep.dataforge.data
import kotlin.reflect.KClass
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
actual fun DataNode<*>.checkType(type: KClass<*>) {
//Not supported in js yet
}

View File

@ -0,0 +1,18 @@
package hep.dataforge.data
import kotlin.reflect.KClass
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
actual fun <T : Any> DataNode<*>.checkType(type: KClass<out T>) {
//Not supported in js yet
}
///**
// * Performing
// */
//@Suppress("UNCHECKED_CAST")
//actual fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R>{
// return this as DataNode<R>
//}

View File

@ -8,7 +8,7 @@ import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : Any, R : Any> Data<T>.safeCast(type: KClass<out R>): Data<R>? { private fun <T : Any, R : Any> Data<T>.safeCast(type: KClass<out R>): Data<R>? {
return if (this.type.isSubclassOf(type)) { return if (this.type.isSubclassOf(type)) {
return object : Data<R> { return object : Data<R> {
override val meta: Meta get() = this@safeCast.meta override val meta: Meta get() = this@safeCast.meta
@ -23,20 +23,6 @@ fun <T : Any, R : Any> Data<T>.safeCast(type: KClass<out R>): Data<R>? {
} }
} }
/**
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
* but could contain empty nodes
*/
fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R> {
return if (this is CastDataNode) {
origin.cast(type)
} else {
CastDataNode(this, type)
}
}
inline fun <T : Any, reified R : Any> DataNode<T>.cast(): DataNode<R> = cast(R::class)
class CastDataNode<out T : Any>(val origin: DataNode<Any>, override val type: KClass<out T>) : DataNode<T> { class CastDataNode<out T : Any>(val origin: DataNode<Any>, override val type: KClass<out T>) : DataNode<T> {
override val items: Map<NameToken, DataItem<T>> by lazy { override val items: Map<NameToken, DataItem<T>> by lazy {
origin.items.mapNotNull { (key, item) -> origin.items.mapNotNull { (key, item) ->

View File

@ -12,8 +12,22 @@ fun <T : Any> Data<T>.get(): T = runBlocking { await() }
/** /**
* Check that node is compatible with given type meaning that each element could be cast to the type * Check that node is compatible with given type meaning that each element could be cast to the type
*/ */
actual fun DataNode<*>.checkType(type: KClass<*>) { actual fun <T: Any> DataNode<*>.checkType(type: KClass<out T>) {
if (!type.isSuperclassOf(type)) { if (!type.isSuperclassOf(type)) {
error("$type expected, but $type received") error("$type expected, but $type received")
} }
} }
/**
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
* but could contain empty nodes
*/
fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R> {
return if (this is CastDataNode) {
origin.cast(type)
} else {
CastDataNode(this, type)
}
}
inline fun <T : Any, reified R : Any> DataNode<T>.cast(): DataNode<R> = cast(R::class)

View File

@ -6,6 +6,7 @@ import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.get import hep.dataforge.meta.get
import hep.dataforge.meta.string import hep.dataforge.meta.string
import hep.dataforge.names.EmptyName
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -14,6 +15,7 @@ import kotlin.reflect.KClass
class TaskBuilder(val name: String) { class TaskBuilder(val name: String) {
private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { data("*") } private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { data("*") }
var descriptor: NodeDescriptor? = null var descriptor: NodeDescriptor? = null
private val dataTransforms: MutableList<DataTransformation> = ArrayList()
/** /**
* TODO will look better as extension class * TODO will look better as extension class
@ -33,8 +35,6 @@ class TaskBuilder(val name: String) {
} }
} }
private val dataTransforms: MutableList<DataTransformation> = ArrayList();
fun model(modelTransform: TaskModelBuilder.(Meta) -> Unit) { fun model(modelTransform: TaskModelBuilder.(Meta) -> Unit) {
this.modelTransform = modelTransform this.modelTransform = modelTransform
} }
@ -43,17 +43,19 @@ class TaskBuilder(val name: String) {
inputType: KClass<T>, inputType: KClass<T>,
from: String = "", from: String = "",
to: String = "", to: String = "",
block: TaskModel.(Context, DataNode<T>) -> DataNode<Any> block: TaskEnv.(DataNode<T>) -> DataNode<Any>
) { ) {
dataTransforms += DataTransformation(from, to) { context, model, data -> dataTransforms += DataTransformation(from, to) { context, model, data ->
block(model, context, data.cast(inputType)) data.checkType(inputType)
val env = TaskEnv(EmptyName, model.meta, context)
env.block(data.cast(inputType))
} }
} }
inline fun <reified T : Any> transform( inline fun <reified T : Any> transform(
from: String = "", from: String = "",
to: String = "", to: String = "",
noinline block: TaskModel.(Context, DataNode<T>) -> DataNode<Any> noinline block: TaskEnv.(DataNode<T>) -> DataNode<Any>
) { ) {
transform(T::class, from, to, block) transform(T::class, from, to, block)
} }
@ -64,10 +66,10 @@ class TaskBuilder(val name: String) {
inline fun <reified T : Any, reified R : Any> action( inline fun <reified T : Any, reified R : Any> action(
from: String = "", from: String = "",
to: String = "", to: String = "",
crossinline block: Context.() -> Action<T, R> crossinline block: TaskEnv.() -> Action<T, R>
) { ) {
transform(from, to) { context, data: DataNode<T> -> transform(from, to) { data: DataNode<T> ->
block(context).invoke(data, meta) block().invoke(data, meta)
} }
} }
@ -82,7 +84,6 @@ class TaskBuilder(val name: String) {
crossinline block: PipeBuilder<T, R>.(Context) -> Unit crossinline block: PipeBuilder<T, R>.(Context) -> Unit
) { ) {
action(from, to) { action(from, to) {
val context = this
PipeAction( PipeAction(
inputType = T::class, inputType = T::class,
outputType = R::class outputType = R::class
@ -99,7 +100,6 @@ class TaskBuilder(val name: String) {
crossinline block: suspend TaskEnv.(T) -> R crossinline block: suspend TaskEnv.(T) -> R
) { ) {
action(from, to) { action(from, to) {
val context = this
PipeAction( PipeAction(
inputType = T::class, inputType = T::class,
outputType = R::class outputType = R::class
@ -124,7 +124,7 @@ class TaskBuilder(val name: String) {
JoinAction( JoinAction(
inputType = T::class, inputType = T::class,
outputType = R::class outputType = R::class
) { block(this@action) } ) { block(context) }
} }
} }
@ -137,7 +137,6 @@ class TaskBuilder(val name: String) {
crossinline block: suspend TaskEnv.(Map<Name, T>) -> R crossinline block: suspend TaskEnv.(Map<Name, T>) -> R
) { ) {
action(from, to) { action(from, to) {
val context = this
JoinAction( JoinAction(
inputType = T::class, inputType = T::class,
outputType = R::class, outputType = R::class,
@ -164,7 +163,7 @@ class TaskBuilder(val name: String) {
SplitAction( SplitAction(
inputType = T::class, inputType = T::class,
outputType = R::class outputType = R::class
) { block(this@action) } ) { block(context) }
} }
} }
@ -187,7 +186,7 @@ class TaskBuilder(val name: String) {
val model = this val model = this
if (dataTransforms.isEmpty()) { if (dataTransforms.isEmpty()) {
//return data node as is //return data node as is
logger.warn("No transformation present, returning input data") logger.warn { "No transformation present, returning input data" }
data data
} else { } else {
val builder = DataTreeBuilder(Any::class) val builder = DataTreeBuilder(Any::class)