Implement YamlMetaFormat with yaml.kt
This commit is contained in:
parent
47d49d1e0e
commit
4c98d62e8f
@ -1,16 +1,24 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.jvm")
|
||||
id("ru.mipt.npm.mpp")
|
||||
}
|
||||
|
||||
description = "YAML meta IO"
|
||||
|
||||
kscience {
|
||||
useSerialization {
|
||||
yaml()
|
||||
}
|
||||
repositories{
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":dataforge-io"))
|
||||
api("org.yaml:snakeyaml:1.26")
|
||||
kscience {
|
||||
useSerialization()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
jvmMain{
|
||||
dependencies {
|
||||
api(project(":dataforge-io"))
|
||||
api("net.mamoe.yamlkt:yamlkt:${ru.mipt.npm.gradle.KScienceVersions.Serialization.yamlKtVersion}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class FrontMatterEnvelopeFormat(
|
||||
}
|
||||
|
||||
public companion object : EnvelopeFormatFactory {
|
||||
public const val SEPARATOR = "---"
|
||||
public const val SEPARATOR: String = "---"
|
||||
|
||||
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)
|
||||
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
|
||||
element<Boolean>("isNode")
|
||||
element("content", buildSerialDescriptor("MetaItem.content", PolymorphicKind.SEALED))
|
||||
element("content", buildSerialDescriptor("MetaItem.content", SerialKind.CONTEXTUAL))
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): MetaItem<*> {
|
||||
|
Loading…
Reference in New Issue
Block a user