[WIP] change KClass to KType
This commit is contained in:
parent
6a0bfae931
commit
fcd99b1ca8
@ -12,10 +12,6 @@ kotlin {
|
|||||||
commonMain{
|
commonMain{
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-meta"))
|
api(project(":dataforge-meta"))
|
||||||
}
|
|
||||||
}
|
|
||||||
jvmMain{
|
|
||||||
dependencies{
|
|
||||||
api(kotlin("reflect"))
|
api(kotlin("reflect"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
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
|
* 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>(
|
@PublishedApi
|
||||||
public val outputType: KClass<out R>,
|
internal class MapAction<in T : Any, out R : Any>(
|
||||||
|
private val outputType: KType,
|
||||||
private val block: MapActionBuilder<T, R>.() -> Unit,
|
private val block: MapActionBuilder<T, R>.() -> Unit,
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
@ -84,8 +86,8 @@ public class MapAction<in T : Any, out R : Any>(
|
|||||||
|
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@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,
|
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.flow
|
||||||
import kotlinx.coroutines.flow.fold
|
import kotlinx.coroutines.flow.fold
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
|
|
||||||
@DFExperimental
|
@DFExperimental
|
||||||
@ -75,7 +76,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
|
|||||||
@DFExperimental
|
@DFExperimental
|
||||||
public class ReduceAction<T : Any, R : Any>(
|
public class ReduceAction<T : Any, R : Any>(
|
||||||
private val inputType: KClass<out T>,
|
private val inputType: KClass<out T>,
|
||||||
outputType: KClass<out R>,
|
outputType: KType,
|
||||||
private val action: ReduceGroupBuilder<T, R>.() -> Unit,
|
private val action: ReduceGroupBuilder<T, R>.() -> Unit,
|
||||||
) : CachingAction<T, R>(outputType) {
|
) : CachingAction<T, R>(outputType) {
|
||||||
//TODO optimize reduction. Currently the whole action recalculates on push
|
//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.flow.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.collections.set
|
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) {
|
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
|
* Action that splits each incoming element into a number of fragments defined in builder
|
||||||
*/
|
*/
|
||||||
public class SplitAction<T : Any, R : Any>(
|
internal class SplitAction<T : Any, R : Any>(
|
||||||
private val outputType: KClass<out R>,
|
private val outputType: KType,
|
||||||
private val action: SplitBuilder<T, R>.() -> Unit,
|
private val action: SplitBuilder<T, R>.() -> Unit,
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
@ -59,11 +59,11 @@ public class SplitAction<T : Any, R : Any>(
|
|||||||
// apply individual fragment rules to result
|
// apply individual fragment rules to result
|
||||||
return split.fragments.entries.asFlow().map { (fragmentName, rule) ->
|
return split.fragments.entries.asFlow().map { (fragmentName, rule) ->
|
||||||
val env = SplitBuilder.FragmentRule<T, R>(fragmentName, laminate.toMutableMeta()).apply(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))
|
populate(dataSet.flow().flatMapConcat(transform = ::splitOne))
|
||||||
scope?.launch {
|
scope?.launch {
|
||||||
dataSet.updates.collect { name ->
|
dataSet.updates.collect { name ->
|
||||||
|
@ -8,13 +8,14 @@ import kotlinx.coroutines.flow.*
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mutable [DataTree.Companion.active]. It
|
* A mutable [DataTree.Companion.active]. It
|
||||||
*/
|
*/
|
||||||
public class ActiveDataTree<T : Any>(
|
public class ActiveDataTree<T : Any>(
|
||||||
override val dataType: KClass<out T>,
|
override val dataType: KType,
|
||||||
) : DataTree<T>, DataSetBuilder<T>, ActiveDataSet<T> {
|
) : DataTree<T>, DataSetBuilder<T>, ActiveDataSet<T> {
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
private val treeItems = HashMap<NameToken, DataTreeItem<T>>()
|
private val treeItems = HashMap<NameToken, DataTreeItem<T>>()
|
||||||
@ -49,7 +50,7 @@ public class ActiveDataTree<T : Any>(
|
|||||||
|
|
||||||
private suspend fun getOrCreateNode(token: NameToken): ActiveDataTree<T> =
|
private suspend fun getOrCreateNode(token: NameToken): ActiveDataTree<T> =
|
||||||
(treeItems[token] as? DataTreeItem.Node<T>)?.tree as? ActiveDataTree<T>
|
(treeItems[token] as? DataTreeItem.Node<T>)?.tree as? ActiveDataTree<T>
|
||||||
?: ActiveDataTree(dataType).also {
|
?: ActiveDataTree<T>(dataType).also {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
treeItems[token] = DataTreeItem.Node(it)
|
treeItems[token] = DataTreeItem.Node(it)
|
||||||
}
|
}
|
||||||
@ -92,10 +93,10 @@ public class ActiveDataTree<T : Any>(
|
|||||||
*/
|
*/
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
public suspend fun <T : Any> ActiveDataTree(
|
public suspend fun <T : Any> ActiveDataTree(
|
||||||
type: KClass<out T>,
|
type: KType,
|
||||||
block: suspend ActiveDataTree<T>.() -> Unit,
|
block: suspend ActiveDataTree<T>.() -> Unit,
|
||||||
): ActiveDataTree<T> {
|
): ActiveDataTree<T> {
|
||||||
val tree = ActiveDataTree(type)
|
val tree = ActiveDataTree<T>(type)
|
||||||
tree.block()
|
tree.block()
|
||||||
return tree
|
return tree
|
||||||
}
|
}
|
||||||
@ -103,15 +104,15 @@ public suspend fun <T : Any> ActiveDataTree(
|
|||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
public suspend inline fun <reified T : Any> ActiveDataTree(
|
public suspend inline fun <reified T : Any> ActiveDataTree(
|
||||||
crossinline block: suspend ActiveDataTree<T>.() -> Unit,
|
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(
|
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
|
||||||
name: Name,
|
name: Name,
|
||||||
noinline block: suspend ActiveDataTree<T>.() -> Unit,
|
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(
|
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
|
||||||
name: String,
|
name: String,
|
||||||
noinline block: suspend ActiveDataTree<T>.() -> Unit,
|
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.coroutineScope
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all values with keys starting with [name]
|
* 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
|
* An action that caches results on-demand and recalculates them on source push
|
||||||
*/
|
*/
|
||||||
public abstract class CachingAction<in T : Any, out R : Any>(
|
public abstract class CachingAction<in T : Any, out R : Any>(
|
||||||
public val outputType: KClass<out R>,
|
public val outputType: KType,
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
|
||||||
protected abstract fun CoroutineScope.transform(
|
protected abstract fun CoroutineScope.transform(
|
||||||
@ -36,7 +36,7 @@ public abstract class CachingAction<in T : Any, out R : Any>(
|
|||||||
dataSet: DataSet<T>,
|
dataSet: DataSet<T>,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
scope: CoroutineScope?,
|
scope: CoroutineScope?,
|
||||||
): DataSet<R> = ActiveDataTree(outputType) {
|
): DataSet<R> = ActiveDataTree<R>(outputType) {
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
populate(transform(dataSet, meta))
|
populate(transform(dataSet, meta))
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import hep.dataforge.misc.Type
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A data element characterized by its meta
|
* 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.
|
* 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
|
* Meta for the data
|
||||||
@ -25,7 +26,7 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
|||||||
public val meta: Meta
|
public val meta: Meta
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta {
|
override fun toMeta(): Meta = Meta {
|
||||||
"type" put (type.simpleName ?: "undefined")
|
"type" put (type.toString())
|
||||||
if (!meta.isEmpty()) {
|
if (!meta.isEmpty()) {
|
||||||
"meta" put meta
|
"meta" put meta
|
||||||
}
|
}
|
||||||
@ -34,16 +35,17 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
|||||||
public companion object {
|
public companion object {
|
||||||
public const val TYPE: String = "data"
|
public const val TYPE: String = "data"
|
||||||
|
|
||||||
public fun <T : Any> static(
|
public inline fun <reified T : Any> static(
|
||||||
value: T,
|
value: T,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
): Data<T> = StaticData(value, meta)
|
): Data<T> = StaticData(typeOf<T>(),value, meta)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An empty data containing only meta
|
* An empty data containing only meta
|
||||||
*/
|
*/
|
||||||
public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
|
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 meta: Meta = meta
|
||||||
override val dependencies: Collection<Goal<*>> = emptyList()
|
override val dependencies: Collection<Goal<*>> = emptyList()
|
||||||
override val deferred: Deferred<Nothing>
|
override val deferred: Deferred<Nothing>
|
||||||
@ -58,7 +60,7 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class LazyData<T : Any>(
|
public class LazyData<T : Any>(
|
||||||
override val type: KClass<out T>,
|
override val type: KType,
|
||||||
override val meta: Meta = Meta.EMPTY,
|
override val meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
dependencies: Collection<Data<*>> = emptyList(),
|
dependencies: Collection<Data<*>> = emptyList(),
|
||||||
@ -66,15 +68,14 @@ public class LazyData<T : Any>(
|
|||||||
) : Data<T>, LazyGoal<T>(context, dependencies, block)
|
) : Data<T>, LazyGoal<T>(context, dependencies, block)
|
||||||
|
|
||||||
public class StaticData<T : Any>(
|
public class StaticData<T : Any>(
|
||||||
|
override val type: KType,
|
||||||
value: T,
|
value: T,
|
||||||
override val meta: Meta = Meta.EMPTY,
|
override val meta: Meta = Meta.EMPTY,
|
||||||
) : Data<T>, StaticGoal<T>(value) {
|
) : Data<T>, StaticGoal<T>(value)
|
||||||
override val type: KClass<out T> get() = value::class
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
public fun <T : Any> Data(
|
public fun <T : Any> Data(
|
||||||
type: KClass<out T>,
|
type: KType,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
dependencies: Collection<Data<*>> = emptyList(),
|
dependencies: Collection<Data<*>> = emptyList(),
|
||||||
@ -87,4 +88,4 @@ public inline fun <reified T : Any> Data(
|
|||||||
context: CoroutineContext = EmptyCoroutineContext,
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
dependencies: Collection<Data<*>> = emptyList(),
|
dependencies: Collection<Data<*>> = emptyList(),
|
||||||
noinline block: suspend () -> T,
|
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 hep.dataforge.names.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
public interface DataSet<out T : Any> {
|
public interface DataSet<out T : Any> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimal common ancestor to all data in the node
|
* 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.
|
* 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
|
* An empty [DataSet] that suits all types
|
||||||
*/
|
*/
|
||||||
public val EMPTY: DataSet<Nothing> = object : DataSet<Nothing> {
|
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()
|
override fun flow(): Flow<NamedData<Nothing>> = emptyFlow()
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ public suspend fun DataSet<*>.toMeta(): Meta = Meta {
|
|||||||
set(it.name, it.meta)
|
set(it.name, it.meta)
|
||||||
} else {
|
} else {
|
||||||
it.name put {
|
it.name put {
|
||||||
"type" put it.type.simpleName
|
"type" put it.type.toString()
|
||||||
"meta" put it.meta
|
"meta" put it.meta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,12 @@ package hep.dataforge.data
|
|||||||
import hep.dataforge.names.*
|
import hep.dataforge.names.*
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal class StaticDataTree<T : Any>(
|
internal class StaticDataTree<T : Any>(
|
||||||
override val dataType: KClass<out T>,
|
override val dataType: KType,
|
||||||
) : DataSetBuilder<T>, DataTree<T> {
|
) : DataSetBuilder<T>, DataTree<T> {
|
||||||
|
|
||||||
private val items: MutableMap<NameToken, DataTreeItem<T>> = HashMap()
|
private val items: MutableMap<NameToken, DataTreeItem<T>> = HashMap()
|
||||||
@ -26,7 +27,7 @@ internal class StaticDataTree<T : Any>(
|
|||||||
0 -> this
|
0 -> this
|
||||||
1 -> {
|
1 -> {
|
||||||
val itemName = name.firstOrNull()!!
|
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)
|
items[itemName] = DataTreeItem.Node(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,14 +62,14 @@ internal class StaticDataTree<T : Any>(
|
|||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
public suspend fun <T : Any> DataTree(
|
public suspend fun <T : Any> DataTree(
|
||||||
dataType: KClass<out T>,
|
dataType: KType,
|
||||||
block: suspend DataSetBuilder<T>.() -> Unit,
|
block: suspend DataSetBuilder<T>.() -> Unit,
|
||||||
): DataTree<T> = StaticDataTree(dataType).apply { block() }
|
): DataTree<T> = StaticDataTree<T>(dataType).apply { block() }
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
public suspend inline fun <reified T : Any> DataTree(
|
public suspend inline fun <reified T : Any> DataTree(
|
||||||
noinline block: suspend DataSetBuilder<T>.() -> Unit,
|
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){
|
public suspend fun <T : Any> DataSet<T>.seal(): DataTree<T> = DataTree(dataType){
|
||||||
populate(this@seal)
|
populate(this@seal)
|
||||||
|
@ -11,7 +11,8 @@ import kotlin.contracts.InvocationKind
|
|||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
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).
|
* 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 meta for the resulting data. By default equals input data.
|
||||||
* @param block the transformation itself
|
* @param block the transformation itself
|
||||||
*/
|
*/
|
||||||
public fun <T : Any, R : Any> Data<T>.map(
|
private fun <T : Any, R : Any> Data<T>.map(
|
||||||
outputType: KClass<out R>,
|
outputType: KType,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = this.meta,
|
meta: Meta = this.meta,
|
||||||
block: suspend (T) -> R,
|
block: suspend (T) -> R,
|
||||||
@ -35,7 +36,7 @@ public inline fun <T : Any, reified R : Any> Data<T>.map(
|
|||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = this.meta,
|
meta: Meta = this.meta,
|
||||||
crossinline block: suspend (T) -> R,
|
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())
|
block(await())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ public inline fun <T1 : Any, T2 : Any, reified R : Any> Data<T1>.combine(
|
|||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = this.meta,
|
meta: Meta = this.meta,
|
||||||
crossinline block: suspend (left: T1, right: T2) -> R,
|
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())
|
block(await(), other.await())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduceToData(
|
|||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
crossinline block: suspend (Collection<T>) -> R,
|
crossinline block: suspend (Collection<T>) -> R,
|
||||||
): LazyData<R> = LazyData(
|
): LazyData<R> = LazyData(
|
||||||
R::class,
|
typeOf<R>(),
|
||||||
meta,
|
meta,
|
||||||
coroutineContext,
|
coroutineContext,
|
||||||
this
|
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(
|
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduceToData(
|
||||||
outputType: KClass<out R>,
|
outputType: KType,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
block: suspend (Map<K, T>) -> R,
|
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,
|
meta: Meta = Meta.EMPTY,
|
||||||
noinline block: suspend (Map<K, T>) -> R,
|
noinline block: suspend (Map<K, T>) -> R,
|
||||||
): LazyData<R> = LazyData(
|
): LazyData<R> = LazyData(
|
||||||
R::class,
|
typeOf<R>(),
|
||||||
meta,
|
meta,
|
||||||
coroutineContext,
|
coroutineContext,
|
||||||
this.values
|
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].
|
* Transform a [Flow] of [NamedData] to a single [Data].
|
||||||
*/
|
*/
|
||||||
public suspend fun <T : Any, R : Any> Flow<NamedData<T>>.reduceToData(
|
public suspend fun <T : Any, R : Any> Flow<NamedData<T>>.reduceToData(
|
||||||
outputType: KClass<out R>,
|
outputType: KType,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
transformation: suspend (Flow<NamedData<T>>) -> R,
|
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,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
meta: Meta = Meta.EMPTY,
|
meta: Meta = Meta.EMPTY,
|
||||||
noinline transformation: suspend (Flow<NamedData<T>>) -> R,
|
noinline transformation: suspend (Flow<NamedData<T>>) -> R,
|
||||||
): LazyData<R> = reduceToData(R::class, coroutineContext, meta) {
|
): LazyData<R> = reduceToData(typeOf<R>(), coroutineContext, meta) {
|
||||||
transformation(it)
|
transformation(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,11 +149,11 @@ public suspend inline fun <T : Any, reified R : Any> Flow<NamedData<T>>.foldToDa
|
|||||||
//DataSet operations
|
//DataSet operations
|
||||||
|
|
||||||
public suspend fun <T : Any, R : Any> DataSet<T>.map(
|
public suspend fun <T : Any, R : Any> DataSet<T>.map(
|
||||||
outputType: KClass<out R>,
|
outputType: KType,
|
||||||
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
metaTransform: MetaBuilder.() -> Unit = {},
|
metaTransform: MetaBuilder.() -> Unit = {},
|
||||||
block: suspend (T) -> R,
|
block: suspend (T) -> R,
|
||||||
): DataTree<R> = DataTree(outputType) {
|
): DataTree<R> = DataTree<R>(outputType) {
|
||||||
populate(
|
populate(
|
||||||
flow().map {
|
flow().map {
|
||||||
val newMeta = it.meta.toMutableMeta().apply(metaTransform).seal()
|
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,
|
coroutineContext: CoroutineContext = EmptyCoroutineContext,
|
||||||
noinline metaTransform: MetaBuilder.() -> Unit = {},
|
noinline metaTransform: MetaBuilder.() -> Unit = {},
|
||||||
noinline block: suspend (T) -> R,
|
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) {
|
public suspend fun <T : Any> DataSet<T>.forEach(block: suspend (NamedData<T>) -> Unit) {
|
||||||
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
|
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.NamedData
|
||||||
import hep.dataforge.actions.named
|
import hep.dataforge.actions.named
|
||||||
import hep.dataforge.meta.DFExperimental
|
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.Flow
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.map
|
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
|
* Select all data matching given type and filters. Does not modify paths
|
||||||
*/
|
*/
|
||||||
@OptIn(DFExperimental::class)
|
@OptIn(DFExperimental::class)
|
||||||
public fun <R : Any> DataSet<*>.select(
|
@PublishedApi
|
||||||
type: KClass<out R>,
|
internal fun <R : Any> DataSet<*>.select(
|
||||||
|
type: KType,
|
||||||
namePattern: Name? = null,
|
namePattern: Name? = null,
|
||||||
): ActiveDataSet<R> = object : ActiveDataSet<R> {
|
): ActiveDataSet<R> = object : ActiveDataSet<R> {
|
||||||
override val dataType: KClass<out R> = type
|
override val dataType = type
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun flow(): Flow<NamedData<R>> = this@select.flow().filter {
|
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 {
|
}.map {
|
||||||
it as NamedData<R>
|
it as NamedData<R>
|
||||||
}
|
}
|
||||||
@ -31,7 +74,7 @@ public fun <R : Any> DataSet<*>.select(
|
|||||||
|
|
||||||
override val updates: Flow<Name> = this@select.updates.filter {
|
override val updates: Flow<Name> = this@select.updates.filter {
|
||||||
val datum = this@select.getData(it)
|
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
|
* Select a single datum of the appropriate type
|
||||||
*/
|
*/
|
||||||
public inline fun <reified R : Any> DataSet<*>.select(namePattern: Name? = null): DataSet<R> =
|
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>? =
|
public suspend fun <R : Any> DataSet<*>.selectOne(type: KType, name: Name): NamedData<R>? =
|
||||||
getData(name)?.castOrNull(type)?.named(name)
|
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>? =
|
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.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.full.cast
|
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
import kotlin.reflect.safeCast
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
public fun <T : Any> Column<*>.cast(type: KClass<out T>): Column<T> {
|
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 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>> {
|
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