[WIP] change KClass to KType
This commit is contained in:
parent
6a0bfae931
commit
fcd99b1ca8
@ -12,10 +12,6 @@ kotlin {
|
||||
commonMain{
|
||||
dependencies {
|
||||
api(project(":dataforge-meta"))
|
||||
}
|
||||
}
|
||||
jvmMain{
|
||||
dependencies{
|
||||
api(kotlin("reflect"))
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Action environment includes data name, data meta and action configuration meta
|
||||
@ -34,8 +35,9 @@ public class MapActionBuilder<T, R>(public var name: Name, public var meta: Meta
|
||||
}
|
||||
|
||||
|
||||
public class MapAction<in T : Any, out R : Any>(
|
||||
public val outputType: KClass<out R>,
|
||||
@PublishedApi
|
||||
internal class MapAction<in T : Any, out R : Any>(
|
||||
private val outputType: KType,
|
||||
private val block: MapActionBuilder<T, R>.() -> Unit,
|
||||
) : Action<T, R> {
|
||||
|
||||
@ -84,8 +86,8 @@ public class MapAction<in T : Any, out R : Any>(
|
||||
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public inline fun <T : Any, reified R : Any> MapAction(
|
||||
public inline fun <T : Any, reified R : Any> Action.Companion.map(
|
||||
noinline builder: MapActionBuilder<T, R>.() -> Unit,
|
||||
): MapAction<T, R> = MapAction(R::class, builder)
|
||||
): Action<T, R> = MapAction(typeOf<R>(), builder)
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.fold
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
|
||||
@DFExperimental
|
||||
@ -75,7 +76,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
|
||||
@DFExperimental
|
||||
public class ReduceAction<T : Any, R : Any>(
|
||||
private val inputType: KClass<out T>,
|
||||
outputType: KClass<out R>,
|
||||
outputType: KType,
|
||||
private val action: ReduceGroupBuilder<T, R>.() -> Unit,
|
||||
) : CachingAction<T, R>(outputType) {
|
||||
//TODO optimize reduction. Currently the whole action recalculates on push
|
||||
|
@ -11,7 +11,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.collections.set
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
|
||||
public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) {
|
||||
@ -39,8 +39,8 @@ public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val me
|
||||
/**
|
||||
* Action that splits each incoming element into a number of fragments defined in builder
|
||||
*/
|
||||
public class SplitAction<T : Any, R : Any>(
|
||||
private val outputType: KClass<out R>,
|
||||
internal class SplitAction<T : Any, R : Any>(
|
||||
private val outputType: KType,
|
||||
private val action: SplitBuilder<T, R>.() -> Unit,
|
||||
) : Action<T, R> {
|
||||
|
||||
@ -59,11 +59,11 @@ public class SplitAction<T : Any, R : Any>(
|
||||
// apply individual fragment rules to result
|
||||
return split.fragments.entries.asFlow().map { (fragmentName, rule) ->
|
||||
val env = SplitBuilder.FragmentRule<T, R>(fragmentName, laminate.toMutableMeta()).apply(rule)
|
||||
data.map(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
|
||||
data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
|
||||
}
|
||||
}
|
||||
|
||||
return ActiveDataTree(outputType) {
|
||||
return ActiveDataTree<R>(outputType) {
|
||||
populate(dataSet.flow().flatMapConcat(transform = ::splitOne))
|
||||
scope?.launch {
|
||||
dataSet.updates.collect { name ->
|
||||
|
@ -8,13 +8,14 @@ import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* A mutable [DataTree.Companion.active]. It
|
||||
*/
|
||||
public class ActiveDataTree<T : Any>(
|
||||
override val dataType: KClass<out T>,
|
||||
override val dataType: KType,
|
||||
) : DataTree<T>, DataSetBuilder<T>, ActiveDataSet<T> {
|
||||
private val mutex = Mutex()
|
||||
private val treeItems = HashMap<NameToken, DataTreeItem<T>>()
|
||||
@ -49,7 +50,7 @@ public class ActiveDataTree<T : Any>(
|
||||
|
||||
private suspend fun getOrCreateNode(token: NameToken): ActiveDataTree<T> =
|
||||
(treeItems[token] as? DataTreeItem.Node<T>)?.tree as? ActiveDataTree<T>
|
||||
?: ActiveDataTree(dataType).also {
|
||||
?: ActiveDataTree<T>(dataType).also {
|
||||
mutex.withLock {
|
||||
treeItems[token] = DataTreeItem.Node(it)
|
||||
}
|
||||
@ -92,10 +93,10 @@ public class ActiveDataTree<T : Any>(
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
public suspend fun <T : Any> ActiveDataTree(
|
||||
type: KClass<out T>,
|
||||
type: KType,
|
||||
block: suspend ActiveDataTree<T>.() -> Unit,
|
||||
): ActiveDataTree<T> {
|
||||
val tree = ActiveDataTree(type)
|
||||
val tree = ActiveDataTree<T>(type)
|
||||
tree.block()
|
||||
return tree
|
||||
}
|
||||
@ -103,15 +104,15 @@ public suspend fun <T : Any> ActiveDataTree(
|
||||
@Suppress("FunctionName")
|
||||
public suspend inline fun <reified T : Any> ActiveDataTree(
|
||||
crossinline block: suspend ActiveDataTree<T>.() -> Unit,
|
||||
): ActiveDataTree<T> = ActiveDataTree(T::class).apply { block() }
|
||||
): ActiveDataTree<T> = ActiveDataTree<T>(typeOf<T>()).apply { block() }
|
||||
|
||||
|
||||
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
|
||||
name: Name,
|
||||
noinline block: suspend ActiveDataTree<T>.() -> Unit,
|
||||
): Unit = emit(name, ActiveDataTree(T::class, block))
|
||||
): Unit = emit(name, ActiveDataTree(typeOf<T>(), block))
|
||||
|
||||
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
|
||||
name: String,
|
||||
noinline block: suspend ActiveDataTree<T>.() -> Unit,
|
||||
): Unit = emit(name.toName(), ActiveDataTree(T::class, block))
|
||||
): Unit = emit(name.toName(), ActiveDataTree(typeOf<T>(), block))
|
||||
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
/**
|
||||
* Remove all values with keys starting with [name]
|
||||
@ -23,7 +23,7 @@ internal fun MutableMap<Name, *>.removeWhatStartsWith(name: Name) {
|
||||
* An action that caches results on-demand and recalculates them on source push
|
||||
*/
|
||||
public abstract class CachingAction<in T : Any, out R : Any>(
|
||||
public val outputType: KClass<out R>,
|
||||
public val outputType: KType,
|
||||
) : Action<T, R> {
|
||||
|
||||
protected abstract fun CoroutineScope.transform(
|
||||
@ -36,7 +36,7 @@ public abstract class CachingAction<in T : Any, out R : Any>(
|
||||
dataSet: DataSet<T>,
|
||||
meta: Meta,
|
||||
scope: CoroutineScope?,
|
||||
): DataSet<R> = ActiveDataTree(outputType) {
|
||||
): DataSet<R> = ActiveDataTree<R>(outputType) {
|
||||
coroutineScope {
|
||||
populate(transform(dataSet, meta))
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import hep.dataforge.misc.Type
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* A data element characterized by its meta
|
||||
@ -17,7 +18,7 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
||||
/**
|
||||
* Type marker for the data. The type is known before the calculation takes place so it could be checked.
|
||||
*/
|
||||
public val type: KClass<out T>
|
||||
public val type: KType
|
||||
|
||||
/**
|
||||
* Meta for the data
|
||||
@ -25,7 +26,7 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
||||
public val meta: Meta
|
||||
|
||||
override fun toMeta(): Meta = Meta {
|
||||
"type" put (type.simpleName ?: "undefined")
|
||||
"type" put (type.toString())
|
||||
if (!meta.isEmpty()) {
|
||||
"meta" put meta
|
||||
}
|
||||
@ -34,16 +35,17 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
||||
public companion object {
|
||||
public const val TYPE: String = "data"
|
||||
|
||||
public fun <T : Any> static(
|
||||
public inline fun <reified T : Any> static(
|
||||
value: T,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
): Data<T> = StaticData(value, meta)
|
||||
): Data<T> = StaticData(typeOf<T>(),value, meta)
|
||||
|
||||
/**
|
||||
* An empty data containing only meta
|
||||
*/
|
||||
public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
|
||||
override val type: KClass<out Nothing> = Nothing::class
|
||||
private val nothing: Nothing get() = error("this is nothing")
|
||||
override val type: KType = this::nothing.returnType
|
||||
override val meta: Meta = meta
|
||||
override val dependencies: Collection<Goal<*>> = emptyList()
|
||||
override val deferred: Deferred<Nothing>
|
||||
@ -58,7 +60,7 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
||||
}
|
||||
|
||||
public class LazyData<T : Any>(
|
||||
override val type: KClass<out T>,
|
||||
override val type: KType,
|
||||
override val meta: Meta = Meta.EMPTY,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
dependencies: Collection<Data<*>> = emptyList(),
|
||||
@ -66,15 +68,14 @@ public class LazyData<T : Any>(
|
||||
) : Data<T>, LazyGoal<T>(context, dependencies, block)
|
||||
|
||||
public class StaticData<T : Any>(
|
||||
override val type: KType,
|
||||
value: T,
|
||||
override val meta: Meta = Meta.EMPTY,
|
||||
) : Data<T>, StaticGoal<T>(value) {
|
||||
override val type: KClass<out T> get() = value::class
|
||||
}
|
||||
) : Data<T>, StaticGoal<T>(value)
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public fun <T : Any> Data(
|
||||
type: KClass<out T>,
|
||||
type: KType,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
dependencies: Collection<Data<*>> = emptyList(),
|
||||
@ -87,4 +88,4 @@ public inline fun <reified T : Any> Data(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
dependencies: Collection<Data<*>> = emptyList(),
|
||||
noinline block: suspend () -> T,
|
||||
): Data<T> = Data(T::class, meta, context, dependencies, block)
|
||||
): Data<T> = Data(typeOf<T>(), meta, context, dependencies, block)
|
||||
|
@ -7,14 +7,14 @@ import hep.dataforge.meta.set
|
||||
import hep.dataforge.names.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
|
||||
public interface DataSet<out T : Any> {
|
||||
|
||||
/**
|
||||
* The minimal common ancestor to all data in the node
|
||||
*/
|
||||
public val dataType: KClass<out T>
|
||||
public val dataType: KType
|
||||
|
||||
/**
|
||||
* Traverse this provider or its child. The order is not guaranteed.
|
||||
@ -43,7 +43,9 @@ public interface DataSet<out T : Any> {
|
||||
* An empty [DataSet] that suits all types
|
||||
*/
|
||||
public val EMPTY: DataSet<Nothing> = object : DataSet<Nothing> {
|
||||
override val dataType: KClass<out Nothing> = Nothing::class
|
||||
override val dataType: KType = this::nothing.returnType
|
||||
|
||||
private val nothing: Nothing get() = error("this is nothing")
|
||||
|
||||
override fun flow(): Flow<NamedData<Nothing>> = emptyFlow()
|
||||
|
||||
@ -88,7 +90,7 @@ public suspend fun DataSet<*>.toMeta(): Meta = Meta {
|
||||
set(it.name, it.meta)
|
||||
} else {
|
||||
it.name put {
|
||||
"type" put it.type.simpleName
|
||||
"type" put it.type.toString()
|
||||
"meta" put it.meta
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,12 @@ package hep.dataforge.data
|
||||
import hep.dataforge.names.*
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
@PublishedApi
|
||||
internal class StaticDataTree<T : Any>(
|
||||
override val dataType: KClass<out T>,
|
||||
override val dataType: KType,
|
||||
) : DataSetBuilder<T>, DataTree<T> {
|
||||
|
||||
private val items: MutableMap<NameToken, DataTreeItem<T>> = HashMap()
|
||||
@ -26,7 +27,7 @@ internal class StaticDataTree<T : Any>(
|
||||
0 -> this
|
||||
1 -> {
|
||||
val itemName = name.firstOrNull()!!
|
||||
(items[itemName].tree as? StaticDataTree<T>) ?: StaticDataTree(dataType).also {
|
||||
(items[itemName].tree as? StaticDataTree<T>) ?: StaticDataTree<T>(dataType).also {
|
||||
items[itemName] = DataTreeItem.Node(it)
|
||||
}
|
||||
}
|
||||
@ -61,14 +62,14 @@ internal class StaticDataTree<T : Any>(
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public suspend fun <T : Any> DataTree(
|
||||
dataType: KClass<out T>,
|
||||
dataType: KType,
|
||||
block: suspend DataSetBuilder<T>.() -> Unit,
|
||||
): DataTree<T> = StaticDataTree(dataType).apply { block() }
|
||||
): DataTree<T> = StaticDataTree<T>(dataType).apply { block() }
|
||||
|
||||
@Suppress("FunctionName")
|
||||
public suspend inline fun <reified T : Any> DataTree(
|
||||
noinline block: suspend DataSetBuilder<T>.() -> Unit,
|
||||
): DataTree<T> = DataTree(T::class, block)
|
||||
): DataTree<T> = DataTree(typeOf<T>(), block)
|
||||
|
||||
public suspend fun <T : Any> DataSet<T>.seal(): DataTree<T> = DataTree(dataType){
|
||||
populate(this@seal)
|
||||
|
@ -11,7 +11,8 @@ import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
/**
|
||||
* Lazily transform this data to another data. By convention [block] should not use external data (be pure).
|
||||
@ -19,8 +20,8 @@ import kotlin.reflect.KClass
|
||||
* @param meta for the resulting data. By default equals input data.
|
||||
* @param block the transformation itself
|
||||
*/
|
||||
public fun <T : Any, R : Any> Data<T>.map(
|
||||
outputType: KClass<out R>,
|
||||
private fun <T : Any, R : Any> Data<T>.map(
|
||||
outputType: KType,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = this.meta,
|
||||
block: suspend (T) -> R,
|
||||
@ -35,7 +36,7 @@ public inline fun <T : Any, reified R : Any> Data<T>.map(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = this.meta,
|
||||
crossinline block: suspend (T) -> R,
|
||||
): LazyData<R> = LazyData(R::class, meta, coroutineContext, listOf(this)) {
|
||||
): LazyData<R> = LazyData(typeOf<R>(), meta, coroutineContext, listOf(this)) {
|
||||
block(await())
|
||||
}
|
||||
|
||||
@ -47,7 +48,7 @@ public inline fun <T1 : Any, T2 : Any, reified R : Any> Data<T1>.combine(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = this.meta,
|
||||
crossinline block: suspend (left: T1, right: T2) -> R,
|
||||
): LazyData<R> = LazyData(R::class, meta, coroutineContext, listOf(this, other)) {
|
||||
): LazyData<R> = LazyData(typeOf<R>(), meta, coroutineContext, listOf(this, other)) {
|
||||
block(await(), other.await())
|
||||
}
|
||||
|
||||
@ -62,7 +63,7 @@ public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduceToData(
|
||||
meta: Meta = Meta.EMPTY,
|
||||
crossinline block: suspend (Collection<T>) -> R,
|
||||
): LazyData<R> = LazyData(
|
||||
R::class,
|
||||
typeOf<R>(),
|
||||
meta,
|
||||
coroutineContext,
|
||||
this
|
||||
@ -71,7 +72,7 @@ public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduceToData(
|
||||
}
|
||||
|
||||
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduceToData(
|
||||
outputType: KClass<out R>,
|
||||
outputType: KType,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
block: suspend (Map<K, T>) -> R,
|
||||
@ -96,7 +97,7 @@ public inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduceToData(
|
||||
meta: Meta = Meta.EMPTY,
|
||||
noinline block: suspend (Map<K, T>) -> R,
|
||||
): LazyData<R> = LazyData(
|
||||
R::class,
|
||||
typeOf<R>(),
|
||||
meta,
|
||||
coroutineContext,
|
||||
this.values
|
||||
@ -110,7 +111,7 @@ public inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduceToData(
|
||||
* Transform a [Flow] of [NamedData] to a single [Data].
|
||||
*/
|
||||
public suspend fun <T : Any, R : Any> Flow<NamedData<T>>.reduceToData(
|
||||
outputType: KClass<out R>,
|
||||
outputType: KType,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
transformation: suspend (Flow<NamedData<T>>) -> R,
|
||||
@ -127,7 +128,7 @@ public suspend inline fun <T : Any, reified R : Any> Flow<NamedData<T>>.reduceTo
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
meta: Meta = Meta.EMPTY,
|
||||
noinline transformation: suspend (Flow<NamedData<T>>) -> R,
|
||||
): LazyData<R> = reduceToData(R::class, coroutineContext, meta) {
|
||||
): LazyData<R> = reduceToData(typeOf<R>(), coroutineContext, meta) {
|
||||
transformation(it)
|
||||
}
|
||||
|
||||
@ -148,11 +149,11 @@ public suspend inline fun <T : Any, reified R : Any> Flow<NamedData<T>>.foldToDa
|
||||
//DataSet operations
|
||||
|
||||
public suspend fun <T : Any, R : Any> DataSet<T>.map(
|
||||
outputType: KClass<out R>,
|
||||
outputType: KType,
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
metaTransform: MetaBuilder.() -> Unit = {},
|
||||
block: suspend (T) -> R,
|
||||
): DataTree<R> = DataTree(outputType) {
|
||||
): DataTree<R> = DataTree<R>(outputType) {
|
||||
populate(
|
||||
flow().map {
|
||||
val newMeta = it.meta.toMutableMeta().apply(metaTransform).seal()
|
||||
@ -165,7 +166,7 @@ public suspend inline fun <T : Any, reified R : Any> DataSet<T>.map(
|
||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||
noinline metaTransform: MetaBuilder.() -> Unit = {},
|
||||
noinline block: suspend (T) -> R,
|
||||
): DataTree<R> = map(R::class, coroutineContext, metaTransform, block)
|
||||
): DataTree<R> = map(typeOf<R>(), coroutineContext, metaTransform, block)
|
||||
|
||||
public suspend fun <T : Any> DataSet<T>.forEach(block: suspend (NamedData<T>) -> Unit) {
|
||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
||||
|
@ -1,42 +0,0 @@
|
||||
package hep.dataforge.data
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
/**
|
||||
* Check if data could be safely cast to given class
|
||||
*/
|
||||
internal fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean = this.type.isSubclassOf(type)
|
||||
|
||||
/**
|
||||
* Cast the node to given type if the cast is possible or return null
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <R : Any> Data<*>.castOrNull(type: KClass<out R>): Data<R>? =
|
||||
if (!canCast(type)) null else object : Data<R> by (this as Data<R>) {
|
||||
override val type: KClass<out R> = type
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe cast of data node
|
||||
*/
|
||||
public fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> =
|
||||
castOrNull(type) ?: error("Can't cast ${this.type} to $type")
|
||||
|
||||
public inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(R::class)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <R : Any> DataSet<*>.castOrNull(type: KClass<out R>): DataSet<R>? =
|
||||
if (!canCast(type)) null else object : DataSet<R> by (this as DataSet<R>) {
|
||||
override val dataType: KClass<out R> = type
|
||||
}
|
||||
|
||||
|
||||
public fun <R : Any> DataSet<*>.cast(type: KClass<out R>): DataSet<R> =
|
||||
castOrNull(type) ?: error("Can't cast ${this.dataType} to $type")
|
||||
|
||||
/**
|
||||
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||
*/
|
||||
internal fun <R : Any> DataSet<*>.canCast(type: KClass<out R>): Boolean =
|
||||
type.isSubclassOf(this.dataType)
|
@ -3,26 +3,69 @@ package hep.dataforge.data
|
||||
import hep.dataforge.actions.NamedData
|
||||
import hep.dataforge.actions.named
|
||||
import hep.dataforge.meta.DFExperimental
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.matches
|
||||
import hep.dataforge.names.toName
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.full.isSubtypeOf
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
|
||||
/**
|
||||
* Check if data could be safely cast to given class
|
||||
*/
|
||||
private fun <R : Any> Data<*>.canCast(type: KType): Boolean = this.type.isSubtypeOf(type)
|
||||
|
||||
/**
|
||||
* Cast the node to given type if the cast is possible or return null
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <R : Any> Data<*>.castOrNull(type: KType): Data<R>? =
|
||||
if (!canCast<R>(type)) null else object : Data<R> by (this as Data<R>) {
|
||||
override val type: KType = type
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe cast of data node
|
||||
*/
|
||||
private fun <R : Any> Data<*>.cast(type: KType): Data<R> =
|
||||
castOrNull(type) ?: error("Can't cast ${this.type} to $type")
|
||||
|
||||
private inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(typeOf<R>())
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <R : Any> DataSet<*>.castOrNull(type: KType): DataSet<R>? =
|
||||
if (!canCast<R>(type)) null else object : DataSet<R> by (this as DataSet<R>) {
|
||||
override val dataType: KType = type
|
||||
}
|
||||
|
||||
|
||||
private fun <R : Any> DataSet<*>.cast(type: KType): DataSet<R> =
|
||||
castOrNull(type) ?: error("Can't cast ${this.dataType} to $type")
|
||||
|
||||
/**
|
||||
* Check that node is compatible with given type meaning that each element could be cast to the type
|
||||
*/
|
||||
private fun <R : Any> DataSet<*>.canCast(type: KType): Boolean =
|
||||
type.isSubtypeOf(this.dataType)
|
||||
|
||||
/**
|
||||
* Select all data matching given type and filters. Does not modify paths
|
||||
*/
|
||||
@OptIn(DFExperimental::class)
|
||||
public fun <R : Any> DataSet<*>.select(
|
||||
type: KClass<out R>,
|
||||
@PublishedApi
|
||||
internal fun <R : Any> DataSet<*>.select(
|
||||
type: KType,
|
||||
namePattern: Name? = null,
|
||||
): ActiveDataSet<R> = object : ActiveDataSet<R> {
|
||||
override val dataType: KClass<out R> = type
|
||||
override val dataType = type
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun flow(): Flow<NamedData<R>> = this@select.flow().filter {
|
||||
it.canCast(type) && (namePattern == null || it.name.matches(namePattern))
|
||||
it.type.isSubtypeOf(type) && (namePattern == null || it.name.matches(namePattern))
|
||||
}.map {
|
||||
it as NamedData<R>
|
||||
}
|
||||
@ -31,7 +74,7 @@ public fun <R : Any> DataSet<*>.select(
|
||||
|
||||
override val updates: Flow<Name> = this@select.updates.filter {
|
||||
val datum = this@select.getData(it)
|
||||
datum?.canCast(type) ?: false
|
||||
datum?.canCast<R>(type) ?: false
|
||||
}
|
||||
|
||||
}
|
||||
@ -40,12 +83,12 @@ public fun <R : Any> DataSet<*>.select(
|
||||
* Select a single datum of the appropriate type
|
||||
*/
|
||||
public inline fun <reified R : Any> DataSet<*>.select(namePattern: Name? = null): DataSet<R> =
|
||||
select(R::class, namePattern)
|
||||
select(typeOf<R>(), namePattern)
|
||||
|
||||
public suspend fun <R : Any> DataSet<*>.selectOne(type: KClass<out R>, name: Name): NamedData<R>? =
|
||||
getData(name)?.castOrNull(type)?.named(name)
|
||||
public suspend fun <R : Any> DataSet<*>.selectOne(type: KType, name: Name): NamedData<R>? =
|
||||
getData(name)?.castOrNull<R>(type)?.named(name)
|
||||
|
||||
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: Name): NamedData<R>? = selectOne(R::class, name)
|
||||
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: Name): NamedData<R>? = selectOne(typeOf<R>(), name)
|
||||
|
||||
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: String): NamedData<R>? =
|
||||
selectOne(R::class, name.toName())
|
||||
selectOne(typeOf<R>(), name.toName())
|
@ -4,8 +4,8 @@ import hep.dataforge.meta.Meta
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.full.cast
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.safeCast
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public fun <T : Any> Column<*>.cast(type: KClass<out T>): Column<T> {
|
||||
@ -22,7 +22,7 @@ public class CastColumn<T : Any>(private val origin: Column<*>, override val typ
|
||||
override val size: Int get() = origin.size
|
||||
|
||||
|
||||
override fun get(index: Int): T? = type.cast(origin[index])
|
||||
override fun get(index: Int): T? = type.safeCast(origin[index])
|
||||
}
|
||||
|
||||
public class ColumnProperty<C: Any, T : C>(public val table: Table<C>, public val type: KClass<T>) : ReadOnlyProperty<Any?, Column<T>> {
|
||||
|
Loading…
Reference in New Issue
Block a user