Meta serialization update

This commit is contained in:
Alexander Nozik 2019-08-02 15:42:45 +03:00
parent c82eda28d8
commit a729d27d1c
5 changed files with 121 additions and 37 deletions

View File

@ -1,5 +1,6 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.meta.* import hep.dataforge.meta.*
import hep.dataforge.values.* import hep.dataforge.values.*
import kotlinx.io.core.Input import kotlinx.io.core.Input
@ -11,7 +12,7 @@ object BinaryMetaFormat : MetaFormat {
override val name: String = "bin" override val name: String = "bin"
override val key: Short = 0x4249//BI override val key: Short = 0x4249//BI
override fun Input.readObject(): Meta { override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
return (readMetaItem() as MetaItem.NodeItem).node return (readMetaItem() as MetaItem.NodeItem).node
} }
@ -69,7 +70,7 @@ object BinaryMetaFormat : MetaFormat {
} }
} }
override fun Output.writeObject(meta: Meta) { override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
writeChar('M') writeChar('M')
writeInt(meta.items.size) writeInt(meta.items.size)
meta.items.forEach { (key, item) -> meta.items.forEach { (key, item) ->

View File

@ -1,5 +1,8 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.descriptors.ItemDescriptor
import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.descriptors.ValueDescriptor
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem import hep.dataforge.meta.MetaItem
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
@ -10,6 +13,9 @@ import kotlinx.io.core.Output
import kotlinx.io.core.readText import kotlinx.io.core.readText
import kotlinx.io.core.writeText import kotlinx.io.core.writeText
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
object JsonMetaFormat : MetaFormat { object JsonMetaFormat : MetaFormat {
@ -17,12 +23,12 @@ object JsonMetaFormat : MetaFormat {
override val name: String = "json" override val name: String = "json"
override val key: Short = 0x4a53//"JS" override val key: Short = 0x4a53//"JS"
override fun Output.writeObject(obj: Meta) { override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
val str = obj.toJson().toString() val str = meta.toJson().toString()
writeText(str) writeText(str)
} }
override fun Input.readObject(): Meta { override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
val str = readText() val str = readText()
val json = Json.plain.parseJson(str) val json = Json.plain.parseJson(str)
@ -34,7 +40,7 @@ object JsonMetaFormat : MetaFormat {
} }
} }
fun Value.toJson(): JsonElement { fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
return if (isList()) { return if (isList()) {
JsonArray(list.map { it.toJson() }) JsonArray(list.map { it.toJson() })
} else { } else {
@ -47,22 +53,35 @@ fun Value.toJson(): JsonElement {
} }
} }
fun Meta.toJson(): JsonObject { //Use theese methods to customize JSON key mapping
val map = this.items.mapValues { entry -> private fun NameToken.toJsonKey(descriptor: ItemDescriptor?) = toString()
when (val value = entry.value) { private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)
is MetaItem.ValueItem -> value.value.toJson()
is MetaItem.NodeItem -> value.node.toJson() fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject {
//TODO search for same name siblings and arrange them into arrays
val map = this.items.entries.associate {(name,item)->
val itemDescriptor = descriptor?.items?.get(name.body)
val key = name.toJsonKey(itemDescriptor)
val value = when (item) {
is MetaItem.ValueItem -> {
item.value.toJson(itemDescriptor as? ValueDescriptor)
}
is MetaItem.NodeItem -> {
item.node.toJson(itemDescriptor as? NodeDescriptor)
}
}
key to value
} }
}.mapKeys { it.key.toString() }
return JsonObject(map) return JsonObject(map)
} }
fun JsonObject.toMeta() = JsonMeta(this) fun JsonObject.toMeta(descriptor: NodeDescriptor? = null) = JsonMeta(this, descriptor)
class JsonMeta(val json: JsonObject) : Meta { class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : Meta {
private fun JsonPrimitive.toValue(): Value { private fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
return when (this) { return when (this) {
JsonNull -> Null JsonNull -> Null
else -> this.content.parseValue() // Optimize number and boolean parsing else -> this.content.parseValue() // Optimize number and boolean parsing
@ -70,30 +89,45 @@ class JsonMeta(val json: JsonObject) : Meta {
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement) = when (value) { private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement): Unit {
is JsonPrimitive -> this[key] = MetaItem.ValueItem(value.toValue()) as MetaItem<JsonMeta> val itemDescriptor = descriptor.getDescriptor(key)
is JsonObject -> this[key] = MetaItem.NodeItem(value.toMeta()) //use name from descriptor in case descriptor name differs from json key
val name = itemDescriptor?.name ?: key
return when (value) {
is JsonPrimitive -> {
this[name] = MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor)) as MetaItem<JsonMeta>
}
is JsonObject -> {
this[name] = MetaItem.NodeItem(value.toMeta(itemDescriptor as? NodeDescriptor))
}
is JsonArray -> { is JsonArray -> {
when { when {
value.all { it is JsonPrimitive } -> { value.all { it is JsonPrimitive } -> {
val listValue = ListValue( val listValue = ListValue(
value.map { value.map {
//We already checked that all values are primitives //We already checked that all values are primitives
(it as JsonPrimitive).toValue() (it as JsonPrimitive).toValue(itemDescriptor as? ValueDescriptor)
} }
) )
this[key] = MetaItem.ValueItem(listValue) as MetaItem<JsonMeta> this[name] = MetaItem.ValueItem(listValue) as MetaItem<JsonMeta>
} }
else -> value.forEachIndexed { index, jsonElement -> else -> value.forEachIndexed { index, jsonElement ->
when (jsonElement) { when (jsonElement) {
is JsonObject -> this["$key[$index]"] = MetaItem.NodeItem(JsonMeta(jsonElement)) is JsonObject -> {
is JsonPrimitive -> this["$key[$index]"] = MetaItem.ValueItem(jsonElement.toValue()) as MetaItem<JsonMeta> this["$name[$index]"] =
MetaItem.NodeItem(jsonElement.toMeta(itemDescriptor as? NodeDescriptor))
}
is JsonPrimitive -> {
this["$name[$index]"] =
MetaItem.ValueItem(jsonElement.toValue(itemDescriptor as? ValueDescriptor))
}
is JsonArray -> TODO("Nested arrays not supported") is JsonArray -> TODO("Nested arrays not supported")
} }
} }
} }
} }
} }
}
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy { override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy {
val map = HashMap<String, MetaItem<JsonMeta>>() val map = HashMap<String, MetaItem<JsonMeta>>()

View File

@ -1,9 +1,8 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.*
import kotlinx.io.core.buildPacket
import kotlinx.io.core.toByteArray
/** /**
* A format for meta serialization * A format for meta serialization
@ -11,6 +10,15 @@ import kotlinx.io.core.toByteArray
interface MetaFormat : IOFormat<Meta> { interface MetaFormat : IOFormat<Meta> {
val name: String val name: String
val key: Short val key: Short
override fun Output.writeObject(obj: Meta) {
writeMeta(obj, null)
}
override fun Input.readObject(): Meta = readMeta(null)
fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?)
fun Input.readMeta(descriptor: NodeDescriptor?): Meta
} }
fun Meta.toString(format: MetaFormat = JsonMetaFormat): String = buildPacket { fun Meta.toString(format: MetaFormat = JsonMetaFormat): String = buildPacket {

View File

@ -0,0 +1,38 @@
package hep.dataforge.io
import hep.dataforge.meta.Config
import hep.dataforge.meta.Meta
import hep.dataforge.meta.toConfig
import kotlinx.serialization.Decoder
import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialDescriptor
import kotlinx.serialization.json.JsonObjectSerializer
/**
* Serialized for meta
*/
object MetaSerializer : KSerializer<Meta> {
override val descriptor: SerialDescriptor = JsonObjectSerializer.descriptor
override fun deserialize(decoder: Decoder): Meta {
//currently just delegates serialization to json serializer
return JsonObjectSerializer.deserialize(decoder).toMeta()
}
override fun serialize(encoder: Encoder, obj: Meta) {
JsonObjectSerializer.serialize(encoder, obj.toJson())
}
}
object ConfigSerializer: KSerializer<Config>{
override val descriptor: SerialDescriptor = JsonObjectSerializer.descriptor
override fun deserialize(decoder: Decoder): Config {
return JsonObjectSerializer.deserialize(decoder).toMeta().toConfig()
}
override fun serialize(encoder: Encoder, obj: Config) {
JsonObjectSerializer.serialize(encoder, obj.toJson())
}
}

View File

@ -39,6 +39,9 @@ interface MetaRepr {
* * Same name siblings are supported via elements with the same [Name] but different queries * * Same name siblings are supported via elements with the same [Name] but different queries
*/ */
interface Meta : MetaRepr { interface Meta : MetaRepr {
/**
* Top level items of meta tree
*/
val items: Map<NameToken, MetaItem<*>> val items: Map<NameToken, MetaItem<*>>
override fun toMeta(): Meta = this override fun toMeta(): Meta = this