Transformation of Meta to Map and back

This commit is contained in:
Alexander Nozik 2019-10-28 12:35:19 +03:00
parent d3dd15884c
commit cd4736ab5e
10 changed files with 129 additions and 78 deletions

View File

@ -1,9 +0,0 @@
plugins {
id("scientifik.jvm")
}
description = "YAML meta IO"
dependencies{
api(project(":dataforge-io"))
}

View File

@ -1,7 +0,0 @@
package hep.dataforge.meta
/**
* General marker for dataforge builders
*/
@DslMarker
annotation class DFBuilder

View File

@ -4,8 +4,6 @@ import hep.dataforge.names.NameToken
/**
* A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Styled].
*
*
*/
class Laminate(layers: List<Meta>) : MetaBase() {

View File

@ -80,27 +80,6 @@ operator fun Meta?.get(name: Name): MetaItem<*>? {
operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token)
operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
/**
* Get all items matching given name.
*/
fun Meta.getAll(name: Name): Map<String, MetaItem<*>> {
val root = when (name.length) {
0 -> error("Can't use empty name for that")
1 -> this
else -> (this[name.cutLast()] as? NodeItem<*>)?.node
}
val (body, index) = name.last()!!
val regex = index.toRegex()
return root?.items
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
?.mapKeys { it.key.index }
?: emptyMap()
}
fun Meta.getAll(name: String): Map<String, MetaItem<*>> = getAll(name.toName())
/**
* Get a sequence of [Name]-[Value] pairs
*/
@ -138,27 +117,6 @@ interface MetaNode<M : MetaNode<M>> : Meta {
override val items: Map<NameToken, MetaItem<M>>
}
/**
* Get all items matching given name.
*/
fun <M : MetaNode<M>> M.getAll(name: Name): Map<String, MetaItem<M>> {
val root: MetaNode<M>? = when (name.length) {
0 -> error("Can't use empty name for that")
1 -> this
else -> (this[name.cutLast()] as? NodeItem<M>)?.node
}
val (body, index) = name.last()!!
val regex = index.toRegex()
return root?.items
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
?.mapKeys { it.key.index }
?: emptyMap()
}
fun <M : MetaNode<M>> M.getAll(name: String): Map<String, MetaItem<M>> = getAll(name.toName())
operator fun <M : MetaNode<M>> MetaNode<M>?.get(name: Name): MetaItem<M>? {
if (this == null) return null
return name.first()?.let { token ->
@ -229,7 +187,6 @@ object EmptyMeta : MetaBase() {
/**
* Unsafe methods to access values and nodes directly from [MetaItem]
*/
val MetaItem<*>?.value: Value?
get() = (this as? ValueItem)?.value
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
@ -258,11 +215,4 @@ val <M : Meta> MetaItem<M>?.node: M?
is NodeItem -> node
}
/**
* Generic meta-holder object
*/
interface Metoid {
val meta: Meta
}
fun Meta.isEmpty() = this === EmptyMeta || this.items.isEmpty()

View File

@ -0,0 +1,11 @@
package hep.dataforge.meta
/**
* General marker for dataforge builders
*/
@DslMarker
annotation class DFBuilder
@Experimental(level = Experimental.Level.WARNING)
@Retention(AnnotationRetention.BINARY)
annotation class DFExperimental

View File

@ -0,0 +1,36 @@
package hep.dataforge.meta
import hep.dataforge.values.Value
///**
// * Find all elements with given body
// */
//private fun Meta.byBody(body: String): Map<String, MetaItem<*>> =
// items.filter { it.key.body == body }.mapKeys { it.key.index }
//
//private fun Meta.distinctNames() = items.keys.map { it.body }.distinct()
/**
* Convert meta to map of maps
*/
fun Meta.toMap(): Map<String, Any?> {
return items.entries.associate { (token, item) ->
token.toString() to when (item) {
is MetaItem.NodeItem -> item.node.toMap()
is MetaItem.ValueItem -> item.value.value
}
}
}
/**
* Convert map of maps to meta
*/
fun Map<String, Any?>.toMeta(): Meta = buildMeta {
entries.forEach { (key, value) ->
@Suppress("UNCHECKED_CAST")
when (value) {
is Map<*, *> -> setNode(key, (value as Map<String, Any?>).toMeta())
else -> setValue(key, Value.of(value))
}
}
}

View File

@ -28,15 +28,21 @@ class StringDelegate(val meta: Meta, private val key: String? = null, private va
}
}
class BooleanDelegate(val meta: Meta, private val key: String? = null, private val default: Boolean? = null) :
ReadOnlyProperty<Metoid, Boolean?> {
override fun getValue(thisRef: Metoid, property: KProperty<*>): Boolean? {
class BooleanDelegate(
val meta: Meta,
private val key: String? = null,
private val default: Boolean? = null
) : ReadOnlyProperty<Any?, Boolean?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean? {
return meta[key ?: property.name]?.boolean ?: default
}
}
class NumberDelegate(val meta: Meta, private val key: String? = null, private val default: Number? = null) :
ReadOnlyProperty<Any?, Number?> {
class NumberDelegate(
val meta: Meta,
private val key: String? = null,
private val default: Number? = null
) : ReadOnlyProperty<Any?, Number?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Number? {
return meta[key ?: property.name]?.number ?: default
}
@ -168,9 +174,6 @@ fun Meta.number(key: String? = null, default: () -> Number) =
inline fun <reified E : Enum<E>> Meta.enum(default: E, key: String? = null) =
SafeEnumDelegate(this, key, default) { enumValueOf(it) }
fun <T : Metoid> Metoid.node(key: String? = null, converter: (Meta) -> T) = ChildDelegate(meta, key, converter)
/* Read-write delegates */
class MutableValueDelegate<M : MutableMeta<M>>(

View File

@ -0,0 +1,51 @@
package hep.dataforge.meta
import hep.dataforge.names.Name
import hep.dataforge.names.toName
/**
* Get all items matching given name.
*/
@DFExperimental
fun Meta.getAll(name: Name): Map<String, MetaItem<*>> {
val root = when (name.length) {
0 -> error("Can't use empty name for that")
1 -> this
else -> (this[name.cutLast()] as? MetaItem.NodeItem<*>)?.node
}
val (body, index) = name.last()!!
val regex = index.toRegex()
return root?.items
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
?.mapKeys { it.key.index }
?: emptyMap()
}
@DFExperimental
fun Meta.getAll(name: String): Map<String, MetaItem<*>> = getAll(name.toName())
/**
* Get all items matching given name.
*/
@DFExperimental
fun <M : MetaNode<M>> M.getAll(name: Name): Map<String, MetaItem<M>> {
val root: MetaNode<M>? = when (name.length) {
0 -> error("Can't use empty name for that")
1 -> this
else -> (this[name.cutLast()] as? MetaItem.NodeItem<M>)?.node
}
val (body, index) = name.last()!!
val regex = index.toRegex()
return root?.items
?.filter { it.key.body == body && (index.isEmpty() || regex.matches(it.key.index)) }
?.mapKeys { it.key.index }
?: emptyMap()
}
@DFExperimental
fun <M : MetaNode<M>> M.getAll(name: String): Map<String, MetaItem<M>> = getAll(name.toName())

View File

@ -30,4 +30,23 @@ class MetaTest {
}.seal()
assertEquals<Meta>(meta1, meta2)
}
@Test
fun metaToMap(){
val meta = buildMeta {
"a" to 22
"b" to {
"c" to "ddd"
}
"list" to (0..4).map {
buildMeta {
"value" to it
}
}
}
val map = meta.toMap()
val reconstructed = map.toMeta()
assertEquals(meta,reconstructed)
}
}

View File

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