Merge pull request #49 from mipt-npm/dev
0.1.8-dev-2
This commit is contained in:
commit
90a241ac75
@ -1,12 +1,13 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
val toolsVersion = "0.4.2"
|
val toolsVersion = "0.5.5"
|
||||||
id("scientifik.mpp") version toolsVersion apply false
|
id("scientifik.mpp") version toolsVersion apply false
|
||||||
id("scientifik.jvm") version toolsVersion apply false
|
id("scientifik.jvm") version toolsVersion apply false
|
||||||
id("scientifik.publish") version toolsVersion apply false
|
id("scientifik.publish") version toolsVersion apply false
|
||||||
|
id("org.jetbrains.dokka") version "0.10.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataforgeVersion by extra("0.1.7")
|
val dataforgeVersion by extra("0.1.8-dev-2")
|
||||||
|
|
||||||
val bintrayRepo by extra("dataforge")
|
val bintrayRepo by extra("dataforge")
|
||||||
val githubProject by extra("dataforge-core")
|
val githubProject by extra("dataforge-core")
|
||||||
@ -22,4 +23,5 @@ allprojects {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
apply(plugin = "scientifik.publish")
|
apply(plugin = "scientifik.publish")
|
||||||
|
apply(plugin = "org.jetbrains.dokka")
|
||||||
}
|
}
|
@ -13,19 +13,19 @@ kotlin {
|
|||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-meta"))
|
api(project(":dataforge-meta"))
|
||||||
api(kotlin("reflect"))
|
api("io.github.microutils:kotlin-logging-common:1.7.9")
|
||||||
api("io.github.microutils:kotlin-logging-common:1.7.8")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmMain by getting {
|
val jvmMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("io.github.microutils:kotlin-logging:1.7.8")
|
api(kotlin("reflect"))
|
||||||
|
api("io.github.microutils:kotlin-logging:1.7.9")
|
||||||
api("ch.qos.logback:logback-classic:1.2.3")
|
api("ch.qos.logback:logback-classic:1.2.3")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
api("io.github.microutils:kotlin-logging-js:1.7.8")
|
api("io.github.microutils:kotlin-logging-js:1.7.9")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,11 @@ import hep.dataforge.provider.Provider
|
|||||||
import hep.dataforge.provider.top
|
import hep.dataforge.provider.top
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import mu.KLogger
|
import mu.KLogger
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
|
||||||
import kotlin.jvm.JvmName
|
import kotlin.jvm.JvmName
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,8 +92,11 @@ open class Context(
|
|||||||
config.action()
|
config.action()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext by lazy {
|
||||||
get() = EmptyCoroutineContext
|
(parent ?: Global).coroutineContext.let { parenContext ->
|
||||||
|
parenContext + SupervisorJob(parenContext[Job])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detach all plugins and terminate context
|
* Detach all plugins and terminate context
|
||||||
|
@ -31,7 +31,7 @@ class MapActionBuilder<T, R>(var name: Name, var meta: MetaBuilder, val actionMe
|
|||||||
|
|
||||||
|
|
||||||
class MapAction<T : Any, out R : Any>(
|
class MapAction<T : Any, out R : Any>(
|
||||||
val inputType: KClass<out T>,
|
val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
val outputType: KClass<out R>,
|
||||||
private val block: MapActionBuilder<T, R>.() -> Unit
|
private val block: MapActionBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
@ -72,7 +72,7 @@ class ReduceGroupBuilder<T : Any, R : Any>(val actionMeta: Meta) {
|
|||||||
* The same rules as for KPipe
|
* The same rules as for KPipe
|
||||||
*/
|
*/
|
||||||
class ReduceAction<T : Any, R : Any>(
|
class ReduceAction<T : Any, R : Any>(
|
||||||
val inputType: KClass<out T>,
|
val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
val outputType: KClass<out R>,
|
||||||
private val action: ReduceGroupBuilder<T, R>.() -> Unit
|
private val action: ReduceGroupBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
@ -33,7 +33,7 @@ class SplitBuilder<T : Any, R : Any>(val name: Name, val meta: Meta) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SplitAction<T : Any, R : Any>(
|
class SplitAction<T : Any, R : Any>(
|
||||||
val inputType: KClass<out T>,
|
val inputType: KClass<T>,
|
||||||
val outputType: KClass<out R>,
|
val outputType: KClass<out R>,
|
||||||
private val action: SplitBuilder<T, R>.() -> Unit
|
private val action: SplitBuilder<T, R>.() -> Unit
|
||||||
) : Action<T, R> {
|
) : Action<T, R> {
|
||||||
|
@ -28,7 +28,7 @@ class EnvelopeServer(
|
|||||||
fun start() {
|
fun start() {
|
||||||
if (job == null) {
|
if (job == null) {
|
||||||
logger.info { "Starting envelope server on port $port" }
|
logger.info { "Starting envelope server on port $port" }
|
||||||
val job = scope.launch(Dispatchers.IO) {
|
job = scope.launch(Dispatchers.IO) {
|
||||||
val serverSocket = ServerSocket(port)
|
val serverSocket = ServerSocket(port)
|
||||||
//TODO add handshake and format negotiation
|
//TODO add handshake and format negotiation
|
||||||
while (isActive && !serverSocket.isClosed) {
|
while (isActive && !serverSocket.isClosed) {
|
||||||
|
@ -14,7 +14,7 @@ data class MetaListener(
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface ObservableMeta : Meta {
|
interface ObservableMeta : Meta {
|
||||||
fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
|
||||||
fun removeListener(owner: Any?)
|
fun removeListener(owner: Any?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,13 @@ interface Configurable : Described {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the property to its default value
|
||||||
|
*/
|
||||||
|
fun Configurable.resetProperty(name: Name) {
|
||||||
|
setProperty(name, null)
|
||||||
|
}
|
||||||
|
|
||||||
fun Configurable.getProperty(key: String) = getProperty(key.toName())
|
fun Configurable.getProperty(key: String) = getProperty(key.toName())
|
||||||
|
|
||||||
fun Configurable.setProperty(name: Name, value: Value?) = setProperty(name, value?.let { MetaItem.ValueItem(value) })
|
fun Configurable.setProperty(name: Name, value: Value?) = setProperty(name, value?.let { MetaItem.ValueItem(value) })
|
||||||
@ -64,4 +71,5 @@ fun Configurable.setProperty(key: String, meta: Meta?) = setProperty(key, meta?.
|
|||||||
|
|
||||||
fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
|
fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
|
||||||
|
|
||||||
|
@DFBuilder
|
||||||
inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }
|
inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }
|
||||||
|
@ -201,8 +201,8 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri
|
|||||||
|
|
||||||
/* Node delegates */
|
/* Node delegates */
|
||||||
|
|
||||||
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> =
|
fun Configurable.config(default: Config? = null, key: Name? = null): ReadWriteProperty<Any?, Config?> =
|
||||||
config.node(key)
|
config.node(default,key)
|
||||||
|
|
||||||
fun Configurable.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).map(
|
fun Configurable.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).map(
|
||||||
reader = { it.node },
|
reader = { it.node },
|
||||||
|
@ -28,7 +28,7 @@ fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Use these methods to customize JSON key mapping
|
//Use these methods to customize JSON key mapping
|
||||||
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.getProperty("jsonName").string ?: toString()
|
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes["jsonName"].string ?: toString()
|
||||||
|
|
||||||
//private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)
|
//private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
|
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
|
||||||
val itemDescriptor = descriptor?.items?.get(key)
|
val itemDescriptor = descriptor?.items?.get(key)
|
||||||
return when (value) {
|
when (value) {
|
||||||
is JsonPrimitive -> {
|
is JsonPrimitive -> {
|
||||||
this[key] =
|
this[key] =
|
||||||
MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem<JsonMeta>
|
MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem<JsonMeta>
|
||||||
|
@ -170,8 +170,12 @@ interface MetaNode<out M : MetaNode<M>> : Meta {
|
|||||||
/**
|
/**
|
||||||
* The same as [Meta.get], but with specific node type
|
* The same as [Meta.get], but with specific node type
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) {
|
||||||
operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = (this as Meta)[name] as MetaItem<M>?
|
null
|
||||||
|
} else {
|
||||||
|
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
|
||||||
|
(this as Meta).get(name) as MetaItem<M>? // Do not change
|
||||||
|
}
|
||||||
|
|
||||||
operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
|
operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
|
||||||
|
|
||||||
|
@ -76,11 +76,9 @@ inline fun MutableMeta<*>.remove(name: Name) = set(name, null)
|
|||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
inline fun MutableMeta<*>.remove(name: String) = remove(name.toName())
|
inline fun MutableMeta<*>.remove(name: String) = remove(name.toName())
|
||||||
|
|
||||||
fun MutableMeta<*>.setValue(name: Name, value: Value) =
|
fun MutableMeta<*>.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value))
|
||||||
set(name, MetaItem.ValueItem(value))
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setValue(name: String, value: Value) =
|
fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value)
|
||||||
set(name.toName(), MetaItem.ValueItem(value))
|
|
||||||
|
|
||||||
fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) {
|
fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) {
|
||||||
when (item) {
|
when (item) {
|
||||||
@ -98,7 +96,7 @@ fun MutableMeta<*>.setNode(name: Name, node: Meta) =
|
|||||||
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
|
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Universal set method
|
* Universal unsafe set method
|
||||||
*/
|
*/
|
||||||
operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
||||||
when (value) {
|
when (value) {
|
||||||
@ -174,3 +172,16 @@ fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)
|
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply existing node with given [builder] or create a new element with it.
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
fun <M : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) {
|
||||||
|
val item = when(val existingItem = get(name)){
|
||||||
|
null -> empty().also { set(name, it) }
|
||||||
|
is MetaItem.NodeItem<M> -> existingItem.node
|
||||||
|
else -> error("Can't edit value meta item")
|
||||||
|
}
|
||||||
|
item.apply(builder)
|
||||||
|
}
|
@ -84,8 +84,8 @@ fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: Name? = null):
|
|||||||
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null): ReadWriteProperty<Any?, Number?> =
|
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: Name? = null): ReadWriteProperty<Any?, Number?> =
|
||||||
item(default, key).transform { it.number }
|
item(default, key).transform { it.number }
|
||||||
|
|
||||||
inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null) =
|
inline fun <reified M : MutableMeta<M>> M.node(default: M? = null, key: Name? = null) =
|
||||||
item(this, key).transform { it.node as? M }
|
item(default, key = key).transform { it.node as? M }
|
||||||
|
|
||||||
@JvmName("safeString")
|
@JvmName("safeString")
|
||||||
fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) =
|
fun <M : MutableMeta<M>> M.string(default: String, key: Name? = null) =
|
||||||
@ -99,6 +99,10 @@ fun <M : MutableMeta<M>> M.boolean(default: Boolean, key: Name? = null) =
|
|||||||
fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) =
|
fun <M : MutableMeta<M>> M.number(default: Number, key: Name? = null) =
|
||||||
item(default, key).transform { it.number!! }
|
item(default, key).transform { it.number!! }
|
||||||
|
|
||||||
|
@JvmName("lazyValue")
|
||||||
|
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> Value) =
|
||||||
|
lazyItem(key, default).transform { it.value!! }
|
||||||
|
|
||||||
@JvmName("lazyString")
|
@JvmName("lazyString")
|
||||||
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) =
|
fun <M : MutableMeta<M>> M.string(key: Name? = null, default: () -> String) =
|
||||||
lazyItem(key, default).transform { it.string!! }
|
lazyItem(key, default).transform { it.string!! }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package hep.dataforge.meta.descriptors
|
package hep.dataforge.meta.descriptors
|
||||||
|
|
||||||
|
import hep.dataforge.meta.Laminate
|
||||||
import hep.dataforge.meta.MetaBase
|
import hep.dataforge.meta.MetaBase
|
||||||
import hep.dataforge.meta.MetaItem
|
import hep.dataforge.meta.MetaItem
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
@ -15,8 +16,10 @@ class DescriptorMeta(val descriptor: NodeDescriptor) : MetaBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun NodeDescriptor.buildDefaultMeta() = Laminate(default, DescriptorMeta(this))
|
||||||
|
|
||||||
fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> =
|
fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> =
|
||||||
MetaItem.NodeItem(default ?: DescriptorMeta(this))
|
MetaItem.NodeItem(buildDefaultMeta())
|
||||||
|
|
||||||
fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null)
|
fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null)
|
||||||
|
|
||||||
|
@ -8,28 +8,21 @@ import hep.dataforge.values.Value
|
|||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
|
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
sealed class ItemDescriptor : Scheme() {
|
sealed class ItemDescriptor(val config: Config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if same name siblings with this name are allowed
|
* True if same name siblings with this name are allowed
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var multiple: Boolean by boolean(false)
|
var multiple: Boolean by config.boolean(false)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The item description
|
* The item description
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var info: String? by string()
|
var info: String? by config.string()
|
||||||
|
|
||||||
/**
|
|
||||||
* Additional attributes of an item. For example validation and widget parameters
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
var attributes by config()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the item is required
|
* True if the item is required
|
||||||
@ -37,19 +30,37 @@ sealed class ItemDescriptor : Scheme() {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
abstract var required: Boolean
|
abstract var required: Boolean
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional attributes of an item. For example validation and widget parameters
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
var attributes by config.node()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure attributes of the descriptor
|
* Configure attributes of the descriptor
|
||||||
*/
|
*/
|
||||||
fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
fun ItemDescriptor.attributes(block: Config.() -> Unit) {
|
||||||
(attributes ?: Config().also { this.config = it }).apply(block)
|
(attributes ?: Config().also { this.attributes = it }).apply(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set specific attribute in the descriptor
|
||||||
|
*/
|
||||||
|
fun ItemDescriptor.setAttribute(name: Name, value: Any?) {
|
||||||
|
attributes {
|
||||||
|
set(name, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if given item suits the descriptor
|
* Check if given item suits the descriptor
|
||||||
*/
|
*/
|
||||||
fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
||||||
|
if (item == null) return !required
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ValueDescriptor -> isAllowedValue(item.value ?: return false)
|
is ValueDescriptor -> isAllowedValue(item.value ?: return false)
|
||||||
is NodeDescriptor -> items.all { (key, d) ->
|
is NodeDescriptor -> items.all { (key, d) ->
|
||||||
@ -65,28 +76,32 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean {
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class NodeDescriptor private constructor() : ItemDescriptor() {
|
class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||||
|
init {
|
||||||
|
config[IS_NODE_KEY] = true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the node is required
|
* True if the node is required
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
override var required: Boolean by boolean { default == null }
|
override var required: Boolean by config.boolean { default == null }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default for this node. Null if there is no default.
|
* The default for this node. Null if there is no default.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var default by node()
|
var default by config.node()
|
||||||
|
|
||||||
val items: Map<String, ItemDescriptor>
|
val items: Map<String, ItemDescriptor>
|
||||||
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) ->
|
||||||
val node = item.node ?: error("Node descriptor must be a node")
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
if (node[IS_NODE_KEY].boolean == true) {
|
if (node[IS_NODE_KEY].boolean == true) {
|
||||||
NodeDescriptor.wrap(node)
|
NodeDescriptor(node)
|
||||||
} else {
|
} else {
|
||||||
ValueDescriptor.wrap(node)
|
ValueDescriptor(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +114,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
|
|||||||
it.value.node[IS_NODE_KEY].boolean == true
|
it.value.node[IS_NODE_KEY].boolean == true
|
||||||
}.associate { (name, item) ->
|
}.associate { (name, item) ->
|
||||||
val node = item.node ?: error("Node descriptor must be a node")
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
name to NodeDescriptor.wrap(node)
|
name to NodeDescriptor(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -110,7 +125,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
|
|||||||
it.value.node[IS_NODE_KEY].boolean != true
|
it.value.node[IS_NODE_KEY].boolean != true
|
||||||
}.associate { (name, item) ->
|
}.associate { (name, item) ->
|
||||||
val node = item.node ?: error("Node descriptor must be a node")
|
val node = item.node ?: error("Node descriptor must be a node")
|
||||||
name to ValueDescriptor.wrap(node)
|
name to ValueDescriptor(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildNode(name: Name): NodeDescriptor {
|
private fun buildNode(name: Name): NodeDescriptor {
|
||||||
@ -122,7 +137,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
|
|||||||
it[IS_NODE_KEY] = true
|
it[IS_NODE_KEY] = true
|
||||||
config[token] = it
|
config[token] = it
|
||||||
}
|
}
|
||||||
wrap(config)
|
NodeDescriptor(config)
|
||||||
}
|
}
|
||||||
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
|
else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst())
|
||||||
}
|
}
|
||||||
@ -137,41 +152,37 @@ class NodeDescriptor private constructor() : ItemDescriptor() {
|
|||||||
config[token] = descriptor.config
|
config[token] = descriptor.config
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineItem(name: Name, descriptor: ItemDescriptor) {
|
fun item(name: Name, descriptor: ItemDescriptor) {
|
||||||
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
|
buildNode(name.cutLast()).newItem(name.last().toString(), descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineItem(name: String, descriptor: ItemDescriptor) {
|
fun item(name: String, descriptor: ItemDescriptor) {
|
||||||
defineItem(name.toName(), descriptor)
|
item(name.toName(), descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) {
|
fun node(name: Name, block: NodeDescriptor.() -> Unit) {
|
||||||
defineItem(name, NodeDescriptor(block))
|
item(name, NodeDescriptor().apply(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineNode(name: String, block: NodeDescriptor.() -> Unit) {
|
fun node(name: String, block: NodeDescriptor.() -> Unit) {
|
||||||
defineNode(name.toName(), block)
|
node(name.toName(), block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineValue(name: Name, block: ValueDescriptor.() -> Unit) {
|
fun value(name: Name, block: ValueDescriptor.() -> Unit) {
|
||||||
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
|
||||||
defineItem(name, ValueDescriptor(block))
|
item(name, ValueDescriptor().apply(block))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun defineValue(name: String, block: ValueDescriptor.() -> Unit) {
|
fun value(name: String, block: ValueDescriptor.() -> Unit) {
|
||||||
defineValue(name.toName(), block)
|
value(name.toName(), block)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object : SchemeSpec<NodeDescriptor>(::NodeDescriptor) {
|
companion object {
|
||||||
|
|
||||||
val ITEM_KEY = "item".asName()
|
val ITEM_KEY = "item".asName()
|
||||||
val IS_NODE_KEY = "@isNode".asName()
|
val IS_NODE_KEY = "@isNode".asName()
|
||||||
|
|
||||||
override fun empty(): NodeDescriptor {
|
inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block)
|
||||||
return super.empty().apply {
|
|
||||||
config[IS_NODE_KEY] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO infer descriptor from spec
|
//TODO infer descriptor from spec
|
||||||
}
|
}
|
||||||
@ -188,6 +199,8 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A descriptor for meta value
|
* A descriptor for meta value
|
||||||
*
|
*
|
||||||
@ -196,21 +209,21 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
|
|||||||
* @author Alexander Nozik
|
* @author Alexander Nozik
|
||||||
*/
|
*/
|
||||||
@DFBuilder
|
@DFBuilder
|
||||||
class ValueDescriptor : ItemDescriptor() {
|
class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the value is required
|
* True if the value is required
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
override var required: Boolean by boolean { default == null }
|
override var required: Boolean by config.boolean { default == null }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default for this value. Null if there is no default.
|
* The default for this value. Null if there is no default.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var default: Value? by value()
|
var default: Value? by config.value()
|
||||||
|
|
||||||
fun default(v: Any) {
|
fun default(v: Any) {
|
||||||
this.default = Value.of(v)
|
this.default = Value.of(v)
|
||||||
@ -221,7 +234,7 @@ class ValueDescriptor : ItemDescriptor() {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var type: List<ValueType> by item {
|
var type: List<ValueType> by config.item().transform {
|
||||||
it?.value?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList()
|
it?.value?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,11 +261,11 @@ class ValueDescriptor : ItemDescriptor() {
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
var allowedValues: List<Value> by value {
|
var allowedValues: List<Value> by config.value().transform {
|
||||||
it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) {
|
when {
|
||||||
listOf(True, False)
|
it?.list != null -> it.list
|
||||||
} else {
|
type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False)
|
||||||
emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,6 +275,14 @@ class ValueDescriptor : ItemDescriptor() {
|
|||||||
fun allow(vararg v: Any) {
|
fun allow(vararg v: Any) {
|
||||||
this.allowedValues = v.map { Value.of(it) }
|
this.allowedValues = v.map { Value.of(it) }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
companion object : SchemeSpec<ValueDescriptor>(::ValueDescriptor)
|
|
||||||
|
/**
|
||||||
|
* Merge two node descriptors into one using first one as primary
|
||||||
|
*/
|
||||||
|
operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
|
||||||
|
return NodeDescriptor().apply {
|
||||||
|
config.update(other.config)
|
||||||
|
config.update(this@plus.config)
|
||||||
|
}
|
||||||
}
|
}
|
@ -125,7 +125,7 @@ object False : Value {
|
|||||||
override val number: Number get() = -1.0
|
override val number: Number get() = -1.0
|
||||||
override val string: String get() = "false"
|
override val string: String get() = "false"
|
||||||
|
|
||||||
override fun toString(): String = True.value.toString()
|
override fun toString(): String = value.toString()
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean = other === False
|
override fun equals(other: Any?): Boolean = other === False
|
||||||
override fun hashCode(): Int = -1
|
override fun hashCode(): Int = -1
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
package hep.dataforge.meta.descriptors
|
package hep.dataforge.meta.descriptors
|
||||||
|
|
||||||
|
import hep.dataforge.meta.boolean
|
||||||
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.values.ValueType
|
import hep.dataforge.values.ValueType
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
class DescriptorTest {
|
class DescriptorTest {
|
||||||
|
|
||||||
val descriptor = NodeDescriptor {
|
val descriptor = NodeDescriptor {
|
||||||
defineNode("aNode") {
|
node("aNode") {
|
||||||
info = "A root demo node"
|
info = "A root demo node"
|
||||||
defineValue("b") {
|
value("b") {
|
||||||
info = "b number value"
|
info = "b number value"
|
||||||
type(ValueType.NUMBER)
|
type(ValueType.NUMBER)
|
||||||
}
|
}
|
||||||
defineNode("otherNode") {
|
node("otherNode") {
|
||||||
defineValue("otherValue") {
|
value("otherValue") {
|
||||||
type(ValueType.BOOLEAN)
|
type(ValueType.BOOLEAN)
|
||||||
default(false)
|
default(false)
|
||||||
info = "default value"
|
info = "default value"
|
||||||
@ -25,7 +28,15 @@ class DescriptorTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testAllowedValues() {
|
fun testAllowedValues() {
|
||||||
|
val child = descriptor["aNode.b"]
|
||||||
|
assertNotNull(child)
|
||||||
val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues
|
val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues
|
||||||
assertEquals(emptyList(), allowed)
|
assertEquals(emptyList(), allowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDefaultMetaNode(){
|
||||||
|
val meta = descriptor.buildDefaultMeta()
|
||||||
|
assertEquals(false, meta["aNode.otherNode.otherValue"].boolean)
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,9 +2,9 @@ package hep.dataforge.workspace
|
|||||||
|
|
||||||
import hep.dataforge.context.Context
|
import hep.dataforge.context.Context
|
||||||
import hep.dataforge.data.*
|
import hep.dataforge.data.*
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.meta.DFBuilder
|
import hep.dataforge.meta.DFBuilder
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.Meta
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
import hep.dataforge.meta.get
|
import hep.dataforge.meta.get
|
||||||
import hep.dataforge.meta.string
|
import hep.dataforge.meta.string
|
||||||
import hep.dataforge.names.Name
|
import hep.dataforge.names.Name
|
||||||
@ -16,7 +16,8 @@ import kotlin.reflect.KClass
|
|||||||
@DFBuilder
|
@DFBuilder
|
||||||
class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
||||||
private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { allData() }
|
private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { allData() }
|
||||||
// private val additionalDependencies = HashSet<Dependency>()
|
|
||||||
|
// private val additionalDependencies = HashSet<Dependency>()
|
||||||
var descriptor: NodeDescriptor? = null
|
var descriptor: NodeDescriptor? = null
|
||||||
private val dataTransforms: MutableList<DataTransformation> = ArrayList()
|
private val dataTransforms: MutableList<DataTransformation> = ArrayList()
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TaskEnv(val name: Name, val meta: Meta, val context: Context, val data: DataNode<Any>) {
|
class TaskEnv(val name: Name, val meta: Meta, val context: Context, val data: DataNode<Any>) {
|
||||||
operator fun <T : Any> DirectTaskDependency<T>.invoke(): DataNode<T> = if(placement.isEmpty()){
|
operator fun <T : Any> DirectTaskDependency<T>.invoke(): DataNode<T> = if (placement.isEmpty()) {
|
||||||
data.cast(task.type)
|
data.cast(task.type)
|
||||||
} else {
|
} else {
|
||||||
data[placement].node?.cast(task.type)
|
data[placement].node?.cast(task.type)
|
||||||
@ -113,10 +114,13 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
crossinline block: MapActionBuilder<T, R>.(TaskEnv) -> Unit
|
crossinline block: MapActionBuilder<T, R>.(TaskEnv) -> Unit
|
||||||
) {
|
) {
|
||||||
action(from, to) {
|
action(from, to) {
|
||||||
|
val env = this
|
||||||
MapAction(
|
MapAction(
|
||||||
inputType = T::class,
|
inputType = T::class,
|
||||||
outputType = type
|
outputType = type
|
||||||
) { block(this@action) }
|
) {
|
||||||
|
block(env)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,10 +154,11 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
crossinline block: ReduceGroupBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
|
crossinline block: ReduceGroupBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
|
||||||
) {
|
) {
|
||||||
action(from, to) {
|
action(from, to) {
|
||||||
|
val env = this
|
||||||
ReduceAction(
|
ReduceAction(
|
||||||
inputType = T::class,
|
inputType = T::class,
|
||||||
outputType = type
|
outputType = type
|
||||||
) { block(this@action) }
|
) { block(env) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,10 +194,11 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
crossinline block: SplitBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
|
crossinline block: SplitBuilder<T, R>.(TaskEnv) -> Unit //TODO needs KEEP-176
|
||||||
) {
|
) {
|
||||||
action(from, to) {
|
action(from, to) {
|
||||||
|
val env = this
|
||||||
SplitAction(
|
SplitAction(
|
||||||
inputType = T::class,
|
inputType = T::class,
|
||||||
outputType = type
|
outputType = type
|
||||||
) { block(this@action) }
|
) { block(env) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +206,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
* Use DSL to create a descriptor for this task
|
* Use DSL to create a descriptor for this task
|
||||||
*/
|
*/
|
||||||
fun description(transform: NodeDescriptor.() -> Unit) {
|
fun description(transform: NodeDescriptor.() -> Unit) {
|
||||||
this.descriptor = NodeDescriptor(transform)
|
this.descriptor = NodeDescriptor().apply(transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun build(): GenericTask<R> {
|
internal fun build(): GenericTask<R> {
|
||||||
@ -212,7 +218,7 @@ class TaskBuilder<R : Any>(val name: Name, val type: KClass<out R>) {
|
|||||||
return GenericTask(
|
return GenericTask(
|
||||||
name,
|
name,
|
||||||
type,
|
type,
|
||||||
descriptor ?: NodeDescriptor.empty(),
|
descriptor ?: NodeDescriptor(),
|
||||||
modelTransform
|
modelTransform
|
||||||
) {
|
) {
|
||||||
val workspace = this
|
val workspace = this
|
||||||
|
Loading…
Reference in New Issue
Block a user