Front matter envelope format

This commit is contained in:
Alexander Nozik 2019-10-28 19:37:15 +03:00
parent 6cfaac74ae
commit 728da96eff
19 changed files with 254 additions and 75 deletions

View File

@ -0,0 +1,12 @@
plugins {
id("scientifik.jvm")
}
description = "YAML meta IO"
dependencies {
api(project(":dataforge-io"))
api("org.yaml:snakeyaml:1.25")
testImplementation(kotlin("test"))
testImplementation(kotlin("test-junit"))
}

View File

@ -0,0 +1,92 @@
package hep.dataforge.io.yaml
import hep.dataforge.context.Context
import hep.dataforge.io.*
import hep.dataforge.meta.EmptyMeta
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import kotlinx.io.core.*
import kotlinx.serialization.toUtf8Bytes
class FrontMatterEnvelopeFormat(
val io: IOPlugin,
val metaType: String = YamlMetaFormat.name.toString(),
meta: Meta = EmptyMeta
) : EnvelopeFormat {
val metaFormat = io.metaFormat(metaType, meta)
?: error("Meta format with type $metaType could not be resolved in $io")
override fun Input.readPartial(): PartialEnvelope {
var line: String = ""
var offset = 0u
do {
line = readUTF8Line() ?: error("Input does not contain front matter separator")
offset += line.toUtf8Bytes().size.toUInt()
} while (!line.startsWith(SEPARATOR))
val readMetaFormat =
metaTypeRegex.matchEntire(line)?.groupValues?.first()
?.let { io.metaFormat(it) } ?: YamlMetaFormat.default
val metaBlock = buildPacket {
do {
line = readUTF8Line() ?: error("Input does not contain closing front matter separator")
appendln(line)
offset += line.toUtf8Bytes().size.toUInt()
} while (!line.startsWith(SEPARATOR))
}
val meta = readMetaFormat.fromBytes(metaBlock)
return PartialEnvelope(meta, offset, null)
}
override fun Input.readObject(): Envelope {
var line: String = ""
do {
line = readUTF8Line() ?: error("Input does not contain front matter separator")
} while (!line.startsWith(SEPARATOR))
val readMetaFormat =
metaTypeRegex.matchEntire(line)?.groupValues?.first()
?.let { io.metaFormat(it) } ?: YamlMetaFormat.default
val metaBlock = buildPacket {
do {
appendln(readUTF8Line() ?: error("Input does not contain closing front matter separator"))
} while (!line.startsWith(SEPARATOR))
}
val meta = readMetaFormat.fromBytes(metaBlock)
val bytes = readBytes()
val data = bytes.asBinary()
return SimpleEnvelope(meta, data)
}
override fun Output.writeObject(obj: Envelope) {
writeText("$SEPARATOR\r\n")
metaFormat.run { writeObject(obj.meta) }
writeText("$SEPARATOR\r\n")
obj.data?.read { copyTo(this@writeObject) }
}
companion object : EnvelopeFormatFactory {
const val SEPARATOR = "---"
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()
override fun invoke(meta: Meta, context: Context): EnvelopeFormat {
val metaFormatName: String = meta["name"].string ?: YamlMetaFormat.name.toString()
return FrontMatterEnvelopeFormat(context.io, metaFormatName, meta)
}
override fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat? {
val line = input.readUTF8Line(3, 30)
return if (line != null && line.startsWith("---")) {
invoke()
} else {
null
}
}
}
}

View File

@ -0,0 +1,54 @@
package hep.dataforge.io.yaml
import hep.dataforge.context.Context
import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.io.MetaFormat
import hep.dataforge.io.MetaFormatFactory
import hep.dataforge.meta.Meta
import hep.dataforge.meta.toMap
import hep.dataforge.meta.toMeta
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import kotlinx.io.core.Input
import kotlinx.io.core.Output
import kotlinx.io.core.readUByte
import kotlinx.io.core.writeText
import org.yaml.snakeyaml.Yaml
import java.io.InputStream
private class InputAsStream(val input: Input) : InputStream() {
override fun read(): Int {
if (input.endOfInput) return -1
return input.readUByte().toInt()
}
override fun close() {
input.close()
}
}
private fun Input.asStream() = InputAsStream(this)
class YamlMetaFormat(val meta: Meta) : MetaFormat {
private val yaml = Yaml()
override fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor?) {
val string = yaml.dump(meta.toMap(descriptor))
writeText(string)
}
override fun Input.readMeta(descriptor: NodeDescriptor?): Meta {
val map: Map<String, Any?> = yaml.load(asStream())
return map.toMeta(descriptor)
}
companion object : MetaFormatFactory {
val default = YamlMetaFormat()
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
override val name: Name = super.name + "yaml"
override val key: Short = 0x594d //YM
}
}

View File

@ -0,0 +1,43 @@
package hep.dataforge.io.yaml
import hep.dataforge.io.parse
import hep.dataforge.io.toString
import hep.dataforge.meta.Meta
import hep.dataforge.meta.buildMeta
import hep.dataforge.meta.get
import hep.dataforge.meta.seal
import org.junit.Test
import kotlin.test.assertEquals
class YamlMetaFormatTest{
@Test
fun testYamlMetaFormat(){
val meta = buildMeta {
"a" to 22
"node" to {
"b" to "DDD"
"c" to 11.1
"d" to {
"d1" to {
"d11" to "aaa"
"d12" to "bbb"
}
"d2" to 2
}
"array" to doubleArrayOf(1.0, 2.0, 3.0)
}
}
val string = meta.toString(YamlMetaFormat)
println(string)
val result = YamlMetaFormat.parse(string)
assertEquals<Meta>(meta, meta.seal())
meta.items.keys.forEach {
if (meta[it] != result[it]) error("${meta[it]} != ${result[it]}")
}
assertEquals(meta, result)
}
}

View File

@ -76,13 +76,13 @@ fun ByteArray.asBinary() = ArrayBinary(this)
*/ */
fun <T : Any> Binary.readWith(format: IOFormat<T>): T = format.run { fun <T : Any> Binary.readWith(format: IOFormat<T>): T = format.run {
read { read {
readThis() readObject()
} }
} }
fun <T : Any> IOFormat<T>.writeBinary(obj: T): Binary { fun <T : Any> IOFormat<T>.writeBinary(obj: T): Binary {
val packet = buildPacket { val packet = buildPacket {
writeThis(obj) writeObject(obj)
} }
return ArrayBinary(packet.readBytes()) return ArrayBinary(packet.readBytes())
} }

View File

@ -85,7 +85,7 @@ object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
writeValue(item.value) writeValue(item.value)
} }
is MetaItem.NodeItem -> { is MetaItem.NodeItem -> {
writeThis(item.node) writeObject(item.node)
} }
} }
} }

View File

@ -20,9 +20,9 @@ data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: U
interface EnvelopeFormat : IOFormat<Envelope> { interface EnvelopeFormat : IOFormat<Envelope> {
fun Input.readPartial(): PartialEnvelope fun Input.readPartial(): PartialEnvelope
override fun Input.readThis(): Envelope override fun Input.readObject(): Envelope
override fun Output.writeThis(obj: Envelope) override fun Output.writeObject(obj: Envelope)
} }
@Type(ENVELOPE_FORMAT_TYPE) @Type(ENVELOPE_FORMAT_TYPE)

View File

@ -23,27 +23,27 @@ import kotlin.reflect.KClass
* And interface for reading and writing objects into with IO streams * And interface for reading and writing objects into with IO streams
*/ */
interface IOFormat<T : Any> { interface IOFormat<T : Any> {
fun Output.writeThis(obj: T) fun Output.writeObject(obj: T)
fun Input.readThis(): T fun Input.readObject(): T
} }
fun <T : Any> Input.readWith(format: IOFormat<T>): T = format.run { readThis() } fun <T : Any> Input.readWith(format: IOFormat<T>): T = format.run { readObject() }
fun <T : Any> Output.writeWith(format: IOFormat<T>, obj: T) = format.run { writeThis(obj) } fun <T : Any> Output.writeWith(format: IOFormat<T>, obj: T) = format.run { writeObject(obj) }
class ListIOFormat<T : Any>(val format: IOFormat<T>) : IOFormat<List<T>> { class ListIOFormat<T : Any>(val format: IOFormat<T>) : IOFormat<List<T>> {
override fun Output.writeThis(obj: List<T>) { override fun Output.writeObject(obj: List<T>) {
writeInt(obj.size) writeInt(obj.size)
format.run { format.run {
obj.forEach { obj.forEach {
writeThis(it) writeObject(it)
} }
} }
} }
override fun Input.readThis(): List<T> { override fun Input.readObject(): List<T> {
val size = readInt() val size = readInt()
return format.run { return format.run {
List(size) { readThis() } List(size) { readObject() }
} }
} }
} }
@ -79,32 +79,8 @@ inline fun buildPacketWithoutPool(headerSizeHint: Int = 0, block: BytePacketBuil
return builder.build() return builder.build()
} }
//@Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_OVERRIDE") fun <T : Any> IOFormat<T>.writePacket(obj: T): ByteReadPacket = buildPacket { writeObject(obj) }
//internal fun <R> Input.useAtMost(most: Int, reader: Input.() -> R): R { fun <T : Any> IOFormat<T>.writeBytes(obj: T): ByteArray = buildPacket { writeObject(obj) }.readBytes()
// val limitedInput: Input = object : AbstractInput(
// IoBuffer.Pool.borrow(),
// remaining = most.toLong(),
// pool = IoBuffer.Pool
// ) {
// var read = 0
// override fun closeSource() {
// this@useAtMost.close()
// }
//
// override fun fill(): IoBuffer? {
// if (read >= most) return null
// return IoBuffer.Pool.fill {
// reserveEndGap(IoBuffer.ReservedSize)
// read += this@useAtMost.peekTo(this, max = most - read)
// }
// }
//
// }
// return limitedInput.reader()
//}
fun <T : Any> IOFormat<T>.writePacket(obj: T): ByteReadPacket = buildPacket { writeThis(obj) }
fun <T : Any> IOFormat<T>.writeBytes(obj: T): ByteArray = buildPacket { writeThis(obj) }.readBytes()
fun <T : Any> IOFormat<T>.readBytes(array: ByteArray): T { fun <T : Any> IOFormat<T>.readBytes(array: ByteArray): T {
//= ByteReadPacket(array).readThis() //= ByteReadPacket(array).readThis()
val byteArrayInput: Input = object : AbstractInput( val byteArrayInput: Input = object : AbstractInput(
@ -129,7 +105,7 @@ fun <T : Any> IOFormat<T>.readBytes(array: ByteArray): T {
} }
} }
return byteArrayInput.readThis() return byteArrayInput.readObject()
} }
object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> { object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> {
@ -139,11 +115,11 @@ object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> {
override val type: KClass<out Double> get() = Double::class override val type: KClass<out Double> get() = Double::class
override fun Output.writeThis(obj: Double) { override fun Output.writeObject(obj: Double) {
writeDouble(obj) writeDouble(obj)
} }
override fun Input.readThis(): Double = readDouble() override fun Input.readObject(): Double = readDouble()
} }
object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> { object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> {
@ -153,11 +129,11 @@ object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> {
override val type: KClass<out Value> get() = Value::class override val type: KClass<out Value> get() = Value::class
override fun Output.writeThis(obj: Value) { override fun Output.writeObject(obj: Value) {
BinaryMetaFormat.run { writeValue(obj) } BinaryMetaFormat.run { writeValue(obj) }
} }
override fun Input.readThis(): Value { override fun Input.readObject(): Value {
return (BinaryMetaFormat.run { readMetaItem() } as? MetaItem.ValueItem)?.value return (BinaryMetaFormat.run { readMetaItem() } as? MetaItem.ValueItem)?.value
?: error("The item is not a value") ?: error("The item is not a value")
} }
@ -175,12 +151,12 @@ class SerializerIOFormat<T : Any>(
//override val name: Name = type.simpleName?.toName() ?: EmptyName //override val name: Name = type.simpleName?.toName() ?: EmptyName
override fun Output.writeThis(obj: T) { override fun Output.writeObject(obj: T) {
val bytes = Cbor.plain.dump(serializer, obj) val bytes = Cbor.plain.dump(serializer, obj)
writeFully(bytes) writeFully(bytes)
} }
override fun Input.readThis(): T { override fun Input.readObject(): T {
//FIXME reads the whole input //FIXME reads the whole input
val bytes = readBytes() val bytes = readBytes()
return Cbor.plain.load(serializer, bytes) return Cbor.plain.load(serializer, bytes)

View File

@ -16,11 +16,11 @@ import kotlin.reflect.KClass
interface MetaFormat : IOFormat<Meta> { interface MetaFormat : IOFormat<Meta> {
override fun Output.writeThis(obj: Meta) { override fun Output.writeObject(obj: Meta) {
writeMeta(obj, null) writeMeta(obj, null)
} }
override fun Input.readThis(): Meta = readMeta() override fun Input.readObject(): Meta = readMeta()
fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor? = null) fun Output.writeMeta(meta: Meta, descriptor: NodeDescriptor? = null)
fun Input.readMeta(descriptor: NodeDescriptor? = null): Meta fun Input.readMeta(descriptor: NodeDescriptor? = null): Meta
@ -42,23 +42,23 @@ interface MetaFormatFactory : IOFormatFactory<Meta> {
} }
fun Meta.toString(format: MetaFormat): String = buildPacket { fun Meta.toString(format: MetaFormat): String = buildPacket {
format.run { writeThis(this@toString) } format.run { writeObject(this@toString) }
}.readText() }.readText()
fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory()) fun Meta.toString(formatFactory: MetaFormatFactory): String = toString(formatFactory())
fun Meta.toBytes(format: MetaFormat = JsonMetaFormat.default): ByteReadPacket = buildPacket { fun Meta.toBytes(format: MetaFormat = JsonMetaFormat.default): ByteReadPacket = buildPacket {
format.run { writeThis(this@toBytes) } format.run { writeObject(this@toBytes) }
} }
fun MetaFormat.parse(str: String): Meta { fun MetaFormat.parse(str: String): Meta {
return ByteReadPacket(str.toByteArray()).readThis() return ByteReadPacket(str.toByteArray()).readObject()
} }
fun MetaFormatFactory.parse(str: String): Meta = invoke().parse(str) fun MetaFormatFactory.parse(str: String): Meta = invoke().parse(str)
fun MetaFormat.fromBytes(packet: ByteReadPacket): Meta { fun MetaFormat.fromBytes(packet: ByteReadPacket): Meta {
return packet.readThis() return packet.readObject()
} }

View File

@ -28,12 +28,12 @@ class TaggedEnvelopeFormat(
writeText(END_SEQUENCE) writeText(END_SEQUENCE)
} }
override fun Output.writeThis(obj: Envelope) { override fun Output.writeObject(obj: Envelope) {
val metaBytes = metaFormat.writeBytes(obj.meta) val metaBytes = metaFormat.writeBytes(obj.meta)
val tag = Tag(metaFormatKey, metaBytes.size.toUInt(), obj.data?.size ?: 0.toULong()) val tag = Tag(metaFormatKey, metaBytes.size.toUInt(), obj.data?.size ?: 0.toULong())
writePacket(tag.toBytes()) writePacket(tag.toBytes())
writeFully(metaBytes) writeFully(metaBytes)
obj.data?.read { copyTo(this@writeThis) } obj.data?.read { copyTo(this@writeObject) }
} }
/** /**
@ -42,7 +42,7 @@ class TaggedEnvelopeFormat(
* @param input an input to read from * @param input an input to read from
* @param formats a collection of meta formats to resolve * @param formats a collection of meta formats to resolve
*/ */
override fun Input.readThis(): Envelope { override fun Input.readObject(): Envelope {
val tag = readTag() val tag = readTag()
val metaFormat = io.metaFormat(tag.metaFormatKey) val metaFormat = io.metaFormat(tag.metaFormatKey)
@ -51,7 +51,7 @@ class TaggedEnvelopeFormat(
val metaPacket = ByteReadPacket(readBytes(tag.metaSize.toInt())) val metaPacket = ByteReadPacket(readBytes(tag.metaSize.toInt()))
val dataBytes = readBytes(tag.dataSize.toInt()) val dataBytes = readBytes(tag.dataSize.toInt())
val meta = metaFormat.run { metaPacket.readThis() } val meta = metaFormat.run { metaPacket.readObject() }
return SimpleEnvelope(meta, ArrayBinary(dataBytes)) return SimpleEnvelope(meta, ArrayBinary(dataBytes))
} }
@ -62,7 +62,7 @@ class TaggedEnvelopeFormat(
?: error("Meta format with key ${tag.metaFormatKey} not found") ?: error("Meta format with key ${tag.metaFormatKey} not found")
val metaPacket = ByteReadPacket(readBytes(tag.metaSize.toInt())) val metaPacket = ByteReadPacket(readBytes(tag.metaSize.toInt()))
val meta = metaFormat.run { metaPacket.readThis() } val meta = metaFormat.run { metaPacket.readObject() }
return PartialEnvelope(meta, TAG_SIZE + tag.metaSize, tag.dataSize) return PartialEnvelope(meta, TAG_SIZE + tag.metaSize, tag.dataSize)
} }

View File

@ -22,7 +22,7 @@ class TaglessEnvelopeFormat(
writeText("#? $key: $value;\r\n") writeText("#? $key: $value;\r\n")
} }
override fun Output.writeThis(obj: Envelope) { override fun Output.writeObject(obj: Envelope) {
//printing header //printing header
writeText(TAGLESS_ENVELOPE_HEADER + "\r\n") writeText(TAGLESS_ENVELOPE_HEADER + "\r\n")
@ -48,7 +48,7 @@ class TaglessEnvelopeFormat(
} }
} }
override fun Input.readThis(): Envelope { override fun Input.readObject(): Envelope {
var line: String = "" var line: String = ""
do { do {
line = readUTF8Line() ?: error("Input does not contain tagless envelope header") line = readUTF8Line() ?: error("Input does not contain tagless envelope header")
@ -73,10 +73,10 @@ class TaglessEnvelopeFormat(
val metaSize = properties.get(META_LENGTH_PROPERTY)?.toInt() val metaSize = properties.get(META_LENGTH_PROPERTY)?.toInt()
meta = if (metaSize != null) { meta = if (metaSize != null) {
val metaPacket = ByteReadPacket(readBytes(metaSize)) val metaPacket = ByteReadPacket(readBytes(metaSize))
metaFormat.run { metaPacket.readThis() } metaFormat.run { metaPacket.readObject() }
} else { } else {
metaFormat.run { metaFormat.run {
readThis() readObject()
} }
} }
} }
@ -128,7 +128,7 @@ class TaglessEnvelopeFormat(
meta = if (metaSize != null) { meta = if (metaSize != null) {
val metaPacket = ByteReadPacket(readBytes(metaSize)) val metaPacket = ByteReadPacket(readBytes(metaSize))
offset += metaSize.toUInt() offset += metaSize.toUInt()
metaFormat.run { metaPacket.readThis() } metaFormat.run { metaPacket.readObject() }
} else { } else {
error("Can't partially read an envelope with undefined meta size") error("Can't partially read an envelope with undefined meta size")
} }

View File

@ -20,7 +20,7 @@ class RemoteFunctionClient(override val context: Context, val responder: Respond
data { data {
val inputFormat: IOFormat<T> = getInputFormat(meta, valueType) val inputFormat: IOFormat<T> = getInputFormat(meta, valueType)
inputFormat.run { inputFormat.run {
writeThis(value) writeObject(value)
} }
} }
} }
@ -39,7 +39,7 @@ class RemoteFunctionClient(override val context: Context, val responder: Respond
val inputFormat: IOFormat<T> = getInputFormat(meta, valueType) val inputFormat: IOFormat<T> = getInputFormat(meta, valueType)
inputFormat.run { inputFormat.run {
values.forEach { values.forEach {
writeThis(it) writeObject(it)
} }
} }
} }
@ -56,7 +56,7 @@ class RemoteFunctionClient(override val context: Context, val responder: Respond
envelope.data?.read { envelope.data?.read {
List<R>(size) { List<R>(size) {
outputFormat.run { outputFormat.run {
readThis() readObject()
} }
} }
} ?: error("Message does not contain data") } ?: error("Message does not contain data")

View File

@ -30,7 +30,7 @@ class RemoteFunctionServer(
val input = request.data?.read { val input = request.data?.read {
inputFormat.run { inputFormat.run {
List(size) { List(size) {
readThis() readObject()
} }
} }
} ?: error("Input is empty") } ?: error("Input is empty")
@ -48,7 +48,7 @@ class RemoteFunctionServer(
data { data {
outputFormat.run { outputFormat.run {
output.forEach { output.forEach {
writeThis(it) writeObject(it)
} }
} }
} }

View File

@ -46,7 +46,7 @@ fun IOPlugin.writeEnvelopeFile(
).asOutput() ).asOutput()
with(formatFactory(formatMeta, context)) { with(formatFactory(formatMeta, context)) {
output.writeThis(envelope) output.writeObject(envelope)
} }
} }

View File

@ -56,10 +56,10 @@ class EnvelopeClient(
val output = socket.getOutputStream() val output = socket.getOutputStream()
format.run { format.run {
output.writePacket { output.writePacket {
writeThis(request) writeObject(request)
} }
logger.debug { "Sent request with type ${request.type} to ${socket.remoteSocketAddress}" } logger.debug { "Sent request with type ${request.type} to ${socket.remoteSocketAddress}" }
val res = input.readThis() val res = input.readObject()
logger.debug { "Received response with type ${res.type} from ${socket.remoteSocketAddress}" } logger.debug { "Received response with type ${res.type} from ${socket.remoteSocketAddress}" }
return@withContext res return@withContext res
} }

View File

@ -75,7 +75,7 @@ class EnvelopeServer(
val outputStream = socket.getOutputStream() val outputStream = socket.getOutputStream()
format.run { format.run {
while (socket.isConnected) { while (socket.isConnected) {
val request = input.readThis() val request = input.readObject()
logger.debug { "Accepted request with type ${request.type} from ${socket.remoteSocketAddress}" } logger.debug { "Accepted request with type ${request.type} from ${socket.remoteSocketAddress}" }
if (request.type == SHUTDOWN_ENVELOPE_TYPE) { if (request.type == SHUTDOWN_ENVELOPE_TYPE) {
//Echo shutdown command //Echo shutdown command
@ -87,7 +87,7 @@ class EnvelopeServer(
runBlocking { runBlocking {
val response = responder.respond(request) val response = responder.respond(request)
outputStream.writePacket { outputStream.writePacket {
writeThis(response) writeObject(response)
} }
logger.debug { "Sent response with type ${response.type} to ${socket.remoteSocketAddress}" } logger.debug { "Sent response with type ${response.type} to ${socket.remoteSocketAddress}" }
} }

View File

@ -1,5 +1,6 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.descriptors.NodeDescriptor
import hep.dataforge.values.Value import hep.dataforge.values.Value
///** ///**
@ -13,7 +14,7 @@ import hep.dataforge.values.Value
/** /**
* Convert meta to map of maps * Convert meta to map of maps
*/ */
fun Meta.toMap(): Map<String, Any?> { fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
return items.entries.associate { (token, item) -> return items.entries.associate { (token, item) ->
token.toString() to when (item) { token.toString() to when (item) {
is MetaItem.NodeItem -> item.node.toMap() is MetaItem.NodeItem -> item.node.toMap()
@ -25,7 +26,7 @@ fun Meta.toMap(): Map<String, Any?> {
/** /**
* Convert map of maps to meta * Convert map of maps to meta
*/ */
fun Map<String, Any?>.toMeta(): Meta = buildMeta { fun Map<String, Any?>.toMeta(descriptor: NodeDescriptor? = null): Meta = buildMeta {
entries.forEach { (key, value) -> entries.forEach { (key, value) ->
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
when (value) { when (value) {

View File

@ -63,7 +63,7 @@ fun <T : Any> IOPlugin.readData(
dataFormat.run { dataFormat.run {
Files.newByteChannel(path, StandardOpenOption.READ) Files.newByteChannel(path, StandardOpenOption.READ)
.asInput() .asInput()
.readThis() .readObject()
} }
} }
} }

View File

@ -24,6 +24,7 @@ enableFeaturePreview("GRADLE_METADATA")
include( include(
":dataforge-meta", ":dataforge-meta",
":dataforge-io", ":dataforge-io",
":dataforge-io:dataforge-io-yaml",
":dataforge-context", ":dataforge-context",
":dataforge-data", ":dataforge-data",
":dataforge-output", ":dataforge-output",