Implement YamlMetaFormat with yaml.kt
This commit is contained in:
parent
47d49d1e0e
commit
4c98d62e8f
@ -1,16 +1,24 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("ru.mipt.npm.jvm")
|
id("ru.mipt.npm.mpp")
|
||||||
}
|
}
|
||||||
|
|
||||||
description = "YAML meta IO"
|
description = "YAML meta IO"
|
||||||
|
|
||||||
kscience {
|
repositories{
|
||||||
useSerialization {
|
jcenter()
|
||||||
yaml()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kscience {
|
||||||
|
useSerialization()
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
sourceSets {
|
||||||
|
jvmMain{
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":dataforge-io"))
|
api(project(":dataforge-io"))
|
||||||
api("org.yaml:snakeyaml:1.26")
|
api("net.mamoe.yamlkt:yamlkt:${ru.mipt.npm.gradle.KScienceVersions.Serialization.yamlKtVersion}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public class FrontMatterEnvelopeFormat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public companion object : EnvelopeFormatFactory {
|
public companion object : EnvelopeFormatFactory {
|
||||||
public const val SEPARATOR = "---"
|
public const val SEPARATOR: String = "---"
|
||||||
|
|
||||||
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
|
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
|
||||||
|
|
@ -0,0 +1,122 @@
|
|||||||
|
package hep.dataforge.io.yaml
|
||||||
|
|
||||||
|
import hep.dataforge.context.Context
|
||||||
|
import hep.dataforge.io.IOFormat.Companion.META_KEY
|
||||||
|
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
|
||||||
|
import hep.dataforge.io.MetaFormat
|
||||||
|
import hep.dataforge.io.MetaFormatFactory
|
||||||
|
import hep.dataforge.meta.*
|
||||||
|
import hep.dataforge.meta.descriptors.ItemDescriptor
|
||||||
|
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||||
|
import hep.dataforge.names.NameToken
|
||||||
|
import hep.dataforge.names.withIndex
|
||||||
|
import hep.dataforge.values.ListValue
|
||||||
|
import hep.dataforge.values.Null
|
||||||
|
import hep.dataforge.values.parseValue
|
||||||
|
import kotlinx.io.Input
|
||||||
|
import kotlinx.io.Output
|
||||||
|
import kotlinx.io.text.readUtf8String
|
||||||
|
import kotlinx.io.text.writeUtf8String
|
||||||
|
import net.mamoe.yamlkt.*
|
||||||
|
|
||||||
|
public fun Meta.toYaml(): YamlMap {
|
||||||
|
val map: Map<String, Any?> = items.entries.associate { (key, item) ->
|
||||||
|
key.toString() to when (item) {
|
||||||
|
is MetaItem.ValueItem -> {
|
||||||
|
item.value.value
|
||||||
|
}
|
||||||
|
is MetaItem.NodeItem -> {
|
||||||
|
item.node.toYaml()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return YamlMap(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class YamlMeta(private val yamlMap: YamlMap, private val descriptor: NodeDescriptor? = null) : MetaBase() {
|
||||||
|
|
||||||
|
private fun buildItems(): Map<NameToken, MetaItem<*>> {
|
||||||
|
val map = LinkedHashMap<NameToken, MetaItem<*>>()
|
||||||
|
|
||||||
|
yamlMap.content.entries.forEach { (key, value) ->
|
||||||
|
val stringKey = key.toString()
|
||||||
|
val itemDescriptor = descriptor?.items?.get(stringKey)
|
||||||
|
val token = NameToken(stringKey)
|
||||||
|
when (value) {
|
||||||
|
YamlNull -> Null.asMetaItem()
|
||||||
|
is YamlLiteral -> map[token] = value.content.parseValue().asMetaItem()
|
||||||
|
is YamlMap -> map[token] = value.toMeta().asMetaItem()
|
||||||
|
is YamlList -> if (value.all { it is YamlLiteral }) {
|
||||||
|
val listValue = ListValue(
|
||||||
|
value.map {
|
||||||
|
//We already checked that all values are primitives
|
||||||
|
(it as YamlLiteral).content.parseValue()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
map[token] = MetaItem.ValueItem(listValue)
|
||||||
|
} else value.forEachIndexed { index, yamlElement ->
|
||||||
|
val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: ItemDescriptor.DEFAULT_INDEX_KEY
|
||||||
|
val indexValue: String = (yamlElement as? YamlMap)?.getStringOrNull(indexKey)
|
||||||
|
?: index.toString() //In case index is non-string, the backward transformation will be broken.
|
||||||
|
|
||||||
|
val tokenWithIndex = token.withIndex(indexValue)
|
||||||
|
map[tokenWithIndex] = yamlElement.toMetaItem(itemDescriptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
override val items: Map<NameToken, MetaItem<*>> get() = buildItems()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun YamlElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<*> = when (this) {
|
||||||
|
YamlNull -> Null.asMetaItem()
|
||||||
|
is YamlLiteral -> content.parseValue().asMetaItem()
|
||||||
|
is YamlMap -> toMeta().asMetaItem()
|
||||||
|
//We can't return multiple items therefore we create top level node
|
||||||
|
is YamlList -> YamlMap(mapOf("@yamlArray" to this)).toMetaItem(descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun YamlMap.toMeta(): Meta = YamlMeta(this)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represent meta as Yaml
|
||||||
|
*/
|
||||||
|
@DFExperimental
|
||||||
|
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
|
||||||
|
private val coder = Yaml.default
|
||||||
|
|
||||||
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
|
||||||
|
val yaml = meta.toYaml()
|
||||||
|
val string = coder.encodeToString(yaml)
|
||||||
|
output.writeUtf8String(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
||||||
|
val yaml = coder.decodeYamlMapFromString(input.readUtf8String())
|
||||||
|
return yaml.toMeta()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toMeta(): Meta = Meta {
|
||||||
|
NAME_KEY put FrontMatterEnvelopeFormat.name.toString()
|
||||||
|
META_KEY put meta
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object : MetaFormatFactory {
|
||||||
|
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
|
||||||
|
|
||||||
|
override val shortName: String = "yaml"
|
||||||
|
|
||||||
|
override val key: Short = 0x594d //YM
|
||||||
|
|
||||||
|
private val default = YamlMetaFormat()
|
||||||
|
|
||||||
|
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
||||||
|
default.writeMeta(output, meta, descriptor)
|
||||||
|
|
||||||
|
override fun readMeta(input: kotlinx.io.Input, descriptor: NodeDescriptor?): Meta =
|
||||||
|
default.readMeta(input, descriptor)
|
||||||
|
}
|
||||||
|
}
|
@ -1,56 +0,0 @@
|
|||||||
package hep.dataforge.io.yaml
|
|
||||||
|
|
||||||
import hep.dataforge.context.Context
|
|
||||||
import hep.dataforge.io.IOFormat.Companion.META_KEY
|
|
||||||
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
|
|
||||||
import hep.dataforge.io.MetaFormat
|
|
||||||
import hep.dataforge.io.MetaFormatFactory
|
|
||||||
import hep.dataforge.meta.DFExperimental
|
|
||||||
import hep.dataforge.meta.Meta
|
|
||||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
|
||||||
import hep.dataforge.meta.toMap
|
|
||||||
import hep.dataforge.meta.toMeta
|
|
||||||
import kotlinx.io.Input
|
|
||||||
import kotlinx.io.Output
|
|
||||||
import kotlinx.io.asInputStream
|
|
||||||
import kotlinx.io.text.writeUtf8String
|
|
||||||
import org.yaml.snakeyaml.Yaml
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represent meta as Yaml
|
|
||||||
*/
|
|
||||||
@DFExperimental
|
|
||||||
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
|
|
||||||
private val yaml = Yaml()
|
|
||||||
|
|
||||||
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
|
|
||||||
val string = yaml.dump(meta.toMap(descriptor))
|
|
||||||
output.writeUtf8String(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
|
|
||||||
val map: Map<String, Any?> = yaml.load(input.asInputStream())
|
|
||||||
return map.toMeta(descriptor)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toMeta(): Meta = Meta{
|
|
||||||
NAME_KEY put FrontMatterEnvelopeFormat.name.toString()
|
|
||||||
META_KEY put meta
|
|
||||||
}
|
|
||||||
|
|
||||||
public companion object : MetaFormatFactory {
|
|
||||||
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
|
|
||||||
|
|
||||||
override val shortName: String = "yaml"
|
|
||||||
|
|
||||||
override val key: Short = 0x594d //YM
|
|
||||||
|
|
||||||
private val default = YamlMetaFormat()
|
|
||||||
|
|
||||||
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
|
|
||||||
default.writeMeta(output, meta, descriptor)
|
|
||||||
|
|
||||||
override fun readMeta(input: kotlinx.io.Input, descriptor: NodeDescriptor?): Meta =
|
|
||||||
default.readMeta(input, descriptor)
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,7 @@ public object MetaItemSerializer : KSerializer<MetaItem<*>> {
|
|||||||
@OptIn(InternalSerializationApi::class)
|
@OptIn(InternalSerializationApi::class)
|
||||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
|
||||||
element<Boolean>("isNode")
|
element<Boolean>("isNode")
|
||||||
element("content", buildSerialDescriptor("MetaItem.content", PolymorphicKind.SEALED))
|
element("content", buildSerialDescriptor("MetaItem.content", SerialKind.CONTEXTUAL))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserialize(decoder: Decoder): MetaItem<*> {
|
override fun deserialize(decoder: Decoder): MetaItem<*> {
|
||||||
|
Loading…
Reference in New Issue
Block a user