From f67fb63c451d97aed46bd39009bc985a8e0b69f0 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 13 Apr 2020 15:23:05 +0300 Subject: [PATCH 1/8] Fix for #48 --- build.gradle.kts | 2 +- .../hep/dataforge/io/tcp/EnvelopeServer.kt | 2 +- .../kotlin/hep/dataforge/meta/JsonMeta.kt | 4 +- .../kotlin/hep/dataforge/meta/Meta.kt | 8 +- .../hep/dataforge/meta/MutableMetaDelegate.kt | 4 + .../meta/descriptors/ItemDescriptor.kt | 82 +++++++++---------- .../meta/descriptors/DescriptorTest.kt | 11 ++- .../hep/dataforge/workspace/TaskBuilder.kt | 6 +- 8 files changed, 65 insertions(+), 54 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d73b0e60..43ea9882 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("scientifik.publish") version toolsVersion apply false } -val dataforgeVersion by extra("0.1.7") +val dataforgeVersion by extra("0.1.8-dev-1") val bintrayRepo by extra("dataforge") val githubProject by extra("dataforge-core") diff --git a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/tcp/EnvelopeServer.kt b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/tcp/EnvelopeServer.kt index fc61ee49..b9569279 100644 --- a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/tcp/EnvelopeServer.kt +++ b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/tcp/EnvelopeServer.kt @@ -28,7 +28,7 @@ class EnvelopeServer( fun start() { if (job == null) { logger.info { "Starting envelope server on port $port" } - val job = scope.launch(Dispatchers.IO) { + job = scope.launch(Dispatchers.IO) { val serverSocket = ServerSocket(port) //TODO add handshake and format negotiation while (isActive && !serverSocket.isClosed) { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt index 89ab1b3e..48ef6c4e 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt @@ -28,7 +28,7 @@ fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement { } //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) @@ -146,7 +146,7 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M @Suppress("UNCHECKED_CAST") private operator fun MutableMap>.set(key: String, value: JsonElement): Unit { val itemDescriptor = descriptor?.items?.get(key) - return when (value) { + when (value) { is JsonPrimitive -> { this[key] = MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt index 9650b04e..3aa5b848 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -170,8 +170,12 @@ interface MetaNode> : Meta { /** * The same as [Meta.get], but with specific node type */ -@Suppress("UNCHECKED_CAST") -operator fun > M?.get(name: Name): MetaItem? = (this as Meta)[name] as MetaItem? +operator fun > M?.get(name: Name): MetaItem? = if( this == null) { + null +} else { + @Suppress("UNCHECKED_CAST") + (this as Meta).get(name) as MetaItem? +} operator fun > M?.get(key: String): MetaItem? = this[key.toName()] diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt index 0cffb3a3..39a022f4 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt @@ -99,6 +99,10 @@ fun > M.boolean(default: Boolean, key: Name? = null) = fun > M.number(default: Number, key: Name? = null) = item(default, key).transform { it.number!! } +@JvmName("lazyValue") +fun > M.string(key: Name? = null, default: () -> Value) = + lazyItem(key, default).transform { it.value!! } + @JvmName("lazyString") fun > M.string(key: Name? = null, default: () -> String) = lazyItem(key, default).transform { it.string!! } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index e025cbb1..02af4374 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -8,28 +8,28 @@ import hep.dataforge.values.Value import hep.dataforge.values.ValueType @DFBuilder -sealed class ItemDescriptor : Scheme() { +sealed class ItemDescriptor(val config: Config) { /** * True if same name siblings with this name are allowed * * @return */ - var multiple: Boolean by boolean(false) + var multiple: Boolean by config.boolean(false) /** * The item description * * @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() + var attributes by config.node() /** * True if the item is required @@ -43,7 +43,7 @@ sealed class ItemDescriptor : Scheme() { * Configure attributes of the descriptor */ fun ItemDescriptor.attributes(block: Config.() -> Unit) { - (attributes ?: Config().also { this.config = it }).apply(block) + (attributes ?: Config().also { this.attributes = it }).apply(block) } /** @@ -65,28 +65,32 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { * @author Alexander Nozik */ @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 * * @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. * * @return */ - var default by node() + var default by config.node() val items: Map get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) -> val node = item.node ?: error("Node descriptor must be a node") if (node[IS_NODE_KEY].boolean == true) { - NodeDescriptor.wrap(node) + NodeDescriptor(node) } else { - ValueDescriptor.wrap(node) + ValueDescriptor(node) } } @@ -99,7 +103,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() { it.value.node[IS_NODE_KEY].boolean == true }.associate { (name, item) -> val node = item.node ?: error("Node descriptor must be a node") - name to NodeDescriptor.wrap(node) + name to NodeDescriptor(node) } /** @@ -110,7 +114,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() { it.value.node[IS_NODE_KEY].boolean != true }.associate { (name, item) -> 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 { @@ -122,7 +126,7 @@ class NodeDescriptor private constructor() : ItemDescriptor() { it[IS_NODE_KEY] = true config[token] = it } - wrap(config) + NodeDescriptor(config) } else -> buildNode(name.first()?.asName()!!).buildNode(name.cutFirst()) } @@ -137,41 +141,37 @@ class NodeDescriptor private constructor() : ItemDescriptor() { config[token] = descriptor.config } - fun defineItem(name: Name, descriptor: ItemDescriptor) { + fun item(name: Name, descriptor: ItemDescriptor) { buildNode(name.cutLast()).newItem(name.last().toString(), descriptor) } - fun defineItem(name: String, descriptor: ItemDescriptor) { - defineItem(name.toName(), descriptor) + fun item(name: String, descriptor: ItemDescriptor) { + item(name.toName(), descriptor) } - fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) { - defineItem(name, NodeDescriptor(block)) + fun node(name: Name, block: NodeDescriptor.() -> Unit) { + item(name, NodeDescriptor().apply(block)) } - fun defineNode(name: String, block: NodeDescriptor.() -> Unit) { - defineNode(name.toName(), block) + fun node(name: String, block: NodeDescriptor.() -> Unit) { + 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" } - defineItem(name, ValueDescriptor(block)) + item(name, ValueDescriptor().apply(block)) } - fun defineValue(name: String, block: ValueDescriptor.() -> Unit) { - defineValue(name.toName(), block) + fun value(name: String, block: ValueDescriptor.() -> Unit) { + value(name.toName(), block) } - companion object : SchemeSpec(::NodeDescriptor) { + companion object{ val ITEM_KEY = "item".asName() val IS_NODE_KEY = "@isNode".asName() - override fun empty(): NodeDescriptor { - return super.empty().apply { - config[IS_NODE_KEY] = true - } - } + inline operator fun invoke(block: NodeDescriptor.()->Unit) = NodeDescriptor().apply(block) //TODO infer descriptor from spec } @@ -188,6 +188,8 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? { } } +operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName()) + /** * A descriptor for meta value * @@ -196,21 +198,21 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? { * @author Alexander Nozik */ @DFBuilder -class ValueDescriptor : ItemDescriptor() { +class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { /** * True if the value is required * * @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. * * @return */ - var default: Value? by value() + var default: Value? by config.value() fun default(v: Any) { this.default = Value.of(v) @@ -221,7 +223,7 @@ class ValueDescriptor : ItemDescriptor() { * * @return */ - var type: List by item { + var type: List by config.item().transform { it?.value?.list?.map { v -> ValueType.valueOf(v.string) } ?: emptyList() } @@ -248,11 +250,11 @@ class ValueDescriptor : ItemDescriptor() { * * @return */ - var allowedValues: List by value { - it?.list ?: if (type.size == 1 && type[0] === ValueType.BOOLEAN) { - listOf(True, False) - } else { - emptyList() + var allowedValues: List by config.value().transform { + when{ + it?.list != null -> it.list + type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False) + else -> emptyList() } } @@ -262,6 +264,4 @@ class ValueDescriptor : ItemDescriptor() { fun allow(vararg v: Any) { this.allowedValues = v.map { Value.of(it) } } - - companion object : SchemeSpec(::ValueDescriptor) } \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt index 77e670c8..9c022637 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt @@ -3,18 +3,19 @@ package hep.dataforge.meta.descriptors import hep.dataforge.values.ValueType import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNotNull class DescriptorTest { val descriptor = NodeDescriptor { - defineNode("aNode") { + node("aNode") { info = "A root demo node" - defineValue("b") { + value("b") { info = "b number value" type(ValueType.NUMBER) } - defineNode("otherNode") { - defineValue("otherValue") { + node("otherNode") { + value("otherValue") { type(ValueType.BOOLEAN) default(false) info = "default value" @@ -25,6 +26,8 @@ class DescriptorTest { @Test fun testAllowedValues() { + val child = descriptor["aNode.b"] + assertNotNull(child) val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues assertEquals(emptyList(), allowed) } diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt index 7f359914..9ce9cf27 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt @@ -2,9 +2,9 @@ package hep.dataforge.workspace import hep.dataforge.context.Context import hep.dataforge.data.* -import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.DFBuilder import hep.dataforge.meta.Meta +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.get import hep.dataforge.meta.string import hep.dataforge.names.Name @@ -200,7 +200,7 @@ class TaskBuilder(val name: Name, val type: KClass) { * Use DSL to create a descriptor for this task */ fun description(transform: NodeDescriptor.() -> Unit) { - this.descriptor = NodeDescriptor(transform) + this.descriptor = NodeDescriptor().apply(transform) } internal fun build(): GenericTask { @@ -212,7 +212,7 @@ class TaskBuilder(val name: Name, val type: KClass) { return GenericTask( name, type, - descriptor ?: NodeDescriptor.empty(), + descriptor ?: NodeDescriptor(), modelTransform ) { val workspace = this From 0434360d46b2e76f8409c24df97dbcf5b34da196 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 13 Apr 2020 15:34:26 +0300 Subject: [PATCH 2/8] Cleanup type variance in Task builder --- .../kotlin/hep/dataforge/data/MapAction.kt | 2 +- .../kotlin/hep/dataforge/data/ReduceAction.kt | 2 +- .../kotlin/hep/dataforge/data/SplitAction.kt | 2 +- .../hep/dataforge/workspace/TaskBuilder.kt | 16 +++++++++++----- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt index 89e887db..61598349 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/MapAction.kt @@ -31,7 +31,7 @@ class MapActionBuilder(var name: Name, var meta: MetaBuilder, val actionMe class MapAction( - val inputType: KClass, + val inputType: KClass, val outputType: KClass, private val block: MapActionBuilder.() -> Unit ) : Action { diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt index 9bb49151..0efb5506 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/ReduceAction.kt @@ -72,7 +72,7 @@ class ReduceGroupBuilder(val actionMeta: Meta) { * The same rules as for KPipe */ class ReduceAction( - val inputType: KClass, + val inputType: KClass, val outputType: KClass, private val action: ReduceGroupBuilder.() -> Unit ) : Action { diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt index a4f82931..dc29394c 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/SplitAction.kt @@ -33,7 +33,7 @@ class SplitBuilder(val name: Name, val meta: Meta) { } class SplitAction( - val inputType: KClass, + val inputType: KClass, val outputType: KClass, private val action: SplitBuilder.() -> Unit ) : Action { diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt index 9ce9cf27..502c669d 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt @@ -16,7 +16,8 @@ import kotlin.reflect.KClass @DFBuilder class TaskBuilder(val name: Name, val type: KClass) { private var modelTransform: TaskModelBuilder.(Meta) -> Unit = { allData() } -// private val additionalDependencies = HashSet() + + // private val additionalDependencies = HashSet() var descriptor: NodeDescriptor? = null private val dataTransforms: MutableList = ArrayList() @@ -96,7 +97,7 @@ class TaskBuilder(val name: Name, val type: KClass) { } class TaskEnv(val name: Name, val meta: Meta, val context: Context, val data: DataNode) { - operator fun DirectTaskDependency.invoke(): DataNode = if(placement.isEmpty()){ + operator fun DirectTaskDependency.invoke(): DataNode = if (placement.isEmpty()) { data.cast(task.type) } else { data[placement].node?.cast(task.type) @@ -113,10 +114,13 @@ class TaskBuilder(val name: Name, val type: KClass) { crossinline block: MapActionBuilder.(TaskEnv) -> Unit ) { action(from, to) { + val env = this MapAction( inputType = T::class, outputType = type - ) { block(this@action) } + ) { + block(env) + } } } @@ -150,10 +154,11 @@ class TaskBuilder(val name: Name, val type: KClass) { crossinline block: ReduceGroupBuilder.(TaskEnv) -> Unit //TODO needs KEEP-176 ) { action(from, to) { + val env = this ReduceAction( inputType = T::class, outputType = type - ) { block(this@action) } + ) { block(env) } } } @@ -189,10 +194,11 @@ class TaskBuilder(val name: Name, val type: KClass) { crossinline block: SplitBuilder.(TaskEnv) -> Unit //TODO needs KEEP-176 ) { action(from, to) { + val env = this SplitAction( inputType = T::class, outputType = type - ) { block(this@action) } + ) { block(env) } } } From 7c68fc6e853966d659525f2f7800f429fe96bb6d Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Mon, 13 Apr 2020 16:10:46 +0300 Subject: [PATCH 3/8] add test to descriptor default --- .../hep/dataforge/meta/descriptors/DescriptorMeta.kt | 5 ++++- .../hep/dataforge/meta/descriptors/DescriptorTest.kt | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt index c0b27925..47c90370 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt @@ -1,5 +1,6 @@ package hep.dataforge.meta.descriptors +import hep.dataforge.meta.Laminate import hep.dataforge.meta.MetaBase import hep.dataforge.meta.MetaItem 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<*> = - MetaItem.NodeItem(default ?: DescriptorMeta(this)) + MetaItem.NodeItem(buildDefaultMeta()) fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null) diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt index 9c022637..605cbebd 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt @@ -1,5 +1,7 @@ package hep.dataforge.meta.descriptors +import hep.dataforge.meta.boolean +import hep.dataforge.meta.get import hep.dataforge.values.ValueType import kotlin.test.Test import kotlin.test.assertEquals @@ -31,4 +33,10 @@ class DescriptorTest { val allowed = descriptor.nodes["aNode"]?.values?.get("b")?.allowedValues assertEquals(emptyList(), allowed) } + + @Test + fun testDefaultMetaNode(){ + val meta = descriptor.buildDefaultMeta() + assertEquals(false, meta["aNode.otherNode.otherValue"].boolean) + } } \ No newline at end of file From fb28c854b3b4bcffd4c9b6cc34fbf4d43b4ead4c Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 17 Apr 2020 18:31:22 +0300 Subject: [PATCH 4/8] Fix structured concurrency in Context --- .../commonMain/kotlin/hep/dataforge/context/Context.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt index b3adcbfd..3db334c2 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -8,10 +8,11 @@ import hep.dataforge.provider.Provider import hep.dataforge.provider.top import hep.dataforge.values.Value import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import mu.KLogger import mu.KotlinLogging import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext import kotlin.jvm.JvmName /** @@ -91,8 +92,9 @@ open class Context( config.action() } - override val coroutineContext: CoroutineContext - get() = EmptyCoroutineContext + override val coroutineContext: CoroutineContext = (parent ?: Global).coroutineContext.let { parenContext -> + parenContext + SupervisorJob(parenContext[Job]) + } /** * Detach all plugins and terminate context From aa52c45c5a33beaf46ad5e22b60cb9978643b3fc Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 19 Apr 2020 23:13:00 +0300 Subject: [PATCH 5/8] Fix boolean value toString() --- .../src/commonMain/kotlin/hep/dataforge/values/Value.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt index 28a5838c..05c082e9 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt @@ -125,7 +125,7 @@ object False : Value { override val number: Number get() = -1.0 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 hashCode(): Int = -1 From 5e8e3014f7e4c3614180635338ac8bb373630126 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 21 Apr 2020 19:32:29 +0300 Subject: [PATCH 6/8] Node editor for MutableMeta --- build.gradle.kts | 2 +- .../kotlin/hep/dataforge/meta/Configurable.kt | 1 + .../kotlin/hep/dataforge/meta/Meta.kt | 4 +-- .../kotlin/hep/dataforge/meta/MutableMeta.kt | 23 +++++++++---- .../meta/descriptors/ItemDescriptor.kt | 33 ++++++++++++------- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 43ea9882..3395cacc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("scientifik.publish") version toolsVersion apply false } -val dataforgeVersion by extra("0.1.8-dev-1") +val dataforgeVersion by extra("0.1.8-dev-2") val bintrayRepo by extra("dataforge") val githubProject by extra("dataforge-core") diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt index b38b7d95..884c1c26 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt @@ -64,4 +64,5 @@ fun Configurable.setProperty(key: String, meta: Meta?) = setProperty(key, meta?. fun T.configure(meta: Meta): T = this.apply { config.update(meta) } +@DFBuilder inline fun T.configure(action: Config.() -> Unit): T = apply { config.apply(action) } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt index 3aa5b848..768ddbfa 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -173,8 +173,8 @@ interface MetaNode> : Meta { operator fun > M?.get(name: Name): MetaItem? = if( this == null) { null } else { - @Suppress("UNCHECKED_CAST") - (this as Meta).get(name) as MetaItem? + @Suppress("UNCHECKED_CAST", "ReplaceGetOrSet") + (this as Meta).get(name) as MetaItem? // Do not change } operator fun > M?.get(key: String): MetaItem? = this[key.toName()] diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt index bb280734..16fcf40d 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -76,11 +76,9 @@ inline fun MutableMeta<*>.remove(name: Name) = set(name, null) @Suppress("NOTHING_TO_INLINE") inline fun MutableMeta<*>.remove(name: String) = remove(name.toName()) -fun MutableMeta<*>.setValue(name: Name, value: Value) = - set(name, MetaItem.ValueItem(value)) +fun MutableMeta<*>.setValue(name: Name, value: Value) = set(name, MetaItem.ValueItem(value)) -fun MutableMeta<*>.setValue(name: String, value: Value) = - set(name.toName(), MetaItem.ValueItem(value)) +fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value) fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) { when (item) { @@ -98,7 +96,7 @@ fun MutableMeta<*>.setNode(name: Name, node: Meta) = 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?) { when (value) { @@ -173,4 +171,17 @@ fun > M.append(name: Name, value: Any?) { } } -fun > M.append(name: String, value: Any?) = append(name.toName(), value) \ No newline at end of file +fun > 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.edit(name: Name, builder: M.() -> Unit) { + val item = when(val existingItem = get(name)){ + null -> empty().also { set(name, it) } + is MetaItem.NodeItem -> existingItem.node + else -> error("Can't edit value meta item") + } + item.apply(builder) +} \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index 02af4374..a551b313 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -24,19 +24,20 @@ sealed class ItemDescriptor(val config: Config) { */ var info: String? by config.string() - /** - * Additional attributes of an item. For example validation and widget parameters - * - * @return - */ - var attributes by config.node() - /** * True if the item is required * * @return */ abstract var required: Boolean + + + /** + * Additional attributes of an item. For example validation and widget parameters + * + * @return + */ + var attributes by config.node() } /** @@ -166,12 +167,12 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { value(name.toName(), block) } - companion object{ + companion object { val ITEM_KEY = "item".asName() val IS_NODE_KEY = "@isNode".asName() - inline operator fun invoke(block: NodeDescriptor.()->Unit) = NodeDescriptor().apply(block) + inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block) //TODO infer descriptor from spec } @@ -251,9 +252,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * @return */ var allowedValues: List by config.value().transform { - when{ + when { it?.list != null -> it.list - type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False) + type.size == 1 && type[0] === ValueType.BOOLEAN -> listOf(True, False) else -> emptyList() } } @@ -264,4 +265,14 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { fun allow(vararg v: Any) { this.allowedValues = v.map { Value.of(it) } } +} + +/** + * 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) + } } \ No newline at end of file From 453a1bc7552ed19a8c5aebfcfbe64ba4d2aeff7a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 22 Apr 2020 13:40:35 +0300 Subject: [PATCH 7/8] Remove reflection from common module --- dataforge-context/build.gradle.kts | 2 +- .../src/commonMain/kotlin/hep/dataforge/context/Context.kt | 6 ++++-- .../src/commonMain/kotlin/hep/dataforge/meta/Config.kt | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dataforge-context/build.gradle.kts b/dataforge-context/build.gradle.kts index dd581254..261933fe 100644 --- a/dataforge-context/build.gradle.kts +++ b/dataforge-context/build.gradle.kts @@ -13,12 +13,12 @@ kotlin { val commonMain by getting { dependencies { api(project(":dataforge-meta")) - api(kotlin("reflect")) api("io.github.microutils:kotlin-logging-common:1.7.8") } } val jvmMain by getting { dependencies { + api(kotlin("reflect")) api("io.github.microutils:kotlin-logging:1.7.8") api("ch.qos.logback:logback-classic:1.2.3") } diff --git a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt index 3db334c2..bf901991 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -92,8 +92,10 @@ open class Context( config.action() } - override val coroutineContext: CoroutineContext = (parent ?: Global).coroutineContext.let { parenContext -> - parenContext + SupervisorJob(parenContext[Job]) + override val coroutineContext: CoroutineContext by lazy { + (parent ?: Global).coroutineContext.let { parenContext -> + parenContext + SupervisorJob(parenContext[Job]) + } } /** diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt index 53a2e184..0ac29d86 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt @@ -14,7 +14,7 @@ data class MetaListener( ) 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?) } From fb559f456201f4af1d54a9156131b0175dd4e395 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 17 May 2020 20:12:44 +0300 Subject: [PATCH 8/8] 0.1.8-dev-2 --- build.gradle.kts | 4 +++- dataforge-context/build.gradle.kts | 6 +++--- .../kotlin/hep/dataforge/meta/Configurable.kt | 7 +++++++ .../kotlin/hep/dataforge/meta/ConfigurableDelegate.kt | 4 ++-- .../kotlin/hep/dataforge/meta/MutableMetaDelegate.kt | 4 ++-- .../hep/dataforge/meta/descriptors/ItemDescriptor.kt | 10 ++++++++++ 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3395cacc..f87fced4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ plugins { - val toolsVersion = "0.4.2" + val toolsVersion = "0.5.5" id("scientifik.mpp") version toolsVersion apply false id("scientifik.jvm") 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.8-dev-2") @@ -22,4 +23,5 @@ allprojects { subprojects { apply(plugin = "scientifik.publish") + apply(plugin = "org.jetbrains.dokka") } \ No newline at end of file diff --git a/dataforge-context/build.gradle.kts b/dataforge-context/build.gradle.kts index 261933fe..3c13042d 100644 --- a/dataforge-context/build.gradle.kts +++ b/dataforge-context/build.gradle.kts @@ -13,19 +13,19 @@ kotlin { val commonMain by getting { dependencies { api(project(":dataforge-meta")) - api("io.github.microutils:kotlin-logging-common:1.7.8") + api("io.github.microutils:kotlin-logging-common:1.7.9") } } val jvmMain by getting { dependencies { api(kotlin("reflect")) - api("io.github.microutils:kotlin-logging:1.7.8") + api("io.github.microutils:kotlin-logging:1.7.9") api("ch.qos.logback:logback-classic:1.2.3") } } val jsMain by getting { dependencies { - api("io.github.microutils:kotlin-logging-js:1.7.8") + api("io.github.microutils:kotlin-logging-js:1.7.9") } } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt index 884c1c26..a078c37f 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt @@ -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.setProperty(name: Name, value: Value?) = setProperty(name, value?.let { MetaItem.ValueItem(value) }) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt index 1999ced4..a94b3667 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt @@ -201,8 +201,8 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri /* Node delegates */ -fun Configurable.config(key: Name? = null): ReadWriteProperty = - config.node(key) +fun Configurable.config(default: Config? = null, key: Name? = null): ReadWriteProperty = + config.node(default,key) fun Configurable.node(key: Name? = null): ReadWriteProperty = item(key).map( reader = { it.node }, diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt index 39a022f4..3230afbe 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMetaDelegate.kt @@ -84,8 +84,8 @@ fun > M.boolean(default: Boolean? = null, key: Name? = null): fun > M.number(default: Number? = null, key: Name? = null): ReadWriteProperty = item(default, key).transform { it.number } -inline fun > M.node(key: Name? = null) = - item(this, key).transform { it.node as? M } +inline fun > M.node(default: M? = null, key: Name? = null) = + item(default, key = key).transform { it.node as? M } @JvmName("safeString") fun > M.string(default: String, key: Name? = null) = diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index a551b313..7f748ff2 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -47,10 +47,20 @@ fun ItemDescriptor.attributes(block: Config.() -> Unit) { (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 */ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { + if (item == null) return !required return when (this) { is ValueDescriptor -> isAllowedValue(item.value ?: return false) is NodeDescriptor -> items.all { (key, d) ->