Implements Envelope parts

An envelope consisting of other envelopes
This commit is contained in:
Alexander Nozik 2019-11-05 21:36:17 +03:00
parent f63a2b6e93
commit 5265c0e5ab
5 changed files with 135 additions and 33 deletions

View File

@ -1,11 +1,11 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.meta.* import hep.dataforge.meta.Laminate
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlinx.io.core.Output
import kotlinx.io.core.buildPacket
import kotlinx.io.core.readBytes
interface Envelope { interface Envelope {
val meta: Meta val meta: Meta
@ -83,32 +83,3 @@ fun Envelope.withMetaLayers(vararg layers: Meta): Envelope {
} }
} }
class EnvelopeBuilder {
private val metaBuilder = MetaBuilder()
var data: Binary? = null
fun meta(block: MetaBuilder.() -> Unit) {
metaBuilder.apply(block)
}
fun meta(meta: Meta) {
metaBuilder.update(meta)
}
var type by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
var dataType by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
var dataID by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
var description by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
/**
* Construct a binary and transform it into byte-array based buffer
*/
fun data(block: Output.() -> Unit) {
val bytes = buildPacket {
block()
}
data = ArrayBinary(bytes.readBytes())
}
internal fun build() = SimpleEnvelope(metaBuilder.seal(), data)
}

View File

@ -0,0 +1,36 @@
package hep.dataforge.io
import hep.dataforge.meta.*
import kotlinx.io.core.Output
import kotlinx.io.core.buildPacket
import kotlinx.io.core.readBytes
class EnvelopeBuilder {
private val metaBuilder = MetaBuilder()
var data: Binary? = null
fun meta(block: MetaBuilder.() -> Unit) {
metaBuilder.apply(block)
}
fun meta(meta: Meta) {
metaBuilder.update(meta)
}
var type by metaBuilder.string(key = Envelope.ENVELOPE_TYPE_KEY)
var dataType by metaBuilder.string(key = Envelope.ENVELOPE_DATA_TYPE_KEY)
var dataID by metaBuilder.string(key = Envelope.ENVELOPE_DATA_ID_KEY)
var description by metaBuilder.string(key = Envelope.ENVELOPE_DESCRIPTION_KEY)
/**
* Construct a binary and transform it into byte-array based buffer
*/
fun data(block: Output.() -> Unit) {
val bytes = buildPacket {
block()
}
data = ArrayBinary(bytes.readBytes())
}
internal fun build() = SimpleEnvelope(metaBuilder.seal(), data)
}

View File

@ -0,0 +1,60 @@
package hep.dataforge.io
import hep.dataforge.context.Global
import hep.dataforge.io.EnvelopeParts.FORMAT_META_KEY
import hep.dataforge.io.EnvelopeParts.FORMAT_NAME_KEY
import hep.dataforge.io.EnvelopeParts.PARTS_DATA_TYPE
import hep.dataforge.io.EnvelopeParts.SIZE_KEY
import hep.dataforge.meta.*
import hep.dataforge.names.plus
import hep.dataforge.names.toName
object EnvelopeParts {
val SIZE_KEY = Envelope.ENVELOPE_NODE_KEY + "parts" + "size"
val FORMAT_NAME_KEY = Envelope.ENVELOPE_NODE_KEY + "parts" + "format"
val FORMAT_META_KEY = Envelope.ENVELOPE_NODE_KEY + "parts" + "meta"
const val PARTS_DATA_TYPE = "envelope.parts"
}
fun EnvelopeBuilder.parts(formatFactory: EnvelopeFormatFactory, envelopes: Collection<Envelope>) {
dataType = PARTS_DATA_TYPE
meta {
SIZE_KEY put envelopes.size
FORMAT_NAME_KEY put formatFactory.name.toString()
}
val format = formatFactory()
data {
format.run {
envelopes.forEach {
writeObject(it)
}
}
}
}
fun EnvelopeBuilder.parts(formatFactory: EnvelopeFormatFactory, builder: suspend SequenceScope<Envelope>.() -> Unit) =
parts(formatFactory, sequence(builder).toList())
fun Envelope.parts(io: IOPlugin = Global.plugins.fetch(IOPlugin)): Sequence<Envelope> {
return when (dataType) {
PARTS_DATA_TYPE -> {
val size = meta[SIZE_KEY].int ?: error("Unsized parts not supported yet")
val formatName = meta[FORMAT_NAME_KEY].string?.toName()
?: error("Inferring parts format is not supported at the moment")
val formatMeta = meta[FORMAT_META_KEY].node ?: EmptyMeta
val format = io.envelopeFormat(formatName, formatMeta)
?: error("Format $formatName is not resolved by $io")
return format.run {
data?.read {
sequence {
repeat(size) {
yield(readObject())
}
}
} ?: emptySequence()
}
}
else -> emptySequence()
}
}

View File

@ -26,6 +26,9 @@ class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
context.content<EnvelopeFormatFactory>(ENVELOPE_FORMAT_TYPE).values context.content<EnvelopeFormatFactory>(ENVELOPE_FORMAT_TYPE).values
} }
fun envelopeFormat(name: Name, meta: Meta = EmptyMeta) =
envelopeFormatFactories.find { it.name == name }?.invoke(meta, context)
override fun provideTop(target: String): Map<Name, Any> { override fun provideTop(target: String): Map<Name, Any> {
return when (target) { return when (target) {
META_FORMAT_TYPE -> defaultMetaFormats.toMap() META_FORMAT_TYPE -> defaultMetaFormats.toMap()

View File

@ -0,0 +1,32 @@
package hep.dataforge.io
import hep.dataforge.meta.get
import hep.dataforge.meta.int
import kotlinx.io.core.writeText
import kotlin.test.Test
import kotlin.test.assertEquals
class EnvelopePartsTest {
val envelopes = (0..5).map {
Envelope {
meta {
"value" put it
}
data {
writeText("Hello World $it")
}
}
}
val partsEnvelope = Envelope {
parts(TaggedEnvelopeFormat, envelopes)
}
@Test
fun testParts() {
val bytes = TaggedEnvelopeFormat.default.writeBytes(partsEnvelope)
val reconstructed = TaggedEnvelopeFormat.default.readBytes(bytes)
val parts = reconstructed.parts().toList()
assertEquals(2, parts[2].meta["value"].int)
}
}