From 8a8484172c99093f0b45e9efc5101678614d655a Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 8 Sep 2020 16:04:15 +0300 Subject: [PATCH] Fix IO after refactoring --- .../io/yaml/FrontMatterEnvelopeFormat.kt | 10 +- .../kotlin/hep/dataforge/io/IOFormat.kt | 2 +- .../kotlin/hep/dataforge/io/JsonMetaFormat.kt | 6 +- .../hep/dataforge/io/TaggedEnvelopeFormat.kt | 29 ++--- .../hep/dataforge/io/TaglessEnvelopeFormat.kt | 24 ++-- .../hep/dataforge/io/EnvelopeFormatTest.kt | 8 +- .../hep/dataforge/io/MetaSerializerTest.kt | 8 +- .../kotlin/hep/dataforge/io/ioTestUtils.kt | 4 +- .../jvmMain/kotlin/hep/dataforge/io/fileIO.kt | 19 +-- .../dataforge/io/tcp/EnvelopeServerTest.kt | 4 +- .../kotlin/hep/dataforge/meta/JsonMeta.kt | 5 +- .../kotlin/hep/dataforge/meta/Scheme.kt | 29 +++-- .../hep/dataforge/meta/Specification.kt | 7 -- .../dataforge/meta/descriptors/Described.kt | 8 +- .../meta/descriptors/DescriptorMeta.kt | 36 ++++-- .../meta/descriptors/ItemDescriptor.kt | 115 +++++++++--------- .../meta/descriptors/DescriptorTest.kt | 2 +- .../hep/dataforge/meta/serialization.kt | 6 - 18 files changed, 165 insertions(+), 157 deletions(-) delete mode 100644 dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/serialization.kt diff --git a/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt b/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt index 76d1b152..0fc1d68a 100644 --- a/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt +++ b/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/FrontMatterEnvelopeFormat.kt @@ -105,11 +105,13 @@ class FrontMatterEnvelopeFormat( override fun readPartial(input: Input): PartialEnvelope = default.readPartial(input) - override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta): Unit = - default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } + override fun Output.writeEnvelope( + envelope: Envelope, + metaFormatFactory: MetaFormatFactory, + formatMeta: Meta, + ): Unit = default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } - override fun readObject(input: Input): Envelope = - default.readObject(input) + override fun readObject(input: Input): Envelope = default.readObject(input) } } \ No newline at end of file diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt index 281381d6..7fe4c970 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/IOFormat.kt @@ -30,7 +30,7 @@ public interface IOFormat : MetaRepr { } } -public fun Input.readWith(format: IOFormat): T = format.run { readObject(this@readWith) } +public fun Input.readWith(format: IOFormat): T = format.readObject(this@readWith) /** * Read given binary as object using given format diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt index aba20e9c..2be2fe51 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt @@ -12,7 +12,7 @@ import hep.dataforge.meta.toJson import hep.dataforge.meta.toMetaItem import kotlinx.io.Input import kotlinx.io.Output -import kotlinx.io.readByteArray +import kotlinx.io.text.readUtf8String import kotlinx.io.text.writeUtf8String import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject @@ -24,7 +24,7 @@ public class JsonMetaFormat(private val json: Json = DEFAULT_JSON) : MetaFormat override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) { val jsonObject = meta.toJson(descriptor) - output.writeUtf8String(this.json.encodeToString(JsonObject.serializer(), jsonObject)) + output.writeUtf8String(json.encodeToString(JsonObject.serializer(), jsonObject)) } override fun toMeta(): Meta = Meta { @@ -32,7 +32,7 @@ public class JsonMetaFormat(private val json: Json = DEFAULT_JSON) : MetaFormat } override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta { - val str = input.readByteArray().decodeToString() + val str = input.readUtf8String()//readByteArray().decodeToString() val jsonElement = json.parseToJsonElement(str) val item = jsonElement.toMetaItem(descriptor) return item.node ?: Meta.EMPTY diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaggedEnvelopeFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaggedEnvelopeFormat.kt index 19c58910..909ce756 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaggedEnvelopeFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaggedEnvelopeFormat.kt @@ -18,7 +18,7 @@ import kotlinx.io.* */ public class TaggedEnvelopeFormat( public val io: IOPlugin, - public val version: VERSION = VERSION.DF02 + public val version: VERSION = VERSION.DF02, ) : EnvelopeFormat { // private val metaFormat = io.metaFormat(metaFormatKey) @@ -67,11 +67,7 @@ public class TaggedEnvelopeFormat( val metaFormat = io.resolveMetaFormat(tag.metaFormatKey) ?: error("Meta format with key ${tag.metaFormatKey} not found") - val meta: Meta = input.limit(tag.metaSize.toInt()).run { - metaFormat.run { - readObject(input) - } - } + val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt())) val data = input.readBinary(tag.dataSize.toInt()) @@ -84,11 +80,8 @@ public class TaggedEnvelopeFormat( val metaFormat = io.resolveMetaFormat(tag.metaFormatKey) ?: error("Meta format with key ${tag.metaFormatKey} not found") - val meta: Meta = input.limit(tag.metaSize.toInt()).run { - metaFormat.run { - readObject(input) - } - } + val meta: Meta = metaFormat.readObject(input.limit(tag.metaSize.toInt())) + return PartialEnvelope(meta, version.tagSize + tag.metaSize, tag.dataSize) } @@ -96,7 +89,7 @@ public class TaggedEnvelopeFormat( private data class Tag( val metaFormatKey: Short, val metaSize: UInt, - val dataSize: ULong + val dataSize: ULong, ) public enum class VERSION(public val tagSize: UInt) { @@ -165,13 +158,13 @@ public class TaggedEnvelopeFormat( override fun readPartial(input: Input): PartialEnvelope = default.run { readPartial(input) } - override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta): Unit = - default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } - - override fun readObject(input: Input): Envelope = - default.run { readObject(input) } - + override fun Output.writeEnvelope( + envelope: Envelope, + metaFormatFactory: MetaFormatFactory, + formatMeta: Meta, + ): Unit = default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } + override fun readObject(input: Input): Envelope = default.readObject(input) } } \ No newline at end of file diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaglessEnvelopeFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaglessEnvelopeFormat.kt index 593e0a95..e0d76350 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaglessEnvelopeFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/TaglessEnvelopeFormat.kt @@ -20,7 +20,7 @@ import kotlin.collections.set */ public class TaglessEnvelopeFormat( public val io: IOPlugin, - public val meta: Meta = Meta.EMPTY + public val meta: Meta = Meta.EMPTY, ) : EnvelopeFormat { private val metaStart = meta[META_START_PROPERTY].string ?: DEFAULT_META_START @@ -85,13 +85,9 @@ public class TaglessEnvelopeFormat( val metaFormat = properties[META_TYPE_PROPERTY]?.let { io.resolveMetaFormat(it) } ?: JsonMetaFormat val metaSize = properties[META_LENGTH_PROPERTY]?.toInt() meta = if (metaSize != null) { - input.limit(metaSize).run { - metaFormat.run { readObject(input) } - } + metaFormat.readObject(input.limit(metaSize)) } else { - metaFormat.run { - readObject(input) - } + metaFormat.readObject(input) } } @@ -150,9 +146,7 @@ public class TaglessEnvelopeFormat( val metaSize = properties[META_LENGTH_PROPERTY]?.toInt() meta = if (metaSize != null) { offset += metaSize.toUInt() - input.limit(metaSize).run { - metaFormat.run { readObject(input) } - } + metaFormat.readObject(input.limit(metaSize)) } else { error("Can't partially read an envelope with undefined meta size") } @@ -203,11 +197,13 @@ public class TaglessEnvelopeFormat( override fun readPartial(input: Input): PartialEnvelope = default.run { readPartial(input) } - override fun Output.writeEnvelope(envelope: Envelope, metaFormatFactory: MetaFormatFactory, formatMeta: Meta): Unit = - default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } + override fun Output.writeEnvelope( + envelope: Envelope, + metaFormatFactory: MetaFormatFactory, + formatMeta: Meta, + ): Unit = default.run { writeEnvelope(envelope, metaFormatFactory, formatMeta) } - override fun readObject(input: Input): Envelope = - default.run { readObject(input) } + override fun readObject(input: Input): Envelope = default.readObject(input) override fun peekFormat(io: IOPlugin, input: Input): EnvelopeFormat? { return try { diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/EnvelopeFormatTest.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/EnvelopeFormatTest.kt index 0fd09abf..8bcc54cd 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/EnvelopeFormatTest.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/EnvelopeFormatTest.kt @@ -23,9 +23,9 @@ class EnvelopeFormatTest { @Test fun testTaggedFormat(){ TaggedEnvelopeFormat.run { - val byteArray = this.toByteArray(envelope) + val byteArray = writeToByteArray(envelope) //println(byteArray.decodeToString()) - val res = readByteArray(byteArray) + val res = readFromByteArray(byteArray) assertEquals(envelope.meta,res.meta) val double = res.data?.read { readDouble() @@ -37,9 +37,9 @@ class EnvelopeFormatTest { @Test fun testTaglessFormat(){ TaglessEnvelopeFormat.run { - val byteArray = toByteArray(envelope) + val byteArray = writeToByteArray(envelope) //println(byteArray.decodeToString()) - val res = readByteArray(byteArray) + val res = readFromByteArray(byteArray) assertEquals(envelope.meta,res.meta) val double = res.data?.read { readDouble() diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt index 75496d7b..64fd3d02 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MetaSerializerTest.kt @@ -1,13 +1,19 @@ package hep.dataforge.io -import hep.dataforge.meta.* +import hep.dataforge.meta.Meta +import hep.dataforge.meta.MetaItem +import hep.dataforge.meta.MetaSerializer import hep.dataforge.names.Name import hep.dataforge.names.toName import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.cbor.Cbor +import kotlinx.serialization.json.Json import kotlin.test.Test import kotlin.test.assertEquals +val JSON_PRETTY: Json = Json { prettyPrint = true; useArrayPolymorphism = true } +val JSON_PLAIN: Json = Json { prettyPrint = false; useArrayPolymorphism = true } + class MetaSerializerTest { val meta = Meta { "a" put 22 diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/ioTestUtils.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/ioTestUtils.kt index d27dc9da..55831f03 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/ioTestUtils.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/ioTestUtils.kt @@ -3,5 +3,5 @@ package hep.dataforge.io import kotlinx.io.ByteArrayInput import kotlinx.io.use -fun IOFormat.toByteArray(obj: T): ByteArray = buildByteArray { writeObject(this, obj) } -fun IOFormat.readByteArray(array: ByteArray): T = ByteArrayInput(array).use { readObject(it) } \ No newline at end of file +fun IOFormat.writeToByteArray(obj: T): ByteArray = buildByteArray { writeObject(this, obj) } +fun IOFormat.readFromByteArray(array: ByteArray): T = ByteArrayInput(array).use { readObject(it) } \ No newline at end of file diff --git a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt index 19c7a14d..3bf0e762 100644 --- a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt +++ b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt @@ -66,7 +66,11 @@ public inline fun IOPlugin.resolveIOFormat(): IOFormat? { * Read file containing meta using given [formatOverride] or file extension to infer meta type. * If [path] is a directory search for file starting with `meta` in it */ -public fun IOPlugin.readMetaFile(path: Path, formatOverride: MetaFormat? = null, descriptor: NodeDescriptor? = null): Meta { +public fun IOPlugin.readMetaFile( + path: Path, + formatOverride: MetaFormat? = null, + descriptor: NodeDescriptor? = null, +): Meta { if (!Files.exists(path)) error("Meta file $path does not exist") val actualPath: Path = if (Files.isDirectory(path)) { @@ -93,7 +97,7 @@ public fun IOPlugin.writeMetaFile( path: Path, meta: Meta, metaFormat: MetaFormatFactory = JsonMetaFormat, - descriptor: NodeDescriptor? = null + descriptor: NodeDescriptor? = null, ) { val actualPath = if (Files.isDirectory(path)) { path.resolve("@" + metaFormat.name.toString()) @@ -146,14 +150,15 @@ public val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data" public fun IOPlugin.readEnvelopeFile( path: Path, readNonEnvelopes: Boolean = false, - formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat + formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat, ): Envelope? { if (!Files.exists(path)) return null //read two-files directory if (Files.isDirectory(path)) { - val metaFile = Files.list(path).asSequence() - .singleOrNull { it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME) } + val metaFile = Files.list(path).asSequence().singleOrNull { + it.fileName.toString().startsWith(IOPlugin.META_FILE_NAME) + } val meta = if (metaFile == null) { Meta.EMPTY @@ -196,7 +201,7 @@ public fun IOPlugin.writeEnvelopeFile( path: Path, envelope: Envelope, envelopeFormat: EnvelopeFormat = TaggedEnvelopeFormat, - metaFormat: MetaFormatFactory? = null + metaFormat: MetaFormatFactory? = null, ) { path.rewrite { with(envelopeFormat) { @@ -212,7 +217,7 @@ public fun IOPlugin.writeEnvelopeFile( fun IOPlugin.writeEnvelopeDirectory( path: Path, envelope: Envelope, - metaFormat: MetaFormatFactory = JsonMetaFormat + metaFormat: MetaFormatFactory = JsonMetaFormat, ) { if (!Files.exists(path)) { Files.createDirectories(path) diff --git a/dataforge-io/src/jvmTest/kotlin/hep/dataforge/io/tcp/EnvelopeServerTest.kt b/dataforge-io/src/jvmTest/kotlin/hep/dataforge/io/tcp/EnvelopeServerTest.kt index 48c108d4..850136d5 100644 --- a/dataforge-io/src/jvmTest/kotlin/hep/dataforge/io/tcp/EnvelopeServerTest.kt +++ b/dataforge-io/src/jvmTest/kotlin/hep/dataforge/io/tcp/EnvelopeServerTest.kt @@ -4,7 +4,7 @@ import hep.dataforge.context.Global import hep.dataforge.io.Envelope import hep.dataforge.io.Responder import hep.dataforge.io.TaggedEnvelopeFormat -import hep.dataforge.io.toByteArray +import hep.dataforge.io.writeToByteArray import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.runBlocking import kotlinx.io.writeDouble @@ -18,7 +18,7 @@ import kotlin.time.ExperimentalTime @ExperimentalStdlibApi object EchoResponder : Responder { override suspend fun respond(request: Envelope): Envelope { - val string = TaggedEnvelopeFormat().run { toByteArray(request).decodeToString() } + val string = TaggedEnvelopeFormat().run { writeToByteArray(request).decodeToString() } println("ECHO:") println(string) return request diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt index debd05c8..2cabc8f1 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/JsonMeta.kt @@ -4,6 +4,7 @@ package hep.dataforge.meta import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY import hep.dataforge.meta.descriptors.ItemDescriptor +import hep.dataforge.meta.descriptors.ItemDescriptor.Companion.DEFAULT_INDEX_KEY import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.names.NameToken @@ -75,7 +76,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String if (indexValue != null) { - val indexKey = descriptor?.indexKey ?: NodeDescriptor.DEFAULT_INDEX_KEY + val indexKey = descriptor?.indexKey ?: DEFAULT_INDEX_KEY elementMap[indexKey] = JsonPrimitive(indexValue) } @@ -158,7 +159,7 @@ public class JsonMeta(private val json: JsonObject, private val descriptor: Node ) map[key] = MetaItem.ValueItem(listValue) } else value.forEachIndexed { index, jsonElement -> - val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: NodeDescriptor.DEFAULT_INDEX_KEY + val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: DEFAULT_INDEX_KEY val indexValue: String = (jsonElement as? JsonObject) ?.get(indexKey)?.jsonPrimitive?.contentOrNull ?: index.toString() //In case index is non-string, the backward transformation will be broken. diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt index 4adc696a..07709ab0 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt @@ -1,9 +1,12 @@ package hep.dataforge.meta -import hep.dataforge.meta.descriptors.* +import hep.dataforge.meta.descriptors.Described +import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.defaultItem +import hep.dataforge.meta.descriptors.get import hep.dataforge.names.Name import hep.dataforge.names.NameToken -import hep.dataforge.names.plus +import hep.dataforge.names.asName /** * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. @@ -30,21 +33,21 @@ public open class Scheme( * values if default value is unavailable. * Values from [defaultProvider] completely replace */ - public open val defaultLayer: Meta get() = DefaultLayer(Name.EMPTY) + public open val defaultLayer: Meta get() = DefaultLayer() override fun toMeta(): Laminate = Laminate(config, defaultLayer) - private inner class DefaultLayer(val path: Name) : MetaBase() { - override val items: Map> = - (descriptor?.get(path) as? NodeDescriptor)?.items?.entries?.associate { (key, descriptor) -> + private inner class DefaultLayer : MetaBase() { + override val items: Map> = buildMap { + descriptor?.items?.forEach { (key, itemDescriptor) -> val token = NameToken(key) - val fullName = path + token - val item: MetaItem<*> = when (descriptor) { - is ValueDescriptor -> getDefaultItem(fullName) ?: descriptor.defaultItem() - is NodeDescriptor -> MetaItem.NodeItem(DefaultLayer(fullName)) + val name = token.asName() + val item = defaultProvider.getItem(name) ?: itemDescriptor.defaultItem() + if (item != null) { + put(token, item) } - token to item - } ?: emptyMap() + } + } } } @@ -82,7 +85,7 @@ public open class MetaScheme( private val meta: Meta, override val descriptor: NodeDescriptor? = null, config: Config = Config(), -) : Scheme(config, meta::get) { +) : Scheme(config, meta) { override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node) } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt index b505ed8a..7988f0c1 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt @@ -23,12 +23,6 @@ public interface Specification { */ public fun Specification.update(config: Config, action: T.() -> Unit): T = wrap(config).apply(action) -/** - * Wrap a configuration using static meta as default - */ -public fun Specification.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T = - wrap(config, default) - /** * Wrap a configuration using static meta as default */ @@ -37,7 +31,6 @@ public fun Specification.wrap(source: Meta): T { return wrap(source.asConfig(), default) } - /** * Apply specified configuration to configurable */ diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt index ac8ba74a..4af17dfb 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt @@ -3,11 +3,11 @@ package hep.dataforge.meta.descriptors /** * An object which provides its descriptor */ -interface Described { - val descriptor: ItemDescriptor? +public interface Described { + public val descriptor: ItemDescriptor? - companion object { - const val DESCRIPTOR_NODE = "@descriptor" + public companion object { + //public const val DESCRIPTOR_NODE: String = "@descriptor" } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt index 47c90370..9a5b915d 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt @@ -1,32 +1,48 @@ package hep.dataforge.meta.descriptors import hep.dataforge.meta.Laminate +import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBase import hep.dataforge.meta.MetaItem import hep.dataforge.names.NameToken -import hep.dataforge.values.Null /** - * A [Meta] that wraps a descriptor node + * A [Meta] that is constructed from [NodeDescriptor] */ -class DescriptorMeta(val descriptor: NodeDescriptor) : MetaBase() { +private class DescriptorMeta(val descriptor: NodeDescriptor) : Meta, MetaBase() { override val items: Map> - get() = descriptor.items.entries.associate { entry -> - NameToken(entry.key) to entry.value.defaultItem() + get() = buildMap { + descriptor.items.forEach { (token, descriptorItem) -> + val item = descriptorItem.defaultItem() + if (item != null) { + put(NameToken(token), item) + } + } } } -fun NodeDescriptor.buildDefaultMeta() = Laminate(default, DescriptorMeta(this)) +/** + * Generate a laminate representing default item set generated by this descriptor + */ +public fun NodeDescriptor.defaultMeta(): Laminate = Laminate(default, DescriptorMeta(this)) -fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> = - MetaItem.NodeItem(buildDefaultMeta()) +/** + * Build a default [MetaItem.NodeItem] from this node descriptor + */ +internal fun NodeDescriptor.defaultItem(): MetaItem.NodeItem<*> = + MetaItem.NodeItem(defaultMeta()) -fun ValueDescriptor.defaultItem(): MetaItem.ValueItem = MetaItem.ValueItem(default ?: Null) +/** + * Build a default [MetaItem.ValueItem] from this descriptor + */ +internal fun ValueDescriptor.defaultItem(): MetaItem.ValueItem? { + return MetaItem.ValueItem(default ?: return null) +} /** * Build a default [MetaItem] from descriptor. */ -fun ItemDescriptor.defaultItem(): MetaItem<*> { +public fun ItemDescriptor.defaultItem(): MetaItem<*>? { return when (this) { is ValueDescriptor -> defaultItem() is NodeDescriptor -> defaultItem() diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index 338e1443..cbb56fa1 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -4,29 +4,26 @@ import hep.dataforge.meta.* import hep.dataforge.names.* import hep.dataforge.values.* +/** + * A common parent for [ValueDescriptor] and [NodeDescriptor]. Describes a single [MetaItem] or a group of same-name-siblings. + */ @DFBuilder -sealed class ItemDescriptor(val config: Config) { +public sealed class ItemDescriptor(public val config: Config) { /** * True if same name siblings with this name are allowed - * - * @return */ - var multiple: Boolean by config.boolean(false) + public var multiple: Boolean by config.boolean(false) /** - * The item description - * - * @return + * The item description text */ - var info: String? by config.string() + public var info: String? by config.string() /** * True if the item is required - * - * @return */ - abstract var required: Boolean + public abstract var required: Boolean /** @@ -34,29 +31,29 @@ sealed class ItemDescriptor(val config: Config) { * * @return */ - var attributes by config.node() -} + public var attributes: Config? by config.node() -/** - * Configure attributes of the descriptor - */ -fun ItemDescriptor.attributes(block: Config.() -> Unit) { - (attributes ?: Config().also { this.attributes = it }).apply(block) -} + /** + * An index field by which this node is identified in case of same name siblings construct + */ + public var indexKey: String by config.string(DEFAULT_INDEX_KEY) -/** - * Set specific attribute in the descriptor - */ -fun ItemDescriptor.setAttribute(name: Name, value: Any?) { - attributes { - set(name, value) + public companion object{ + public const val DEFAULT_INDEX_KEY: String = "@index" } } +/** + * Configure attributes of the descriptor, creating an attributes node if needed. + */ +public fun ItemDescriptor.attributes(block: Config.() -> Unit) { + (attributes ?: Config().also { this.attributes = it }).apply(block) +} + /** * Check if given item suits the descriptor */ -fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { +public fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { if (item == null) return !required return when (this) { is ValueDescriptor -> isAllowedValue(item.value ?: return false) @@ -73,7 +70,7 @@ fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { * @author Alexander Nozik */ @DFBuilder -class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { +public class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { init { config[IS_NODE_KEY] = true } @@ -90,14 +87,12 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { * * @return */ - var default by config.node() + public var default: Config? by config.node() /** - * An index field by which this node is identified in case of same name siblings construct + * The map of children item descriptors (both nodes and values) */ - var indexKey by config.string(DEFAULT_INDEX_KEY) - - val items: Map + public val items: Map get() = config.getIndexed(ITEM_KEY).mapValues { (_, item) -> val node = item.node ?: error("Node descriptor must be a node") if (node[IS_NODE_KEY].boolean == true) { @@ -111,7 +106,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { * The map of children node descriptors */ @Suppress("UNCHECKED_CAST") - val nodes: Map + public val nodes: Map get() = config.getIndexed(ITEM_KEY).entries.filter { it.value.node[IS_NODE_KEY].boolean == true }.associate { (name, item) -> @@ -120,9 +115,9 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { } /** - * The list of value descriptors + * The list of children value descriptors */ - val values: Map + public val values: Map get() = config.getIndexed(ITEM_KEY).entries.filter { it.value.node[IS_NODE_KEY].boolean != true }.associate { (name, item) -> @@ -154,39 +149,43 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { config[token] = descriptor.config } - fun item(name: Name, descriptor: ItemDescriptor) { + public fun item(name: Name, descriptor: ItemDescriptor) { buildNode(name.cutLast()).newItem(name.lastOrNull().toString(), descriptor) } - fun item(name: String, descriptor: ItemDescriptor) { + public fun item(name: String, descriptor: ItemDescriptor) { item(name.toName(), descriptor) } - fun node(name: Name, block: NodeDescriptor.() -> Unit) { + /** + * Create and configure a child node descriptor + */ + public fun node(name: Name, block: NodeDescriptor.() -> Unit) { item(name, NodeDescriptor().apply(block)) } - fun node(name: String, block: NodeDescriptor.() -> Unit) { + public fun node(name: String, block: NodeDescriptor.() -> Unit) { node(name.toName(), block) } - fun value(name: Name, block: ValueDescriptor.() -> Unit) { + /** + * Create and configure child value descriptor + */ + public fun value(name: Name, block: ValueDescriptor.() -> Unit) { require(name.length >= 1) { "Name length for value descriptor must be non-empty" } item(name, ValueDescriptor().apply(block)) } - fun value(name: String, block: ValueDescriptor.() -> Unit) { + public fun value(name: String, block: ValueDescriptor.() -> Unit) { value(name.toName(), block) } - companion object { + public companion object { - val ITEM_KEY = "item".asName() - val IS_NODE_KEY = "@isNode".asName() + internal val ITEM_KEY: Name = "item".asName() + internal val IS_NODE_KEY: Name = "@isNode".asName() - const val DEFAULT_INDEX_KEY = "@index" - - inline operator fun invoke(block: NodeDescriptor.() -> Unit) = NodeDescriptor().apply(block) + public inline operator fun invoke(block: NodeDescriptor.() -> Unit): NodeDescriptor = NodeDescriptor().apply(block) //TODO infer descriptor from spec } @@ -195,7 +194,7 @@ class NodeDescriptor(config: Config = Config()) : ItemDescriptor(config) { /** * Get a descriptor item associated with given name or null if item for given name not provided */ -operator fun ItemDescriptor.get(name: Name): ItemDescriptor? { +public operator fun ItemDescriptor.get(name: Name): ItemDescriptor? { if (name.isEmpty()) return this return when (this) { is ValueDescriptor -> null // empty name already checked @@ -203,7 +202,7 @@ operator fun ItemDescriptor.get(name: Name): ItemDescriptor? { } } -operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName()) +public operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName()) /** * A descriptor for meta value @@ -213,7 +212,7 @@ operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName * @author Alexander Nozik */ @DFBuilder -class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { +public class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { /** * True if the value is required @@ -227,9 +226,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * * @return */ - var default: Value? by config.value() + public var default: Value? by config.value() - fun default(v: Any) { + public fun default(v: Any) { this.default = Value.of(v) } @@ -238,9 +237,9 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * * @return */ - var type: List? by config.listValue { ValueType.valueOf(it.string) } + public var type: List? by config.listValue { ValueType.valueOf(it.string) } - fun type(vararg t: ValueType) { + public fun type(vararg t: ValueType) { this.type = listOf(*t) } @@ -251,7 +250,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * @param value * @return */ - fun isAllowedValue(value: Value): Boolean { + public fun isAllowedValue(value: Value): Boolean { return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true) && (allowedValues.isEmpty() || allowedValues.contains(value)) } @@ -262,7 +261,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { * * @return */ - var allowedValues: List by config.item().convert( + public var allowedValues: List by config.item().convert( reader = { val value = it.value when { @@ -279,7 +278,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { /** * Allow given list of value and forbid others */ - fun allow(vararg v: Any) { + public fun allow(vararg v: Any) { this.allowedValues = v.map { Value.of(it) } } } @@ -287,7 +286,7 @@ class ValueDescriptor(config: Config = Config()) : ItemDescriptor(config) { /** * Merge two node descriptors into one using first one as primary */ -operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor { +public operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor { return NodeDescriptor().apply { config.update(other.config) config.update(this@plus.config) diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt index 605cbebd..6d2c3ca5 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt @@ -36,7 +36,7 @@ class DescriptorTest { @Test fun testDefaultMetaNode(){ - val meta = descriptor.buildDefaultMeta() + val meta = descriptor.defaultMeta() assertEquals(false, meta["aNode.otherNode.otherValue"].boolean) } } \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/serialization.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/serialization.kt deleted file mode 100644 index ecbf8c7a..00000000 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/serialization.kt +++ /dev/null @@ -1,6 +0,0 @@ -package hep.dataforge.meta - -import kotlinx.serialization.json.Json - -public val JSON_PRETTY: Json = Json { prettyPrint = true; useArrayPolymorphism = true } -public val JSON_PLAIN: Json = Json { prettyPrint = false; useArrayPolymorphism = true } \ No newline at end of file