Refactored TaskBuilder to be more predictable
This commit is contained in:
parent
7045f34c2c
commit
418e1c2134
@ -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>
|
@ -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
|
|
||||||
}
|
|
@ -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>
|
||||||
|
//}
|
@ -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) ->
|
||||||
|
@ -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)
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user