Meta and io fixes

This commit is contained in:
Alexander Nozik 2019-07-27 17:02:48 +03:00
parent da4a9ebe9d
commit efddfa8e91
15 changed files with 159 additions and 99 deletions

View File

@ -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
}

View File

@ -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()
}

View File

@ -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 {
// }
}
}

View File

@ -0,0 +1,38 @@
package hep.dataforge.io
import kotlin.reflect.KClass
/**
* A descriptor for specific type of functions
*/
interface FunctionSpec<T : Any, R : Any> {
val inputType: KClass<T>
val outputType: KClass<R>
}
/**
* A server that could produce asynchronous function values
*/
interface FunctionServer {
/**
* Call a function with given name and descriptor
*/
suspend fun <T : Any, R : Any, D : FunctionSpec<T, R>> call(name: String, descriptor: D, arg: T): R
/**
* Resolve a function descriptor for given types
*/
fun <T : Any, R : Any> resolveType(inputType: KClass<out T>, outputType: KClass<out R>): FunctionSpec<T, R>
/**
* Get a generic suspended function with given name and descriptor
*/
operator fun <T : Any, R : Any, D : FunctionSpec<T, R>> get(name: String, descriptor: D): (suspend (T) -> R) =
{ call(name, descriptor, it) }
}
suspend inline fun <reified T : Any, reified R : Any> FunctionServer.call(name: String, arg: T): R =
call(name, resolveType(T::class, R::class), arg)
inline operator fun <reified T : Any, reified R : Any> FunctionServer.get(name: String): (suspend (T) -> R) =
get(name, resolveType(T::class, R::class))

View File

@ -13,14 +13,21 @@ interface MetaFormat : IOFormat<Meta> {
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()
}

View File

@ -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)
}

View File

@ -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<Config>() {
private val listeners = HashSet<MetaListener>()
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<Config>?, newItem: MetaItem<Config>?) {
if (newItem == null) {
_items.remove(key)
if(oldItem!= null && oldItem is MetaItem.NodeItem<Config>) {
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
*/

View File

@ -79,4 +79,14 @@ class Laminate(layers: List<Meta>) : 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

View File

@ -15,8 +15,16 @@ import hep.dataforge.values.boolean
* * a [NodeItem] (node)
*/
sealed class MetaItem<out M : Meta> {
data class ValueItem(val value: Value) : MetaItem<Nothing>()
data class NodeItem<M : Meta>(val node: M) : MetaItem<M>()
data class ValueItem(val value: Value) : MetaItem<Nothing>(){
override fun toString(): String = value.string
}
data class NodeItem<M : Meta>(val node: M) : MetaItem<M>(){
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<M : MetaNode<M>> : MetaNode<M> {
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()
}
/**

View File

@ -110,7 +110,7 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
/**
* Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule.
*/
fun <M : MutableMeta<M>> bind(source: MutableMeta<*>, target: M) {
fun <M : MutableMeta<M>> bind(source: Config, target: M) {
source.onChange(target) { name, _, newItem ->
transformations.forEach { t ->
if (t.matches(name, newItem)) {

View File

@ -12,8 +12,8 @@ internal data class MetaListener(
interface MutableMeta<M : MutableMeta<M>> : MetaNode<M> {
override val items: Map<NameToken, MetaItem<M>>
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<M : MutableMeta<M>> : MetaNode<M> {
* Changes in Meta are not thread safe.
*/
abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
private val listeners = HashSet<MetaListener>()
/**
* 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<NameToken, MetaItem<M>> = HashMap()
protected val _items: MutableMap<NameToken, MetaItem<M>> = HashMap()
override val items: Map<NameToken, MetaItem<M>>
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<M>?, newItem: MetaItem<M>?) {
if (newItem == null) {
_items.remove(key)
if(oldItem!= null && oldItem is MetaItem.NodeItem<M>) {
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")

View File

@ -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)
}
}

View File

@ -43,6 +43,8 @@ interface Value {
val list: List<Value>
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())

View File

@ -12,6 +12,8 @@ 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)

View File

@ -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}")
}
}
}