From 13a00d0d19cb8c923e31aae3ae6dc87b37c98ea7 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 26 Oct 2018 14:10:41 +0300 Subject: [PATCH] Json serialization for JVM and Binary serialization in common --- .gitignore | 1 + build.gradle | 29 ++-- dataforge-envelope/build.gradle | 13 -- .../hep/dataforge/envelopes/Envelope.kt | 9 - dataforge-meta-io/build.gradle | 35 +--- .../hep/dataforge/meta/io/MetaFormat.kt | 155 +++++++++++++++++- .../kotlin/hep/dataforge/meta/io/MetaProxy.kt | 51 ------ .../hep/dataforge/meta/io/Serializers.kt | 145 ++++++---------- .../commonTest/kotlin/io/MetaItemProxyTest.kt | 47 ------ .../kotlin/hep/dataforge/meta/io/JSMeta.kt | 36 ++++ .../hep/dataforge/meta/io/JSONMetaFormat.kt | 17 ++ .../kotlin/hep/dataforge/meta/JSMetaTest.kt | 18 ++ .../hep/dataforge/meta/io/JSONMetaFormat.kt | 118 +++++++++++++ dataforge-meta/build.gradle | 27 ++- .../kotlin/hep/dataforge/meta/Meta.kt | 31 +--- .../kotlin/hep/dataforge/meta/MetaBuilder.kt | 2 +- settings.gradle | 3 +- 17 files changed, 432 insertions(+), 305 deletions(-) delete mode 100644 dataforge-envelope/build.gradle delete mode 100644 dataforge-envelope/src/main/kotlin/hep/dataforge/envelopes/Envelope.kt delete mode 100644 dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaProxy.kt delete mode 100644 dataforge-meta-io/src/commonTest/kotlin/io/MetaItemProxyTest.kt create mode 100644 dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt create mode 100644 dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt create mode 100644 dataforge-meta-io/src/jsTest/kotlin/hep/dataforge/meta/JSMetaTest.kt create mode 100644 dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt diff --git a/.gitignore b/.gitignore index d35e96f9..534e4d13 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ out/ !gradle-wrapper.jar +artifactory.gradle \ No newline at end of file diff --git a/build.gradle b/build.gradle index 25c077f0..5dd5baab 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ buildscript { - ext.kotlin_version = '1.3.0-rc-57' - ext.serialization_version = '0.8.0-rc13' - ext.kotlinx_io_version = '0.1.0-alpha-15-rc13' + ext.kotlin_version = '1.3.0-rc-190' + ext.serialization_version = '0.8.3-rc13' + ext.kotlinx_io_version = '0.1.0-alpha-24-rc13' repositories { jcenter() maven { @@ -12,26 +12,25 @@ buildscript { dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + classpath "org.jfrog.buildinfo:build-info-extractor-gradle:4+" } } -//plugins { -// id 'kotlin-platform-common' version "$kotlin_version" apply false -// id 'kotlin-platform-jvm' version "$kotlin_version" apply false -// id 'kotlin-platform-js' version "$kotlin_version" apply false -// id 'kotlinx-serialization' version "$kotlin_version" apply false -//} - -description = "The basic interfaces for DataForge meta-data" - -group = 'hep.dataforge' -version = '0.1.1-SNAPSHOT' - allprojects { + apply plugin: 'maven-publish' + apply plugin: "com.jfrog.artifactory" + repositories { jcenter() maven { url = "http://dl.bintray.com/kotlin/kotlin-eap" } maven { url = "https://kotlin.bintray.com/kotlinx" } //maven { url 'https://jitpack.io' } } + + group = 'hep.dataforge' + version = '0.1.1-SNAPSHOT' } + +if(file('aritfactory.gradle').exists()) { + apply from: 'aritfactory.gradle' +} \ No newline at end of file diff --git a/dataforge-envelope/build.gradle b/dataforge-envelope/build.gradle deleted file mode 100644 index fd1ea5e8..00000000 --- a/dataforge-envelope/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -plugins{ - id 'kotlin-platform-common' -} - -dependencies { - compile project(":dataforge-meta") - - compile "org.jetbrains.kotlinx:kotlinx-io:$kotlinx_io_version" - - compile "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version" - testCompile "org.jetbrains.kotlin:kotlin-test-annotations-common" - testCompile "org.jetbrains.kotlin:kotlin-test-common" -} \ No newline at end of file diff --git a/dataforge-envelope/src/main/kotlin/hep/dataforge/envelopes/Envelope.kt b/dataforge-envelope/src/main/kotlin/hep/dataforge/envelopes/Envelope.kt deleted file mode 100644 index 9368a452..00000000 --- a/dataforge-envelope/src/main/kotlin/hep/dataforge/envelopes/Envelope.kt +++ /dev/null @@ -1,9 +0,0 @@ -package hep.dataforge.envelopes - -import hep.dataforge.meta.Meta -import kotlinx.io.core.IoBuffer - -interface Envelope{ - val meta: Meta - val data: IoBuffer -} \ No newline at end of file diff --git a/dataforge-meta-io/build.gradle b/dataforge-meta-io/build.gradle index 51ffa452..26c0493d 100644 --- a/dataforge-meta-io/build.gradle +++ b/dataforge-meta-io/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'kotlin-multiplatform'// version '1.3.0-rc-57' + id 'kotlin-multiplatform' id 'kotlinx-serialization' } repositories { @@ -18,45 +18,28 @@ kotlin { sourceSets { commonMain { dependencies { - implementation project(":dataforge-meta") - implementation "org.jetbrains.kotlin:kotlin-stdlib-common" + api project(":dataforge-meta") implementation 'org.jetbrains.kotlin:kotlin-reflect' + implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" implementation "org.jetbrains.kotlinx:kotlinx-io:$kotlinx_io_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" - } - } - commonTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-common' - implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" } } + commonTest {} jvmMain { dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version" + implementation 'com.github.cliftonlabs:json-simple:3.0.2' implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version" + implementation "org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version" } } - jvmTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test' - implementation 'org.jetbrains.kotlin:kotlin-test-junit' - } - } + jvmTest {} jsMain { dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version" - } - } - jsTest { - dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-js' implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version" + implementation "org.jetbrains.kotlinx:kotlinx-io-js:$kotlinx_io_version" } } + jsTest {} // iosMain { // } // iosTest { diff --git a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt index 7eb3b641..0f0a662d 100644 --- a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt +++ b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaFormat.kt @@ -1,15 +1,17 @@ package hep.dataforge.meta.io -import hep.dataforge.meta.Meta +import hep.dataforge.meta.* import kotlinx.io.core.Input import kotlinx.io.core.Output +import kotlinx.io.core.readText +import kotlinx.io.core.writeText /** * A format for meta serialization */ interface MetaFormat { - val name : String - val key : Short + val name: String + val key: Short suspend fun write(meta: Meta, out: Output) suspend fun read(input: Input): Meta @@ -23,4 +25,149 @@ interface MetaFormat { ///** // * Resolve format by its binary key. Null if not provided // */ -//expect fun resolveFormat(key: Short): MetaFormat? \ No newline at end of file +//expect fun resolveFormat(key: Short): MetaFormat? + +internal expect fun writeJson(meta: Meta, out: Output) +internal expect fun readJson(input: Input, length: Int = -1): Meta + +object JSONMetaFormat : MetaFormat { + override val name: String = "json" + override val key: Short = 0x4a53//"JS" + + override suspend fun write(meta: Meta, out: Output) = writeJson(meta, out) + override suspend fun read(input: Input): Meta = readJson(input) +} + +object BinaryMetaFormat : MetaFormat { + override val name: String = "bin" + override val key: Short = 0x4249//BI + + override suspend fun write(meta: Meta, out: Output) { + out.writeMeta(meta) + } + + override suspend fun read(input: Input): Meta { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + private fun Output.writeChar(char: Char) = writeByte(char.toByte()) + + private fun Output.writeString(str: String) { + writeInt(str.length) + writeText(str) + } + + private fun Output.writeValue(value: Value) { + if (value.isList()) { + writeChar('L') + writeInt(value.list.size) + value.list.forEach { + writeValue(it) + } + } else when (value.type) { + ValueType.NUMBER -> when (value.value) { + is Short -> { + writeChar('s') + writeShort(value.number.toShort()) + } + is Int -> { + writeChar('i') + writeInt(value.number.toInt()) + } + is Long -> { + writeChar('l') + writeLong(value.number.toLong()) + } + is Float -> { + writeChar('f') + writeFloat(value.number.toFloat()) + } + else -> { + writeChar('d') + writeDouble(value.number.toDouble()) + } + } + ValueType.STRING -> { + writeChar('S') + writeString(value.string) + } + ValueType.BOOLEAN -> { + if (value.boolean) { + writeChar('+') + } else { + writeChar('-') + } + } + ValueType.NULL -> { + writeChar('N') + } + } + } + + private fun Output.writeMeta(meta: Meta) { + writeChar('M') + writeInt(meta.items.size) + meta.items.forEach { (key, item) -> + writeString(key) + when (item) { + is MetaItem.ValueItem -> { + writeValue(item.value) + } + is MetaItem.SingleNodeItem -> { + writeMeta(item.node) + } + is MetaItem.MultiNodeItem -> { + writeChar('#') + writeInt(item.nodes.size) + item.nodes.forEach { + writeMeta(it) + } + } + } + } + } + + private fun Input.readString(): String { + val length = readInt() + return readText(max = length) + } + + private fun Input.readMetaItem(): MetaItem { + val keyChar = readByte().toChar() + return when (keyChar) { + 'S' -> MetaItem.ValueItem(StringValue(readString())) + 'N' -> MetaItem.ValueItem(Null) + '+' -> MetaItem.ValueItem(True) + '-' -> MetaItem.ValueItem(True) + 's' -> MetaItem.ValueItem(NumberValue(readShort())) + 'i' -> MetaItem.ValueItem(NumberValue(readInt())) + 'l' -> MetaItem.ValueItem(NumberValue(readInt())) + 'f' -> MetaItem.ValueItem(NumberValue(readFloat())) + 'd' -> MetaItem.ValueItem(NumberValue(readDouble())) + 'L' -> { + val length = readInt() + val list = (1..length).map { (readMetaItem() as MetaItem.ValueItem).value } + MetaItem.ValueItem(Value.of(list)) + } + 'M' -> { + val length = readInt() + val meta = buildMeta { + (1..length).forEach { _ -> + val name = readString() + val item = readMetaItem() + set(name,item) + } + } + MetaItem.SingleNodeItem(meta) + } + '#' -> { + val length = readInt() + val nodes = (1..length).map { (readMetaItem() as MetaItem.SingleNodeItem).node } + MetaItem.MultiNodeItem(nodes) + } + else -> error("Unknown serialization key character: $keyChar") + } + } + +} + diff --git a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaProxy.kt b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaProxy.kt deleted file mode 100644 index 3e1e1681..00000000 --- a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/MetaProxy.kt +++ /dev/null @@ -1,51 +0,0 @@ -package hep.dataforge.meta.io - -import hep.dataforge.meta.Meta -import hep.dataforge.meta.MetaItem -import hep.dataforge.meta.ValueType -import hep.dataforge.meta.boolean -import kotlinx.serialization.Polymorphic -import kotlinx.serialization.Serializable - -/*Universal serialization*/ - -@Serializable -class MetaProxy(val map: Map) - - -@Serializable -sealed class MetaItemProxy { - @Serializable - class NumberValueProxy(val number: Number) : MetaItemProxy() - - @Serializable - class StringValueProxy(val string: String) : MetaItemProxy() - - @Serializable - class BooleanValueProxy(val boolean: Boolean) : MetaItemProxy() - - @Serializable - object NullValueProxy : MetaItemProxy() - - @Serializable - class SingleMetaProxy(val node: MetaProxy) : MetaItemProxy() - - @Serializable - class MetaListProxy(val list: List<@Polymorphic MetaProxy>) : MetaItemProxy() -} - - -fun Meta.toMap(): MetaProxy { - return MetaProxy(this.items.mapValues { (_, value) -> - when (value) { - is MetaItem.ValueItem<*> -> when (value.value.type) { - ValueType.NUMBER -> MetaItemProxy.NumberValueProxy(value.value.number) - ValueType.STRING -> MetaItemProxy.StringValueProxy(value.value.string) - ValueType.BOOLEAN -> MetaItemProxy.BooleanValueProxy(value.value.boolean) - ValueType.NULL -> MetaItemProxy.NullValueProxy - } - is MetaItem.SingleNodeItem<*> -> MetaItemProxy.SingleMetaProxy(value.node.toMap()) - is MetaItem.MultiNodeItem<*> -> MetaItemProxy.MetaListProxy(value.nodes.map { it.toMap() }) - } - }) -} diff --git a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/Serializers.kt b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/Serializers.kt index d52b7be1..d1811a72 100644 --- a/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/Serializers.kt +++ b/dataforge-meta-io/src/commonMain/kotlin/hep/dataforge/meta/io/Serializers.kt @@ -6,59 +6,59 @@ import kotlinx.serialization.json.* /*Direct JSON serialization*/ -fun Value.toJson(): JsonElement = if (isList()) { - JsonArray(list.map { it.toJson() }) -} else { - when (type) { - ValueType.NUMBER -> JsonPrimitive(number) - ValueType.STRING -> JsonPrimitive(string) - ValueType.BOOLEAN -> JsonPrimitive(boolean) - ValueType.NULL -> JsonNull - } -} - -fun Meta.toJSON(): JsonObject { - val map = this.items.mapValues { (_, value) -> - when (value) { - is MetaItem.ValueItem -> value.value.toJson() - is MetaItem.SingleNodeItem -> value.node.toJSON() - is MetaItem.MultiNodeItem -> JsonArray(value.nodes.map { it.toJSON() }) - } - } - return JsonObject(map) -} - -fun JsonPrimitive.toValue(): Value { - return when (this) { - is JsonLiteral -> LazyParsedValue(content) - is JsonNull -> Null - } -} - -fun JsonObject.toMeta(): Meta { - return buildMeta { - this@toMeta.forEach { (key, value) -> - when (value) { - is JsonPrimitive -> set(key, value.toValue()) - is JsonObject -> set(key, value.toMeta()) - is JsonArray -> if (value.all { it is JsonPrimitive }) { - set(key, ListValue(value.map { (it as JsonPrimitive).toValue() })) - } else { - set( - key, - value.map { - if (it is JsonObject) { - it.toMeta() - } else { - buildMeta { "@value" to it.primitive.toValue() } - } - } - ) - } - } - } - } -} +//fun Value.toJson(): JsonElement = if (isList()) { +// JsonArray(list.map { it.toJson() }) +//} else { +// when (type) { +// ValueType.NUMBER -> JsonPrimitive(number) +// ValueType.STRING -> JsonPrimitive(string) +// ValueType.BOOLEAN -> JsonPrimitive(boolean) +// ValueType.NULL -> JsonNull +// } +//} +// +//fun Meta.toJSON(): JsonObject { +// val map = this.items.mapValues { (_, value) -> +// when (value) { +// is MetaItem.ValueItem -> value.value.toJson() +// is MetaItem.SingleNodeItem -> value.node.toJSON() +// is MetaItem.MultiNodeItem -> JsonArray(value.nodes.map { it.toJSON() }) +// } +// } +// return JsonObject(map) +//} +// +//fun JsonPrimitive.toValue(): Value { +// return when (this) { +// is JsonLiteral -> LazyParsedValue(content) +// is JsonNull -> Null +// } +//} +// +//fun JsonObject.toMeta(): Meta { +// return buildMeta { +// this@toMeta.forEach { (key, value) -> +// when (value) { +// is JsonPrimitive -> set(key, value.toValue()) +// is JsonObject -> set(key, value.toMeta()) +// is JsonArray -> if (value.all { it is JsonPrimitive }) { +// set(key, ListValue(value.map { (it as JsonPrimitive).toValue() })) +// } else { +// set( +// key, +// value.map { +// if (it is JsonObject) { +// it.toMeta() +// } else { +// buildMeta { "@value" to it.primitive.toValue() } +// } +// } +// ) +// } +// } +// } +// } +//} /*Direct CBOR serialization*/ @@ -67,45 +67,6 @@ fun JsonObject.toMeta(): Meta { // encodeNumber(char.toByte().toLong()) // } // -// fun CBOR.CBOREncoder.encodeValue(value: Value) { -// if (value.isList()) { -// encodeChar('L') -// startArray() -// value.list.forEach { -// encodeValue(it) -// } -// end() -// } else when (value.type) { -// ValueType.NUMBER -> when (value.value) { -// is Int, is Short, is Long -> { -// encodeChar('i') -// encodeNumber(value.number.toLong()) -// } -// is Float -> { -// encodeChar('f') -// encodeFloat(value.number.toFloat()) -// } -// else -> { -// encodeChar('d') -// encodeDouble(value.number.toDouble()) -// } -// } -// ValueType.STRING -> { -// encodeChar('S') -// encodeString(value.string) -// } -// ValueType.BOOLEAN -> { -// if (value.boolean) { -// encodeChar('+') -// } else { -// encodeChar('-') -// } -// } -// ValueType.NULL -> { -// encodeChar('N') -// } -// } -// } // // fun CBOR.CBOREncoder.encodeMeta(meta: Meta) { // meta.items.forEach { (key, item) -> diff --git a/dataforge-meta-io/src/commonTest/kotlin/io/MetaItemProxyTest.kt b/dataforge-meta-io/src/commonTest/kotlin/io/MetaItemProxyTest.kt deleted file mode 100644 index cd12d611..00000000 --- a/dataforge-meta-io/src/commonTest/kotlin/io/MetaItemProxyTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -package io - -import hep.dataforge.meta.buildMeta -import hep.dataforge.meta.io.MetaItemProxy -import hep.dataforge.meta.io.toMap -import kotlinx.serialization.json.JSON -import kotlinx.serialization.serializer -import kotlin.test.Test - -class MetaItemProxyTest { - @Test - fun testGeneration() { - MetaItemProxy::class.serializer() - } - - - @Test - fun testProxySerialization() { - val meta = buildMeta { - "a" to 2 - "b" to { - "c" to "ddd" - "d" to 2.2 - } - } - val json = JSON.indented.stringify(meta.toMap()) - println(json) -// val result: Map = JSON.parse(json) -// assertEquals(meta,result.to) - } - -// @Test -// fun testJSONSerialization() { -// val meta = buildMeta { -// "a" to 2 -// "b" to { -// "c" to "ddd" -// "d" to 2.2 -// } -// } -// val json = meta.toJSON() -// println(json) -// val result = json.toMeta() -// assertEquals(meta, result) -// } - -} \ No newline at end of file diff --git a/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt new file mode 100644 index 00000000..75d0136f --- /dev/null +++ b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSMeta.kt @@ -0,0 +1,36 @@ +package hep.dataforge.meta.io + +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.Value + +/** + * Represent any js object as meta + */ +class JSMeta(val obj: Any) : Meta { + override val items: Map> + get() = listKeys(obj).associateWith { convert(js("obj[it]")) } + + private fun listKeys(obj: Any): List = js("Object").keys(obj) as List + + private fun isList(obj: Any): Boolean = js("Array").isArray(obj) as Boolean + + private fun isPrimitive(obj: Any?): Boolean = js("obj !== Object(obj)") as Boolean + + private fun convert(obj: Any?): MetaItem { + return when (obj) { + null, isPrimitive(obj), is Number, is String, is Boolean -> MetaItem.ValueItem(Value.of(obj)) + isList(obj) -> { + val list = obj as List<*> + //if first value is primitive, treat as value + if (isPrimitive(list.first())) { + MetaItem.ValueItem(Value.of(list)) + } else { + //else treat as meta list + MetaItem.MultiNodeItem(list.map { JSMeta(it!!) }) + } + } + else -> MetaItem.SingleNodeItem(JSMeta(obj)) + } + } +} \ No newline at end of file diff --git a/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt new file mode 100644 index 00000000..60b1446e --- /dev/null +++ b/dataforge-meta-io/src/jsMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt @@ -0,0 +1,17 @@ +package hep.dataforge.meta.io + +import hep.dataforge.meta.Meta +import kotlinx.io.core.Input +import kotlinx.io.core.Output +import kotlinx.io.core.readText +import kotlinx.io.core.writeText +import kotlin.js.Json + +internal actual fun writeJson(meta: Meta, out: Output) { + out.writeText(JSON.stringify(meta)) +} + +internal actual fun readJson(input: Input, length: Int): Meta { + val json: Json = JSON.parse(input.readText(max = if (length > 0) length else Int.MAX_VALUE)) + return JSMeta(json) +} \ No newline at end of file diff --git a/dataforge-meta-io/src/jsTest/kotlin/hep/dataforge/meta/JSMetaTest.kt b/dataforge-meta-io/src/jsTest/kotlin/hep/dataforge/meta/JSMetaTest.kt new file mode 100644 index 00000000..e925b92c --- /dev/null +++ b/dataforge-meta-io/src/jsTest/kotlin/hep/dataforge/meta/JSMetaTest.kt @@ -0,0 +1,18 @@ +package hep.dataforge.meta + +import hep.dataforge.meta.io.JSMeta +import kotlin.js.json +import kotlin.test.Test +import kotlin.test.assertEquals + +class JSMetaTest{ + @Test + fun testConverstion(){ + val test = json( + "a" to 2, + "b" to "ddd" + ) + val meta = JSMeta(test) + assertEquals(2, meta["a"]!!.int) + } +} \ No newline at end of file diff --git a/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt b/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt new file mode 100644 index 00000000..f3bff93c --- /dev/null +++ b/dataforge-meta-io/src/jvmMain/kotlin/hep/dataforge/meta/io/JSONMetaFormat.kt @@ -0,0 +1,118 @@ +package hep.dataforge.meta.io + +import com.github.cliftonlabs.json_simple.JsonArray +import com.github.cliftonlabs.json_simple.JsonObject +import com.github.cliftonlabs.json_simple.Jsoner +import hep.dataforge.meta.* +import kotlinx.io.core.* +import java.io.ByteArrayInputStream +import java.io.InputStreamReader +import java.io.Reader +import java.text.ParseException + +internal actual fun writeJson(meta: Meta, out: Output) { + val json = meta.toJson() + val string = Jsoner.prettyPrint(Jsoner.serialize(json)) + out.writeText(string) +} + +private fun Value.toJson(): Any { + return if (list.size == 1) { + when (type) { + ValueType.NUMBER -> number + ValueType.BOOLEAN -> boolean + else -> string + } + } else { + JsonArray().apply { + list.forEach { add(it.toJson()) } + } + } +} + +private fun Meta.toJson(): JsonObject { + val builder = JsonObject() + items.forEach { name, item -> + when (item) { + is MetaItem.ValueItem -> builder[name] = item.value.toJson() + is MetaItem.SingleNodeItem -> builder[name] = item.node.toJson() + is MetaItem.MultiNodeItem -> { + val array = JsonArray() + item.nodes.forEach { array.add(it.toJson()) } + builder[name] = array + } + } + } + return builder +} + + +internal actual fun readJson(input: Input, length: Int): Meta { + return if (length == 0) { + EmptyMeta + } else { + val json = if (length > 0) { + //Read into intermediate buffer + val buffer = ByteArray(length) + input.readAvailable(buffer, length) + Jsoner.deserialize(InputStreamReader(ByteArrayInputStream(buffer), Charsets.UTF_8)) as JsonObject + } else { + //automatic + val reader = object : Reader() { + override fun close() { + input.close() + } + + override fun read(cbuf: CharArray, off: Int, len: Int): Int { + val block = input.readText(Charsets.UTF_8, len).toCharArray() + System.arraycopy(block, 0, cbuf, off, block.size) + return block.size + } + + } + Jsoner.deserialize(reader) as JsonObject + } + json.toMeta() + } +} + +@Throws(ParseException::class) +private fun JsonObject.toMeta(): Meta { + return buildMeta { + this@toMeta.forEach { key, value -> appendValue(key as String, value) } + } +} + +private fun JsonArray.toListValue(): Value { + val list: List = this.map { value -> + when (value) { + null -> Null + is JsonArray -> value.toListValue() + is Number -> NumberValue(value) + is Boolean -> if (value) True else False + is String -> LazyParsedValue(value) + is JsonObject -> error("Object values inside multidimensional arrays are not allowed") + else -> error("Unknown token $value in json") + } + } + return Value.of(list) +} + +private fun MetaBuilder.appendValue(key: String, value: Any?) { + when (value) { + is JsonObject -> this[key] = value.toMeta() + is JsonArray -> { + value.forEach { + if (it is JsonArray) { + this[key] = it.toListValue() + } else { + appendValue(key, it) + } + } + } + is Number -> this[key] = NumberValue(value) + is Boolean -> this[key] = value + is String -> this[key] = LazyParsedValue(value) + //ignore anything else + } +} diff --git a/dataforge-meta/build.gradle b/dataforge-meta/build.gradle index 34599174..bba6b93b 100644 --- a/dataforge-meta/build.gradle +++ b/dataforge-meta/build.gradle @@ -1,6 +1,5 @@ plugins { - id 'kotlin-multiplatform'// version '1.3.0-rc-57' - id 'kotlinx-serialization' + id 'kotlin-multiplatform' } repositories { maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' } @@ -18,41 +17,35 @@ kotlin { sourceSets { commonMain { dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-common" - implementation 'org.jetbrains.kotlin:kotlin-reflect' - implementation "org.jetbrains.kotlinx:kotlinx-io:$kotlinx_io_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" + api "org.jetbrains.kotlin:kotlin-stdlib-common" + } } commonTest { dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-common' - implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version" + api 'org.jetbrains.kotlin:kotlin-test-common' + api 'org.jetbrains.kotlin:kotlin-test-annotations-common' } } jvmMain { dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk8" } } jvmTest { dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test' - implementation 'org.jetbrains.kotlin:kotlin-test-junit' + api 'org.jetbrains.kotlin:kotlin-test' + api 'org.jetbrains.kotlin:kotlin-test-junit' } } jsMain { dependencies { - implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version" + api 'org.jetbrains.kotlin:kotlin-stdlib-js' } } jsTest { dependencies { - implementation 'org.jetbrains.kotlin:kotlin-test-js' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version" + api 'org.jetbrains.kotlin:kotlin-test-js' } } // iosMain { 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 2d5eb1f1..88495f4e 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Meta.kt @@ -10,34 +10,9 @@ import hep.dataforge.names.toName * * a list of nodes */ sealed class MetaItem { - class ValueItem(val value: Value) : MetaItem(){ - override fun equals(other: Any?): Boolean { - return this.value == (other as? ValueItem<*>)?.value - } - - override fun hashCode(): Int { - return value.hashCode() - } - } - class SingleNodeItem(val node: M) : MetaItem(){ - override fun equals(other: Any?): Boolean { - return this.node == (other as? SingleNodeItem<*>)?.node - } - - override fun hashCode(): Int { - return node.hashCode() - } - } - - class MultiNodeItem(val nodes: List) : MetaItem(){ - override fun equals(other: Any?): Boolean { - return this.nodes == (other as? MultiNodeItem<*>)?.nodes - } - - override fun hashCode(): Int { - return nodes.hashCode() - } - } + data class ValueItem(val value: Value) : MetaItem() + data class SingleNodeItem(val node: M) : MetaItem() + data class MultiNodeItem(val nodes: List) : MetaItem() } operator fun List.get(query: String): M? { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt index c7f6724d..647e560d 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaBuilder.kt @@ -45,4 +45,4 @@ fun Meta.builder(): MetaBuilder { } } -fun buildMeta(builder: MetaBuilder.() -> Unit): Meta = MetaBuilder().apply(builder) \ No newline at end of file +fun buildMeta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder) \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 665278b9..f7aab5b8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -28,5 +28,4 @@ rootProject.name = 'dataforge-core' include ":dataforge-meta" include ":dataforge-meta-io" - -include ":dataforge-envelope" \ No newline at end of file +//include ":dataforge-envelope" \ No newline at end of file