From efddfa8e91a9cd2862edd17df7150e6e7d6d951a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sat, 27 Jul 2019 17:02:48 +0300 Subject: [PATCH] Meta and io fixes --- build.gradle.kts | 13 ++--- .../kotlin/hep/dataforge/context/Context.kt | 2 +- dataforge-io/build.gradle.kts | 47 ++++--------------- .../kotlin/hep/dataforge/io/FunctionServer.kt | 38 +++++++++++++++ .../kotlin/hep/dataforge/io/MetaFormat.kt | 15 ++++-- .../kotlin/hep/dataforge/io/MetaFormatTest.kt | 15 ++++-- .../kotlin/hep/dataforge/meta/Config.kt | 39 +++++++++++++++ .../kotlin/hep/dataforge/meta/Laminate.kt | 10 ++++ .../kotlin/hep/dataforge/meta/Meta.kt | 16 +++++-- .../hep/dataforge/meta/MetaTransformation.kt | 2 +- .../kotlin/hep/dataforge/meta/MutableMeta.kt | 36 ++------------ .../kotlin/hep/dataforge/meta/Styled.kt | 4 +- .../kotlin/hep/dataforge/values/Value.kt | 9 ++++ .../hep/dataforge/values/exoticValues.kt | 4 +- settings.gradle.kts | 8 ++-- 15 files changed, 159 insertions(+), 99 deletions(-) create mode 100644 dataforge-io/src/commonMain/kotlin/hep/dataforge/io/FunctionServer.kt diff --git a/build.gradle.kts b/build.gradle.kts index 00c7dfea..9b042061 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,19 +1,14 @@ plugins { - id("scientifik.mpp") apply false - id("scientifik.publish") apply false + id("scientifik.mpp") version "0.1.4-dev" apply false + id("scientifik.publish") version "0.1.4-dev" apply false } -val dataforgeVersion by extra("0.1.3-dev-9") +val dataforgeVersion by extra("0.1.3-dev-10") val bintrayRepo by extra("dataforge") -val vcs by extra("https://github.com/mipt-npm/dataforge-core") +val githubProject by extra("dataforge-core") allprojects { - repositories { - jcenter() - maven("https://kotlin.bintray.com/kotlinx") - } - group = "hep.dataforge" version = dataforgeVersion } 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 9db32a01..21b8ebe6 100644 --- a/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/hep/dataforge/context/Context.kt @@ -149,7 +149,7 @@ object Global : Context("GLOBAL", null) { return contextRegistry[name] } - fun context(name: String, parent: Context = this, block: ContextBuilder.() -> Unit): Context = + fun context(name: String, parent: Context = this, block: ContextBuilder.() -> Unit = {}): Context = ContextBuilder(name, parent).apply(block).build() } diff --git a/dataforge-io/build.gradle.kts b/dataforge-io/build.gradle.kts index 6ed06857..b65783c6 100644 --- a/dataforge-io/build.gradle.kts +++ b/dataforge-io/build.gradle.kts @@ -2,56 +2,25 @@ plugins { id("scientifik.mpp") } -description = "IO for meta" +description = "IO module" +scientifik{ + serialization = true + io = true +} -val ioVersion: String = Scientifik.ioVersion -val serializationVersion: String = Scientifik.serializationVersion kotlin { - jvm() - js() sourceSets { val commonMain by getting{ dependencies { api(project(":dataforge-meta")) - //implementation 'org.jetbrains.kotlin:kotlin-reflect' - api("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion") - api("org.jetbrains.kotlinx:kotlinx-io:$ioVersion") } } - val commonTest by getting { - dependencies { - implementation("org.jetbrains.kotlin:kotlin-test-common") - implementation("org.jetbrains.kotlin:kotlin-test-annotations-common") + val jsMain by getting{ + dependencies{ + api(npm("text-encoding")) } } - val jvmMain by getting { - dependencies { - api("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion") - api("org.jetbrains.kotlinx:kotlinx-io-jvm:$ioVersion") - } - } - val jvmTest by getting { - dependencies { - implementation("org.jetbrains.kotlin:kotlin-test") - implementation("org.jetbrains.kotlin:kotlin-test-junit") - } - } - val jsMain by getting { - dependencies { - api("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion") - api("org.jetbrains.kotlinx:kotlinx-io-js:$ioVersion") - } - } - val jsTest by getting { - dependencies { - implementation("org.jetbrains.kotlin:kotlin-test-js") - } - } -// iosMain { -// } -// iosTest { -// } } } \ No newline at end of file diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/FunctionServer.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/FunctionServer.kt new file mode 100644 index 00000000..2b254716 --- /dev/null +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/FunctionServer.kt @@ -0,0 +1,38 @@ +package hep.dataforge.io + +import kotlin.reflect.KClass + +/** + * A descriptor for specific type of functions + */ +interface FunctionSpec { + val inputType: KClass + val outputType: KClass +} + +/** + * A server that could produce asynchronous function values + */ +interface FunctionServer { + /** + * Call a function with given name and descriptor + */ + suspend fun > call(name: String, descriptor: D, arg: T): R + + /** + * Resolve a function descriptor for given types + */ + fun resolveType(inputType: KClass, outputType: KClass): FunctionSpec + + /** + * Get a generic suspended function with given name and descriptor + */ + operator fun > get(name: String, descriptor: D): (suspend (T) -> R) = + { call(name, descriptor, it) } +} + +suspend inline fun FunctionServer.call(name: String, arg: T): R = + call(name, resolveType(T::class, R::class), arg) + +inline operator fun FunctionServer.get(name: String): (suspend (T) -> R) = + get(name, resolveType(T::class, R::class)) diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt index 52f01525..4e1f6dec 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt @@ -13,14 +13,21 @@ interface MetaFormat : IOFormat { val key: Short } -fun Meta.asString(format: MetaFormat = JsonMetaFormat): String { - return buildPacket { - format.run { writeObject(this@asString) } - }.readText() +fun Meta.toString(format: MetaFormat = JsonMetaFormat): String = buildPacket { + format.run { writeObject(this@toString) } +}.readText() + +fun Meta.toBytes(format: MetaFormat = JsonMetaFormat): ByteReadPacket = buildPacket { + format.run { writeObject(this@toBytes) } } + fun MetaFormat.parse(str: String): Meta { return ByteReadPacket(str.toByteArray()).readObject() } +fun MetaFormat.fromBytes(packet: ByteReadPacket): Meta { + return packet.readObject() +} + diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaFormatTest.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaFormatTest.kt index e177e4d8..3788a0ef 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaFormatTest.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaFormatTest.kt @@ -1,6 +1,7 @@ package hep.dataforge.io import hep.dataforge.meta.buildMeta +import hep.dataforge.meta.get import kotlin.test.Test import kotlin.test.assertEquals @@ -12,10 +13,11 @@ class MetaFormatTest { "node" to { "b" to "DDD" "c" to 11.1 + "array" to doubleArrayOf(1.0, 2.0, 3.0) } } - val string = meta.asString(BinaryMetaFormat) - val result = BinaryMetaFormat.parse(string) + val bytes = meta.toBytes(BinaryMetaFormat) + val result = BinaryMetaFormat.fromBytes(bytes) assertEquals(meta, result) } @@ -26,11 +28,16 @@ class MetaFormatTest { "node" to { "b" to "DDD" "c" to 11.1 - "array" to doubleArrayOf(1.0,2.0,3.0) + "array" to doubleArrayOf(1.0, 2.0, 3.0) } } - val string = meta.asString(JsonMetaFormat) + val string = meta.toString(JsonMetaFormat) val result = JsonMetaFormat.parse(string) + + meta.items.keys.forEach { + if (meta[it] != result[it]) error("${meta[it]} != ${result[it]}") + } + assertEquals(meta, result) } 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 3ea2a39e..07ce8f96 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt @@ -1,7 +1,9 @@ package hep.dataforge.meta +import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName +import hep.dataforge.names.plus //TODO add validator to configuration @@ -10,6 +12,43 @@ import hep.dataforge.names.asName */ class Config : AbstractMutableMeta() { + private val listeners = HashSet() + + private fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) { + listeners.forEach { it.action(name, oldItem, newItem) } + } + + /** + * Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed + */ + fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) { + listeners.add(MetaListener(owner, action)) + } + + /** + * Remove all listeners belonging to given owner + */ + fun removeListener(owner: Any?) { + listeners.removeAll { it.owner === owner } + } + + override fun replaceItem(key: NameToken, oldItem: MetaItem?, newItem: MetaItem?) { + if (newItem == null) { + _items.remove(key) + if(oldItem!= null && oldItem is MetaItem.NodeItem) { + oldItem.node.removeListener(this) + } + } else { + _items[key] = newItem + if (newItem is MetaItem.NodeItem) { + newItem.node.onChange(this) { name, oldChild, newChild -> + itemChanged(key + name, oldChild, newChild) + } + } + } + itemChanged(key.asName(), oldItem, newItem) + } + /** * Attach configuration node instead of creating one */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt index 28240908..d8be0806 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Laminate.kt @@ -79,4 +79,14 @@ class Laminate(layers: List) : Meta { } } +/** + * Create a new [Laminate] adding given layer to the top + */ +fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers) + +/** + * Create a new [Laminate] adding given layer to the bottom + */ +fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta) + //TODO add custom rules for Laminate merge 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 153beab1..9e71023c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -15,8 +15,16 @@ import hep.dataforge.values.boolean * * a [NodeItem] (node) */ sealed class MetaItem { - data class ValueItem(val value: Value) : MetaItem() - data class NodeItem(val node: M) : MetaItem() + data class ValueItem(val value: Value) : MetaItem(){ + override fun toString(): String = value.string + } + data class NodeItem(val node: M) : MetaItem(){ + override fun toString(): String = node.toString() + + override fun equals(other: Any?): Boolean { + return this.node == (other as? NodeItem<*>).node + } + } } /** @@ -174,12 +182,14 @@ abstract class AbstractMetaNode> : MetaNode { if (this === other) return true if (other !is Meta) return false - return this.items == other.items + return this.items == other.items//this.items.keys == other.items.keys && items.keys.all { this[it] == other[it] } } override fun hashCode(): Int { return items.hashCode() } + + override fun toString(): String = items.toString() } /** diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt index 3d0e50e4..8deada19 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt @@ -110,7 +110,7 @@ inline class MetaTransformation(val transformations: Collection> bind(source: MutableMeta<*>, target: M) { + fun > bind(source: Config, target: M) { source.onChange(target) { name, _, newItem -> transformations.forEach { t -> if (t.matches(name, newItem)) { 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 2be5c1a0..b9ab6f62 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -12,8 +12,8 @@ internal data class MetaListener( interface MutableMeta> : MetaNode { override val items: Map> operator fun set(name: Name, item: MetaItem<*>?) - fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) - fun removeListener(owner: Any? = null) +// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) +// fun removeListener(owner: Any? = null) } /** @@ -22,46 +22,20 @@ interface MutableMeta> : MetaNode { * Changes in Meta are not thread safe. */ abstract class AbstractMutableMeta> : AbstractMetaNode(), MutableMeta { - private val listeners = HashSet() - - /** - * Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed - */ - override fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) { - listeners.add(MetaListener(owner, action)) - } - - /** - * Remove all listeners belonging to given owner - */ - override fun removeListener(owner: Any?) { - listeners.removeAll { it.owner === owner } - } - - private val _items: MutableMap> = HashMap() + protected val _items: MutableMap> = HashMap() override val items: Map> get() = _items - protected fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) { - listeners.forEach { it.action(name, oldItem, newItem) } - } + //protected abstract fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) protected open fun replaceItem(key: NameToken, oldItem: MetaItem?, newItem: MetaItem?) { if (newItem == null) { _items.remove(key) - if(oldItem!= null && oldItem is MetaItem.NodeItem) { - oldItem.node.removeListener(this) - } } else { _items[key] = newItem - if (newItem is MetaItem.NodeItem) { - newItem.node.onChange(this) { name, oldChild, newChild -> - itemChanged(key + name, oldChild, newChild) - } - } } - itemChanged(key.asName(), oldItem, newItem) + //itemChanged(key.asName(), oldItem, newItem) } @Suppress("UNCHECKED_CAST") diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt index c34d933f..55d652aa 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Styled.kt @@ -42,12 +42,12 @@ class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMut } } - override fun onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) { + fun onChange(owner: Any?, action: (Name, before: MetaItem<*>?, after: MetaItem<*>?) -> Unit) { //TODO test correct behavior style.onChange(owner) { name, before, after -> action(name, before ?: base[name], after ?: base[name]) } } - override fun removeListener(owner: Any?) { + fun removeListener(owner: Any?) { style.removeListener(owner) } } 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 ac651c20..140178c2 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/Value.kt @@ -43,6 +43,8 @@ interface Value { val list: List get() = listOf(this) + override fun equals(other: Any?): Boolean + companion object { const val TYPE = "value" @@ -82,6 +84,8 @@ object Null : Value { override val string: String get() = "@null" override fun toString(): String = value.toString() + + override fun equals(other: Any?): Boolean = other === Null } /** @@ -100,6 +104,9 @@ object True : Value { override val string: String get() = "true" override fun toString(): String = value.toString() + + override fun equals(other: Any?): Boolean = other === True + } /** @@ -112,6 +119,8 @@ object False : Value { override val string: String get() = "false" override fun toString(): String = True.value.toString() + + override fun equals(other: Any?): Boolean = other === False } val Value.boolean get() = this == True || this.list.firstOrNull() == True || (type == ValueType.STRING && string.toBoolean()) diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/exoticValues.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/exoticValues.kt index 9f13d73a..8ebc1c6b 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/exoticValues.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/values/exoticValues.kt @@ -12,9 +12,11 @@ class LazyParsedValue(override val string: String) : Value { override val number: Number get() = parsedValue.number override fun toString(): String = string + + override fun equals(other: Any?): Boolean = other is Value && this.parsedValue == other } -fun String.lazyParseValue(): LazyParsedValue = LazyParsedValue(this) +fun String.lazyParseValue(): LazyParsedValue = LazyParsedValue(this) /** * A performance optimized version of list value for doubles diff --git a/settings.gradle.kts b/settings.gradle.kts index 73726216..011123b9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,18 +1,18 @@ pluginManagement { repositories { + mavenLocal() jcenter() gradlePluginPortal() maven("https://dl.bintray.com/kotlin/kotlin-eap") + maven("https://dl.bintray.com/kotlin/kotlinx") maven("https://dl.bintray.com/mipt-npm/scientifik") + maven("https://dl.bintray.com/mipt-npm/dev") } resolutionStrategy { eachPlugin { when (requested.id.id) { "kotlinx-atomicfu" -> useModule("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${requested.version}") - "kotlin-multiplatform" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - "kotlin2js" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${requested.version}") - "org.jetbrains.kotlin.frontend" -> useModule("org.jetbrains.kotlin:kotlin-frontend-plugin:0.0.45") - "scientifik.mpp", "scientifik.publish" -> useModule("scientifik:gradle-tools:0.1.0") + "scientifik.mpp", "scientifik.publish" -> useModule("scientifik:gradle-tools:${requested.version}") } } }