Added unsafe data casts for all platforms and safeCast for JVM
This commit is contained in:
parent
352b98be9b
commit
c239abe6e8
@ -4,7 +4,6 @@ import hep.dataforge.meta.EmptyMeta
|
|||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
import hep.dataforge.meta.MetaRepr
|
import hep.dataforge.meta.MetaRepr
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@ -66,34 +65,6 @@ interface Data<out T : Any> : Goal<T>, MetaRepr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
|
|
||||||
return object : Data<R> by this {
|
|
||||||
override val type: KClass<out R> = type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Upcast a [Data] to a supertype
|
|
||||||
*/
|
|
||||||
inline fun <reified R : Any, T : R> Data<T>.upcast(): Data<R> = upcast(R::class)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unsafe cast of data node
|
|
||||||
*/
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun <R: Any> Data<*>.cast(type: KClass<out R>): Data<R>{
|
|
||||||
return object : Data<R> {
|
|
||||||
override val meta: Meta get() = this@cast.meta
|
|
||||||
override val dependencies: Collection<Goal<*>> get() = this@cast.dependencies
|
|
||||||
override val result: Deferred<R>? get() = this@cast.result as Deferred<R>
|
|
||||||
override fun startAsync(scope: CoroutineScope): Deferred<R> = this@cast.startAsync(scope) as Deferred<R>
|
|
||||||
override fun reset() = this@cast.reset()
|
|
||||||
override val type: KClass<out R> = type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <reified R : Any, T : R> Data<T>.cast(): Data<R> = cast(R::class)
|
|
||||||
|
|
||||||
class DynamicData<T : Any>(
|
class DynamicData<T : Any>(
|
||||||
override val type: KClass<out T>,
|
override val type: KClass<out T>,
|
||||||
override val meta: Meta = EmptyMeta,
|
override val meta: Meta = EmptyMeta,
|
||||||
|
@ -225,10 +225,3 @@ fun <T : Any> DataNode<T>.filter(predicate: (Name, Data<T>) -> Boolean): DataNod
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> DataNode<T>.first(): Data<T>? = dataSequence().first().second
|
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
|
|
||||||
*/
|
|
||||||
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>
|
|
@ -80,7 +80,7 @@ class JoinAction<T : Any, R : Any>(
|
|||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
||||||
node.checkType(inputType)
|
node.ensureType(inputType)
|
||||||
return DataNode.build(outputType) {
|
return DataNode.build(outputType) {
|
||||||
JoinGroupBuilder<T, R>(meta).apply(action).buildGroups(node).forEach { group ->
|
JoinGroupBuilder<T, R>(meta).apply(action).buildGroups(node).forEach { group ->
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class PipeAction<T : Any, R : Any>(
|
|||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
||||||
node.checkType(inputType)
|
node.ensureType(inputType)
|
||||||
|
|
||||||
return DataNode.build(outputType) {
|
return DataNode.build(outputType) {
|
||||||
node.dataSequence().forEach { (name, data) ->
|
node.dataSequence().forEach { (name, data) ->
|
||||||
|
@ -39,7 +39,7 @@ class SplitAction<T : Any, R : Any>(
|
|||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
|
||||||
node.checkType(inputType)
|
node.ensureType(inputType)
|
||||||
|
|
||||||
return DataNode.build(outputType) {
|
return DataNode.build(outputType) {
|
||||||
node.dataSequence().forEach { (name, data) ->
|
node.dataSequence().forEach { (name, data) ->
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
package hep.dataforge.data
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
|
||||||
|
return object : Data<R> by this {
|
||||||
|
override val type: KClass<out R> = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safe upcast a [Data] to a supertype
|
||||||
|
*/
|
||||||
|
inline fun <reified R : Any, T : R> Data<T>.upcast(): Data<R> = upcast(R::class)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if node could be safely cast to given class
|
||||||
|
*/
|
||||||
|
expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if data could be safely cast to given class
|
||||||
|
*/
|
||||||
|
expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean
|
||||||
|
|
||||||
|
fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
|
||||||
|
is DataItem.Node -> value.canCast(type)
|
||||||
|
is DataItem.Leaf -> value.canCast(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe cast of data node
|
||||||
|
*/
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> {
|
||||||
|
return object : Data<R> {
|
||||||
|
override val meta: Meta get() = this@cast.meta
|
||||||
|
override val dependencies: Collection<Goal<*>> get() = this@cast.dependencies
|
||||||
|
override val result: Deferred<R>? get() = this@cast.result as Deferred<R>
|
||||||
|
override fun startAsync(scope: CoroutineScope): Deferred<R> = this@cast.startAsync(scope) as Deferred<R>
|
||||||
|
override fun reset() = this@cast.reset()
|
||||||
|
override val type: KClass<out R> = type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(R::class)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <R : Any> DataNode<*>.cast(type: KClass<out R>): DataNode<R> {
|
||||||
|
return object : DataNode<R> {
|
||||||
|
override val type: KClass<out R> = type
|
||||||
|
override val items: Map<NameToken, DataItem<R>> get() = this@cast.items as Map<NameToken, DataItem<R>>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified R : Any> DataNode<*>.cast(): DataNode<R> = cast(R::class)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||||
|
*/
|
||||||
|
fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
|
||||||
|
if (!canCast(type)) {
|
||||||
|
error("$type expected, but $type received")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//expect fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R>
|
@ -5,14 +5,12 @@ import kotlin.reflect.KClass
|
|||||||
/**
|
/**
|
||||||
* 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 <T : Any> DataNode<*>.checkType(type: KClass<out T>) {
|
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
|
||||||
//Not supported in js yet
|
//Not supported in js yet
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
///**
|
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
|
||||||
// * Performing
|
//Not supported in js yet
|
||||||
// */
|
return true
|
||||||
//@Suppress("UNCHECKED_CAST")
|
}
|
||||||
//actual fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R>{
|
|
||||||
// return this as DataNode<R>
|
|
||||||
//}
|
|
||||||
|
@ -2,18 +2,8 @@ package hep.dataforge.data
|
|||||||
|
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.full.isSubclassOf
|
|
||||||
|
|
||||||
|
|
||||||
fun <T : Any, R : Any> Data<T>.canCast(type: KClass<out R>): Boolean =
|
|
||||||
this.type.isSubclassOf(type)
|
|
||||||
|
|
||||||
fun <T : Any, R : Any> Data<T>.safeCast(type: KClass<out R>): Data<R>? =
|
|
||||||
if (canCast(type)) cast(type) else null
|
|
||||||
|
|
||||||
|
|
||||||
//inline fun <reified R : Any> Data<*>.safeCast(): Data<R>? = safeCast(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) ->
|
||||||
|
@ -2,6 +2,7 @@ package hep.dataforge.data
|
|||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.full.isSuperclassOf
|
import kotlin.reflect.full.isSuperclassOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,11 +13,15 @@ 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 <T : Any> DataNode<*>.checkType(type: KClass<out T>) {
|
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
|
||||||
if (!type.isSuperclassOf(type)) {
|
type.isSuperclassOf(type)
|
||||||
error("$type expected, but $type received")
|
|
||||||
}
|
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
|
||||||
}
|
this.type.isSubclassOf(type)
|
||||||
|
|
||||||
|
|
||||||
|
fun <R : Any> Data<*>.safeCast(type: KClass<out R>): Data<R>? =
|
||||||
|
if (canCast(type)) cast(type) else null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
|
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
|
||||||
@ -30,8 +35,6 @@ fun <R : Any> DataNode<*>.safeCast(type: KClass<out R>): DataNode<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified R : Any> DataNode<*>.cast(): DataNode<R> = safeCast(R::class)
|
|
||||||
|
|
||||||
fun <R : Any> DataItem<*>?.safeCast(type: KClass<out R>): DataItem<R>? = when (this) {
|
fun <R : Any> DataItem<*>?.safeCast(type: KClass<out R>): DataItem<R>? = when (this) {
|
||||||
null -> null
|
null -> null
|
||||||
is DataItem.Node -> DataItem.Node(this.value.safeCast(type))
|
is DataItem.Node -> DataItem.Node(this.value.safeCast(type))
|
||||||
@ -39,3 +42,5 @@ fun <R : Any> DataItem<*>?.safeCast(type: KClass<out R>): DataItem<R>? = when (t
|
|||||||
this.value.safeCast(type) ?: error("Can't cast data with type ${this.value.type} to $type")
|
this.value.safeCast(type) ?: error("Can't cast data with type ${this.value.type} to $type")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified R : Any> DataItem<*>?.safeCast(): DataItem<R>? = safeCast(R::class)
|
@ -47,7 +47,7 @@ class TaskBuilder(val name: String) {
|
|||||||
block: TaskEnv.(DataNode<T>) -> DataNode<Any>
|
block: TaskEnv.(DataNode<T>) -> DataNode<Any>
|
||||||
) {
|
) {
|
||||||
dataTransforms += DataTransformation(from, to) { context, model, data ->
|
dataTransforms += DataTransformation(from, to) { context, model, data ->
|
||||||
data.checkType(inputType)
|
data.ensureType(inputType)
|
||||||
val env = TaskEnv(EmptyName, model.meta, context)
|
val env = TaskEnv(EmptyName, model.meta, context)
|
||||||
env.block(data.safeCast(inputType))
|
env.block(data.safeCast(inputType))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user