Json serialization for JVM and Binary serialization in common
This commit is contained in:
parent
c1d004ec3e
commit
13a00d0d19
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ out/
|
||||
|
||||
!gradle-wrapper.jar
|
||||
|
||||
artifactory.gradle
|
29
build.gradle
29
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'
|
||||
}
|
@ -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"
|
||||
}
|
@ -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
|
||||
}
|
@ -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 {
|
||||
|
@ -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
|
||||
@ -24,3 +26,148 @@ interface MetaFormat {
|
||||
// * Resolve format by its binary key. Null if not provided
|
||||
// */
|
||||
//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<MetaBuilder> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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<String, @Polymorphic MetaItemProxy>)
|
||||
|
||||
|
||||
@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() })
|
||||
}
|
||||
})
|
||||
}
|
@ -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) ->
|
||||
|
@ -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<String, MetaItemProxy> = 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)
|
||||
// }
|
||||
|
||||
}
|
@ -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<String, MetaItem<out Meta>>
|
||||
get() = listKeys(obj).associateWith { convert(js("obj[it]")) }
|
||||
|
||||
private fun listKeys(obj: Any): List<String> = js("Object").keys(obj) as List<String>
|
||||
|
||||
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<out Meta> {
|
||||
return when (obj) {
|
||||
null, isPrimitive(obj), is Number, is String, is Boolean -> MetaItem.ValueItem<JSMeta>(Value.of(obj))
|
||||
isList(obj) -> {
|
||||
val list = obj as List<*>
|
||||
//if first value is primitive, treat as value
|
||||
if (isPrimitive(list.first())) {
|
||||
MetaItem.ValueItem<JSMeta>(Value.of(list))
|
||||
} else {
|
||||
//else treat as meta list
|
||||
MetaItem.MultiNodeItem(list.map { JSMeta(it!!) })
|
||||
}
|
||||
}
|
||||
else -> MetaItem.SingleNodeItem(JSMeta(obj))
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
@ -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<Value> = 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
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -10,34 +10,9 @@ import hep.dataforge.names.toName
|
||||
* * a list of nodes
|
||||
*/
|
||||
sealed class MetaItem<M : Meta> {
|
||||
class ValueItem<M : Meta>(val value: Value) : MetaItem<M>(){
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this.value == (other as? ValueItem<*>)?.value
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.hashCode()
|
||||
}
|
||||
}
|
||||
class SingleNodeItem<M : Meta>(val node: M) : MetaItem<M>(){
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this.node == (other as? SingleNodeItem<*>)?.node
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return node.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
class MultiNodeItem<M : Meta>(val nodes: List<M>) : MetaItem<M>(){
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this.nodes == (other as? MultiNodeItem<*>)?.nodes
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return nodes.hashCode()
|
||||
}
|
||||
}
|
||||
data class ValueItem<M : Meta>(val value: Value) : MetaItem<M>()
|
||||
data class SingleNodeItem<M : Meta>(val node: M) : MetaItem<M>()
|
||||
data class MultiNodeItem<M : Meta>(val nodes: List<M>) : MetaItem<M>()
|
||||
}
|
||||
|
||||
operator fun <M : Meta> List<M>.get(query: String): M? {
|
||||
|
@ -45,4 +45,4 @@ fun Meta.builder(): MetaBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fun buildMeta(builder: MetaBuilder.() -> Unit): Meta = MetaBuilder().apply(builder)
|
||||
fun buildMeta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
@ -28,5 +28,4 @@ rootProject.name = 'dataforge-core'
|
||||
|
||||
include ":dataforge-meta"
|
||||
include ":dataforge-meta-io"
|
||||
|
||||
include ":dataforge-envelope"
|
||||
//include ":dataforge-envelope"
|
Loading…
Reference in New Issue
Block a user