Json serialization for JVM and Binary serialization in common

This commit is contained in:
Alexander Nozik 2018-10-26 14:10:41 +03:00
parent c1d004ec3e
commit 13a00d0d19
17 changed files with 432 additions and 305 deletions

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ out/
!gradle-wrapper.jar
artifactory.gradle

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +1,10 @@
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
@ -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")
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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? {

View File

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

View File

@ -28,5 +28,4 @@ rootProject.name = 'dataforge-core'
include ":dataforge-meta"
include ":dataforge-meta-io"
include ":dataforge-envelope"
//include ":dataforge-envelope"