Meta serialization update
This commit is contained in:
parent
c82eda28d8
commit
a729d27d1c
@ -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) ->
|
||||||
|
@ -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>>()
|
||||||
|
@ -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 {
|
||||||
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user