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
|
!gradle-wrapper.jar
|
||||||
|
|
||||||
|
artifactory.gradle
|
29
build.gradle
29
build.gradle
@ -1,7 +1,7 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.0-rc-57'
|
ext.kotlin_version = '1.3.0-rc-190'
|
||||||
ext.serialization_version = '0.8.0-rc13'
|
ext.serialization_version = '0.8.3-rc13'
|
||||||
ext.kotlinx_io_version = '0.1.0-alpha-15-rc13'
|
ext.kotlinx_io_version = '0.1.0-alpha-24-rc13'
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
maven {
|
maven {
|
||||||
@ -12,26 +12,25 @@ buildscript {
|
|||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$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 {
|
allprojects {
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
apply plugin: "com.jfrog.artifactory"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url = "http://dl.bintray.com/kotlin/kotlin-eap" }
|
maven { url = "http://dl.bintray.com/kotlin/kotlin-eap" }
|
||||||
maven { url = "https://kotlin.bintray.com/kotlinx" }
|
maven { url = "https://kotlin.bintray.com/kotlinx" }
|
||||||
//maven { url 'https://jitpack.io' }
|
//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 {
|
plugins {
|
||||||
id 'kotlin-multiplatform'// version '1.3.0-rc-57'
|
id 'kotlin-multiplatform'
|
||||||
id 'kotlinx-serialization'
|
id 'kotlinx-serialization'
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
@ -18,45 +18,28 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":dataforge-meta")
|
api project(":dataforge-meta")
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-common"
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-reflect'
|
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-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 {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
implementation 'com.github.cliftonlabs:json-simple:3.0.2'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version"
|
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmTest {
|
jvmTest {}
|
||||||
dependencies {
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test'
|
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jsMain {
|
jsMain {
|
||||||
dependencies {
|
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-serialization-runtime-js:$serialization_version"
|
||||||
|
implementation "org.jetbrains.kotlinx:kotlinx-io-js:$kotlinx_io_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
jsTest {}
|
||||||
// iosMain {
|
// iosMain {
|
||||||
// }
|
// }
|
||||||
// iosTest {
|
// iosTest {
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package hep.dataforge.meta.io
|
package hep.dataforge.meta.io
|
||||||
|
|
||||||
import hep.dataforge.meta.Meta
|
import hep.dataforge.meta.*
|
||||||
import kotlinx.io.core.Input
|
import kotlinx.io.core.Input
|
||||||
import kotlinx.io.core.Output
|
import kotlinx.io.core.Output
|
||||||
|
import kotlinx.io.core.readText
|
||||||
|
import kotlinx.io.core.writeText
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A format for meta serialization
|
* A format for meta serialization
|
||||||
*/
|
*/
|
||||||
interface MetaFormat {
|
interface MetaFormat {
|
||||||
val name : String
|
val name: String
|
||||||
val key : Short
|
val key: Short
|
||||||
|
|
||||||
suspend fun write(meta: Meta, out: Output)
|
suspend fun write(meta: Meta, out: Output)
|
||||||
suspend fun read(input: Input): Meta
|
suspend fun read(input: Input): Meta
|
||||||
@ -23,4 +25,149 @@ interface MetaFormat {
|
|||||||
///**
|
///**
|
||||||
// * Resolve format by its binary key. Null if not provided
|
// * Resolve format by its binary key. Null if not provided
|
||||||
// */
|
// */
|
||||||
//expect fun resolveFormat(key: Short): MetaFormat?
|
//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*/
|
/*Direct JSON serialization*/
|
||||||
|
|
||||||
fun Value.toJson(): JsonElement = if (isList()) {
|
//fun Value.toJson(): JsonElement = if (isList()) {
|
||||||
JsonArray(list.map { it.toJson() })
|
// JsonArray(list.map { it.toJson() })
|
||||||
} else {
|
//} else {
|
||||||
when (type) {
|
// when (type) {
|
||||||
ValueType.NUMBER -> JsonPrimitive(number)
|
// ValueType.NUMBER -> JsonPrimitive(number)
|
||||||
ValueType.STRING -> JsonPrimitive(string)
|
// ValueType.STRING -> JsonPrimitive(string)
|
||||||
ValueType.BOOLEAN -> JsonPrimitive(boolean)
|
// ValueType.BOOLEAN -> JsonPrimitive(boolean)
|
||||||
ValueType.NULL -> JsonNull
|
// ValueType.NULL -> JsonNull
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fun Meta.toJSON(): JsonObject {
|
//fun Meta.toJSON(): JsonObject {
|
||||||
val map = this.items.mapValues { (_, value) ->
|
// val map = this.items.mapValues { (_, value) ->
|
||||||
when (value) {
|
// when (value) {
|
||||||
is MetaItem.ValueItem -> value.value.toJson()
|
// is MetaItem.ValueItem -> value.value.toJson()
|
||||||
is MetaItem.SingleNodeItem -> value.node.toJSON()
|
// is MetaItem.SingleNodeItem -> value.node.toJSON()
|
||||||
is MetaItem.MultiNodeItem -> JsonArray(value.nodes.map { it.toJSON() })
|
// is MetaItem.MultiNodeItem -> JsonArray(value.nodes.map { it.toJSON() })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return JsonObject(map)
|
// return JsonObject(map)
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fun JsonPrimitive.toValue(): Value {
|
//fun JsonPrimitive.toValue(): Value {
|
||||||
return when (this) {
|
// return when (this) {
|
||||||
is JsonLiteral -> LazyParsedValue(content)
|
// is JsonLiteral -> LazyParsedValue(content)
|
||||||
is JsonNull -> Null
|
// is JsonNull -> Null
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fun JsonObject.toMeta(): Meta {
|
//fun JsonObject.toMeta(): Meta {
|
||||||
return buildMeta {
|
// return buildMeta {
|
||||||
this@toMeta.forEach { (key, value) ->
|
// this@toMeta.forEach { (key, value) ->
|
||||||
when (value) {
|
// when (value) {
|
||||||
is JsonPrimitive -> set(key, value.toValue())
|
// is JsonPrimitive -> set(key, value.toValue())
|
||||||
is JsonObject -> set(key, value.toMeta())
|
// is JsonObject -> set(key, value.toMeta())
|
||||||
is JsonArray -> if (value.all { it is JsonPrimitive }) {
|
// is JsonArray -> if (value.all { it is JsonPrimitive }) {
|
||||||
set(key, ListValue(value.map { (it as JsonPrimitive).toValue() }))
|
// set(key, ListValue(value.map { (it as JsonPrimitive).toValue() }))
|
||||||
} else {
|
// } else {
|
||||||
set(
|
// set(
|
||||||
key,
|
// key,
|
||||||
value.map {
|
// value.map {
|
||||||
if (it is JsonObject) {
|
// if (it is JsonObject) {
|
||||||
it.toMeta()
|
// it.toMeta()
|
||||||
} else {
|
// } else {
|
||||||
buildMeta { "@value" to it.primitive.toValue() }
|
// buildMeta { "@value" to it.primitive.toValue() }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
/*Direct CBOR serialization*/
|
/*Direct CBOR serialization*/
|
||||||
|
|
||||||
@ -67,45 +67,6 @@ fun JsonObject.toMeta(): Meta {
|
|||||||
// encodeNumber(char.toByte().toLong())
|
// 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) {
|
// fun CBOR.CBOREncoder.encodeMeta(meta: Meta) {
|
||||||
// meta.items.forEach { (key, item) ->
|
// 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 {
|
plugins {
|
||||||
id 'kotlin-multiplatform'// version '1.3.0-rc-57'
|
id 'kotlin-multiplatform'
|
||||||
id 'kotlinx-serialization'
|
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' }
|
maven { url = 'http://dl.bintray.com/kotlin/kotlin-eap' }
|
||||||
@ -18,41 +17,35 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-common"
|
api "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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
commonTest {
|
commonTest {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test-common'
|
api 'org.jetbrains.kotlin:kotlin-test-common'
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
|
api 'org.jetbrains.kotlin:kotlin-test-annotations-common'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serialization_version"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serialization_version"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jvmTest {
|
jvmTest {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test'
|
api 'org.jetbrains.kotlin:kotlin-test'
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
|
api 'org.jetbrains.kotlin:kotlin-test-junit'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsMain {
|
jsMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
|
api 'org.jetbrains.kotlin:kotlin-stdlib-js'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsTest {
|
jsTest {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.jetbrains.kotlin:kotlin-test-js'
|
api 'org.jetbrains.kotlin:kotlin-test-js'
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serialization_version"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// iosMain {
|
// iosMain {
|
||||||
|
@ -10,34 +10,9 @@ import hep.dataforge.names.toName
|
|||||||
* * a list of nodes
|
* * a list of nodes
|
||||||
*/
|
*/
|
||||||
sealed class MetaItem<M : Meta> {
|
sealed class MetaItem<M : Meta> {
|
||||||
class ValueItem<M : Meta>(val value: Value) : MetaItem<M>(){
|
data class ValueItem<M : Meta>(val value: Value) : MetaItem<M>()
|
||||||
override fun equals(other: Any?): Boolean {
|
data class SingleNodeItem<M : Meta>(val node: M) : MetaItem<M>()
|
||||||
return this.value == (other as? ValueItem<*>)?.value
|
data class MultiNodeItem<M : Meta>(val nodes: List<M>) : MetaItem<M>()
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <M : Meta> List<M>.get(query: String): 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"
|
||||||
include ":dataforge-meta-io"
|
include ":dataforge-meta-io"
|
||||||
|
//include ":dataforge-envelope"
|
||||||
include ":dataforge-envelope"
|
|
Loading…
Reference in New Issue
Block a user