Optimized type projections in meta. Set operations are now non-generic
This commit is contained in:
parent
f0413464a3
commit
d08e1ee57d
@ -90,6 +90,7 @@ object BinaryMetaFormat : MetaFormat {
|
|||||||
return readText(max = length)
|
return readText(max = length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
private fun Input.readMetaItem(): MetaItem<MetaBuilder> {
|
||||||
val keyChar = readByte().toChar()
|
val keyChar = readByte().toChar()
|
||||||
return when (keyChar) {
|
return when (keyChar) {
|
||||||
@ -119,6 +120,6 @@ object BinaryMetaFormat : MetaFormat {
|
|||||||
MetaItem.NodeItem(meta)
|
MetaItem.NodeItem(meta)
|
||||||
}
|
}
|
||||||
else -> error("Unknown serialization key character: $keyChar")
|
else -> error("Unknown serialization key character: $keyChar")
|
||||||
}
|
} as MetaItem<MetaBuilder>
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -49,8 +49,7 @@ fun Value.toJson(): JsonElement {
|
|||||||
|
|
||||||
fun Meta.toJson(): JsonObject {
|
fun Meta.toJson(): JsonObject {
|
||||||
val map = this.items.mapValues { entry ->
|
val map = this.items.mapValues { entry ->
|
||||||
val value = entry.value
|
when (val value = entry.value) {
|
||||||
when (value) {
|
|
||||||
is MetaItem.ValueItem -> value.value.toJson()
|
is MetaItem.ValueItem -> value.value.toJson()
|
||||||
is MetaItem.NodeItem -> value.node.toJson()
|
is MetaItem.NodeItem -> value.node.toJson()
|
||||||
}
|
}
|
||||||
@ -70,8 +69,9 @@ class JsonMeta(val json: JsonObject) : Meta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement) = when (value) {
|
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement) = when (value) {
|
||||||
is JsonPrimitive -> this[key] = MetaItem.ValueItem(value.toValue())
|
is JsonPrimitive -> this[key] = MetaItem.ValueItem(value.toValue()) as MetaItem<JsonMeta>
|
||||||
is JsonObject -> this[key] = MetaItem.NodeItem(value.toMeta())
|
is JsonObject -> this[key] = MetaItem.NodeItem(value.toMeta())
|
||||||
is JsonArray -> {
|
is JsonArray -> {
|
||||||
when {
|
when {
|
||||||
@ -82,12 +82,12 @@ class JsonMeta(val json: JsonObject) : Meta {
|
|||||||
(it as JsonPrimitive).toValue()
|
(it as JsonPrimitive).toValue()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
this[key] = MetaItem.ValueItem(listValue)
|
this[key] = MetaItem.ValueItem(listValue) as MetaItem<JsonMeta>
|
||||||
}
|
}
|
||||||
else -> value.forEachIndexed { index, jsonElement ->
|
else -> value.forEachIndexed { index, jsonElement ->
|
||||||
when (jsonElement) {
|
when (jsonElement) {
|
||||||
is JsonObject -> this["$key[$index]"] = MetaItem.NodeItem(JsonMeta(jsonElement))
|
is JsonObject -> this["$key[$index]"] = MetaItem.NodeItem(JsonMeta(jsonElement))
|
||||||
is JsonPrimitive -> this["$key[$index]"] = MetaItem.ValueItem(jsonElement.toValue())
|
is JsonPrimitive -> this["$key[$index]"] = MetaItem.ValueItem(jsonElement.toValue()) as MetaItem<JsonMeta>
|
||||||
is JsonArray -> TODO("Nested arrays not supported")
|
is JsonArray -> TODO("Nested arrays not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.NameToken
|
import hep.dataforge.names.NameToken
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
|
|
||||||
@ -9,12 +8,12 @@ import hep.dataforge.names.asName
|
|||||||
/**
|
/**
|
||||||
* Mutable meta representing object state
|
* Mutable meta representing object state
|
||||||
*/
|
*/
|
||||||
open class Config : AbstractMutableMeta<Config>() {
|
class Config : AbstractMutableMeta<Config>() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach configuration node instead of creating one
|
* Attach configuration node instead of creating one
|
||||||
*/
|
*/
|
||||||
override fun wrap(name: Name, meta: Meta): Config = meta.toConfig()
|
override fun wrapNode(meta: Meta): Config = meta.toConfig()
|
||||||
|
|
||||||
override fun empty(): Config = Config()
|
override fun empty(): Config = Config()
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ fun Meta.toConfig(): Config = this as? Config ?: Config().also { builder ->
|
|||||||
this.items.mapValues { entry ->
|
this.items.mapValues { entry ->
|
||||||
val item = entry.value
|
val item = entry.value
|
||||||
builder[entry.key.asName()] = when (item) {
|
builder[entry.key.asName()] = when (item) {
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem(item.value)
|
is MetaItem.ValueItem -> item.value
|
||||||
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.toConfig())
|
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.toConfig())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ import hep.dataforge.values.boolean
|
|||||||
* * a [ValueItem] (leaf)
|
* * a [ValueItem] (leaf)
|
||||||
* * a [NodeItem] (node)
|
* * a [NodeItem] (node)
|
||||||
*/
|
*/
|
||||||
sealed class MetaItem<M : Meta> {
|
sealed class MetaItem<out M : Meta> {
|
||||||
data class ValueItem<M : Meta>(val value: Value) : MetaItem<M>()
|
data class ValueItem(val value: Value) : MetaItem<Nothing>()
|
||||||
data class NodeItem<M : Meta>(val node: M) : MetaItem<M>()
|
data class NodeItem<M : Meta>(val node: M) : MetaItem<M>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ interface MetaRepr {
|
|||||||
* * Same name siblings are supported via elements with the same [Name] but different queries
|
* * Same name siblings are supported via elements with the same [Name] but different queries
|
||||||
*/
|
*/
|
||||||
interface Meta : MetaRepr {
|
interface Meta : MetaRepr {
|
||||||
val items: Map<NameToken, MetaItem<out Meta>>
|
val items: Map<NameToken, MetaItem<*>>
|
||||||
|
|
||||||
override fun toMeta(): Meta = this
|
override fun toMeta(): Meta = this
|
||||||
|
|
||||||
@ -50,12 +50,7 @@ interface Meta : MetaRepr {
|
|||||||
|
|
||||||
/* Get operations*/
|
/* Get operations*/
|
||||||
|
|
||||||
/**
|
operator fun Meta?.get(name: Name): MetaItem<*>? {
|
||||||
* Fast [String]-based accessor for item map
|
|
||||||
*/
|
|
||||||
operator fun <T> Map<NameToken, T>.get(body: String, query: String = ""): T? = get(NameToken(body, query))
|
|
||||||
|
|
||||||
operator fun Meta?.get(name: Name): MetaItem<out Meta>? {
|
|
||||||
if (this == null) return null
|
if (this == null) return null
|
||||||
return name.first()?.let { token ->
|
return name.first()?.let { token ->
|
||||||
val tail = name.cutFirst()
|
val tail = name.cutFirst()
|
||||||
@ -66,13 +61,13 @@ operator fun Meta?.get(name: Name): MetaItem<out Meta>? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun Meta?.get(token: NameToken): MetaItem<out Meta>? = this?.items?.get(token)
|
operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token)
|
||||||
operator fun Meta?.get(key: String): MetaItem<out Meta>? = get(key.toName())
|
operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all items matching given name.
|
* Get all items matching given name.
|
||||||
*/
|
*/
|
||||||
fun Meta.getAll(name: Name): Map<String, MetaItem<out Meta>> {
|
fun Meta.getAll(name: Name): Map<String, MetaItem<*>> {
|
||||||
val root = when (name.length) {
|
val root = when (name.length) {
|
||||||
0 -> error("Can't use empty name for that")
|
0 -> error("Can't use empty name for that")
|
||||||
1 -> this
|
1 -> this
|
||||||
@ -88,7 +83,7 @@ fun Meta.getAll(name: Name): Map<String, MetaItem<out Meta>> {
|
|||||||
?: emptyMap()
|
?: emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Meta.getAll(name: String): Map<String, MetaItem<out Meta>> = getAll(name.toName())
|
fun Meta.getAll(name: String): Map<String, MetaItem<*>> = getAll(name.toName())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a sequence of [Name]-[Value] pairs
|
* Get a sequence of [Name]-[Value] pairs
|
||||||
@ -130,7 +125,7 @@ interface MetaNode<M : MetaNode<M>> : Meta {
|
|||||||
/**
|
/**
|
||||||
* Get all items matching given name.
|
* Get all items matching given name.
|
||||||
*/
|
*/
|
||||||
fun <M : MetaNode<M>> MetaNode<M>.getAll(name: Name): Map<String, MetaItem<M>> {
|
fun <M : MetaNode<M>> M.getAll(name: Name): Map<String, MetaItem<M>> {
|
||||||
val root: MetaNode<M>? = when (name.length) {
|
val root: MetaNode<M>? = when (name.length) {
|
||||||
0 -> error("Can't use empty name for that")
|
0 -> error("Can't use empty name for that")
|
||||||
1 -> this
|
1 -> this
|
||||||
@ -158,7 +153,11 @@ operator fun <M : MetaNode<M>> MetaNode<M>.get(name: Name): MetaItem<M>? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <M : MetaNode<M>> MetaNode<M>?.get(key: String): MetaItem<M>? = this?.let { get(key.toName()) }
|
operator fun <M : MetaNode<M>> MetaNode<M>?.get(key: String): MetaItem<M>? = if (this == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
this[key.toName()]
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equals and hash code implementation for meta node
|
* Equals and hash code implementation for meta node
|
||||||
@ -189,13 +188,14 @@ class SealedMeta internal constructor(override val items: Map<NameToken, MetaIte
|
|||||||
*/
|
*/
|
||||||
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
|
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem(value)
|
is ValueItem -> this as MetaItem<SealedMeta>
|
||||||
is MetaItem.NodeItem -> MetaItem.NodeItem(node.seal())
|
is NodeItem -> NodeItem(node.seal())
|
||||||
}
|
}
|
||||||
|
|
||||||
object EmptyMeta : Meta {
|
object EmptyMeta : Meta {
|
||||||
override val items: Map<NameToken, MetaItem<out Meta>> = emptyMap()
|
override val items: Map<NameToken, MetaItem<*>> = emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,8 +203,8 @@ object EmptyMeta : Meta {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
val MetaItem<*>?.value
|
val MetaItem<*>?.value
|
||||||
get() = (this as? MetaItem.ValueItem)?.value
|
get() = (this as? ValueItem)?.value
|
||||||
?: (this?.node?.get(VALUE_KEY) as? MetaItem.ValueItem)?.value
|
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
|
||||||
|
|
||||||
val MetaItem<*>?.string get() = value?.string
|
val MetaItem<*>?.string get() = value?.string
|
||||||
val MetaItem<*>?.boolean get() = value?.boolean
|
val MetaItem<*>?.boolean get() = value?.boolean
|
||||||
@ -226,8 +226,8 @@ val MetaItem<*>?.stringList get() = value?.list?.map { it.string } ?: emptyList(
|
|||||||
val <M : Meta> MetaItem<M>?.node: M?
|
val <M : Meta> MetaItem<M>?.node: M?
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
null -> null
|
null -> null
|
||||||
is MetaItem.ValueItem -> error("Trying to interpret value meta item as node item")
|
is ValueItem -> error("Trying to interpret value meta item as node item")
|
||||||
is MetaItem.NodeItem -> node
|
is NodeItem -> node
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package hep.dataforge.meta
|
package hep.dataforge.meta
|
||||||
|
|
||||||
import hep.dataforge.names.Name
|
|
||||||
import hep.dataforge.names.asName
|
import hep.dataforge.names.asName
|
||||||
import hep.dataforge.values.Value
|
import hep.dataforge.values.Value
|
||||||
|
|
||||||
@ -8,7 +7,7 @@ import hep.dataforge.values.Value
|
|||||||
* DSL builder for meta. Is not intended to store mutable state
|
* DSL builder for meta. Is not intended to store mutable state
|
||||||
*/
|
*/
|
||||||
class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
||||||
override fun wrap(name: Name, meta: Meta): MetaBuilder = meta.builder()
|
override fun wrapNode(meta: Meta): MetaBuilder = meta.builder()
|
||||||
override fun empty(): MetaBuilder = MetaBuilder()
|
override fun empty(): MetaBuilder = MetaBuilder()
|
||||||
|
|
||||||
infix fun String.to(value: Any) {
|
infix fun String.to(value: Any) {
|
||||||
@ -39,7 +38,7 @@ fun Meta.builder(): MetaBuilder {
|
|||||||
items.mapValues { entry ->
|
items.mapValues { entry ->
|
||||||
val item = entry.value
|
val item = entry.value
|
||||||
builder[entry.key.asName()] = when (item) {
|
builder[entry.key.asName()] = when (item) {
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem<MetaBuilder>(item.value)
|
is MetaItem.ValueItem -> item.value
|
||||||
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.builder())
|
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.builder())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,9 @@ data class RegexpItemTransformationRule(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of [TransformationRule] to either transform static meta or create dynamically updated [MutableMeta]
|
||||||
|
*/
|
||||||
inline class MetaTransformation(val transformations: Collection<TransformationRule>) {
|
inline class MetaTransformation(val transformations: Collection<TransformationRule>) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,7 +112,7 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
|
|||||||
* Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule.
|
* Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule.
|
||||||
*/
|
*/
|
||||||
fun <M : MutableMeta<M>> bind(source: MutableMeta<*>, target: M) {
|
fun <M : MutableMeta<M>> bind(source: MutableMeta<*>, target: M) {
|
||||||
source.onChange(target) { name, oldItem, newItem ->
|
source.onChange(target) { name, _, newItem ->
|
||||||
transformations.forEach { t ->
|
transformations.forEach { t ->
|
||||||
if (t.matches(name, newItem)) {
|
if (t.matches(name, newItem)) {
|
||||||
t.transformItem(name, newItem, target)
|
t.transformItem(name, newItem, target)
|
||||||
@ -123,18 +126,29 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for a set of transformation rules
|
||||||
|
*/
|
||||||
class MetaTransformationBuilder {
|
class MetaTransformationBuilder {
|
||||||
val transformations = HashSet<TransformationRule>()
|
val transformations = HashSet<TransformationRule>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep all items with name satisfying the criteria
|
||||||
|
*/
|
||||||
fun keep(selector: (Name) -> Boolean) {
|
fun keep(selector: (Name) -> Boolean) {
|
||||||
transformations.add(KeepTransformationRule(selector))
|
transformations.add(KeepTransformationRule(selector))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep specific item (including its descendants)
|
||||||
|
*/
|
||||||
fun keep(name: Name) {
|
fun keep(name: Name) {
|
||||||
keep{it == name}
|
keep{it == name}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun keepNode(name: Name){
|
fun move(from: Name, to: Name){
|
||||||
keep{it.startsWith(name)}
|
transformations.add(
|
||||||
|
SingleItemTransformationRule(from){ _, item -> setItem(to, item)}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,15 +10,8 @@ internal data class MetaListener(
|
|||||||
|
|
||||||
|
|
||||||
interface MutableMeta<M : MutableMeta<M>> : MetaNode<M> {
|
interface MutableMeta<M : MutableMeta<M>> : MetaNode<M> {
|
||||||
/**
|
|
||||||
* Transform given meta to node type of this meta tree
|
|
||||||
* @param name the name of the node where meta should be attached. Needed for correct assignment validators and styles
|
|
||||||
* @param meta the node itself
|
|
||||||
*/
|
|
||||||
fun wrap(name: Name, meta: Meta): M
|
|
||||||
|
|
||||||
override val items: Map<NameToken, MetaItem<M>>
|
override val items: Map<NameToken, MetaItem<M>>
|
||||||
operator fun set(name: Name, item: MetaItem<M>?)
|
operator fun set(name: Name, item: MetaItem<*>?)
|
||||||
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
||||||
fun removeListener(owner: Any? = null)
|
fun removeListener(owner: Any? = null)
|
||||||
}
|
}
|
||||||
@ -69,59 +62,70 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
|
|||||||
itemChanged(key.asName(), oldItem, newItem)
|
itemChanged(key.asName(), oldItem, newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
protected fun wrapItem(item: MetaItem<*>?): MetaItem<M>? = when (item) {
|
||||||
|
null -> null
|
||||||
|
is MetaItem.ValueItem -> item as MetaItem<M>
|
||||||
|
is MetaItem.NodeItem<*> -> MetaItem.NodeItem(wrapNode(item.node))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform given meta to node type of this meta tree
|
||||||
|
*/
|
||||||
|
protected abstract fun wrapNode(meta: Meta): M
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create empty node
|
* Create empty node
|
||||||
*/
|
*/
|
||||||
internal abstract fun empty(): M
|
internal abstract fun empty(): M
|
||||||
|
|
||||||
override operator fun set(name: Name, item: MetaItem<M>?) {
|
override operator fun set(name: Name, item: MetaItem<*>?) {
|
||||||
when (name.length) {
|
when (name.length) {
|
||||||
0 -> error("Can't setValue meta item for empty name")
|
0 -> error("Can't setValue meta item for empty name")
|
||||||
1 -> {
|
1 -> {
|
||||||
val token = name.first()!!
|
val token = name.first()!!
|
||||||
replaceItem(token, get(name), item)
|
replaceItem(token, get(name), wrapItem(item))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val token = name.first()!!
|
val token = name.first()!!
|
||||||
//get existing or create new node. Query is ignored for new node
|
//get existing or create new node. Query is ignored for new node
|
||||||
val child = this.items[token]?.node
|
if(items[token] == null){
|
||||||
?: empty().also { this[token.body.toName()] = MetaItem.NodeItem(it) }
|
replaceItem(token,null, MetaItem.NodeItem(empty()))
|
||||||
child[name.cutFirst()] = item
|
}
|
||||||
|
items[token]?.node!![name.cutFirst()] = item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.remove(name: Name) = set(name, null)
|
fun MutableMeta<*>.remove(name: Name) = set(name, null)
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.remove(name: String) = remove(name.toName())
|
fun MutableMeta<*>.remove(name: String) = remove(name.toName())
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setValue(name: Name, value: Value) =
|
fun MutableMeta<*>.setValue(name: Name, value: Value) =
|
||||||
set(name, MetaItem.ValueItem(value))
|
set(name, MetaItem.ValueItem(value))
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setValue(name: String, value: Value) =
|
fun MutableMeta<*>.setValue(name: String, value: Value) =
|
||||||
set(name.toName(), MetaItem.ValueItem(value))
|
set(name.toName(), MetaItem.ValueItem(value))
|
||||||
|
|
||||||
//fun <M : MutableMeta<M>> MutableMeta<M>.setItem(token: NameToken, item: MetaItem<M>?) = set(token.asName(), item)
|
fun MutableMeta<*>.setItem(name: Name, item: MetaItem<*>?) {
|
||||||
//fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<M>) = set(name.toName(), item)
|
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: Name, item: MetaItem<*>) {
|
|
||||||
when (item) {
|
when (item) {
|
||||||
is MetaItem.ValueItem<*> -> setValue(name, item.value)
|
null -> remove(name)
|
||||||
|
is MetaItem.ValueItem -> setValue(name, item.value)
|
||||||
is MetaItem.NodeItem<*> -> setNode(name, item.node)
|
is MetaItem.NodeItem<*> -> setNode(name, item.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<*>) = setItem(name.toName(), item)
|
fun MutableMeta<*>.setItem(name: String, item: MetaItem<*>?) = setItem(name.toName(), item)
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setNode(name: Name, node: Meta) =
|
fun MutableMeta<*>.setNode(name: Name, node: Meta) =
|
||||||
set(name, MetaItem.NodeItem(wrap(name, node)))
|
set(name, MetaItem.NodeItem(node))
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> MutableMeta<M>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
|
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Universal set method
|
* Universal set method
|
||||||
*/
|
*/
|
||||||
operator fun <M : MutableMeta<M>> MutableMeta<M>.set(name: Name, value: Any?) {
|
operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
||||||
when (value) {
|
when (value) {
|
||||||
null -> remove(name)
|
null -> remove(name)
|
||||||
is MetaItem<*> -> setItem(name, value)
|
is MetaItem<*> -> setItem(name, value)
|
||||||
@ -131,9 +135,9 @@ operator fun <M : MutableMeta<M>> MutableMeta<M>.set(name: Name, value: Any?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <M : MutableMeta<M>> M.set(name: NameToken, value: Any?) = set(name.asName(), value)
|
operator fun MutableMeta<*>.set(name: NameToken, value: Any?) = set(name.asName(), value)
|
||||||
|
|
||||||
operator fun <M : MutableMeta<M>> M.set(key: String, value: Any?) = set(key.toName(), value)
|
operator fun MutableMeta<*>.set(key: String, value: Any?) = set(key.toName(), value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update existing mutable node with another node. The rules are following:
|
* Update existing mutable node with another node. The rules are following:
|
||||||
@ -143,8 +147,7 @@ operator fun <M : MutableMeta<M>> M.set(key: String, value: Any?) = set(key.toNa
|
|||||||
*/
|
*/
|
||||||
fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
||||||
meta.items.forEach { entry ->
|
meta.items.forEach { entry ->
|
||||||
val value = entry.value
|
when (val value = entry.value) {
|
||||||
when (value) {
|
|
||||||
is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value)
|
is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value)
|
||||||
is MetaItem.NodeItem -> (this[entry.key.asName()] as? MetaItem.NodeItem)?.node?.update(value.node)
|
is MetaItem.NodeItem -> (this[entry.key.asName()] as? MetaItem.NodeItem)?.node?.update(value.node)
|
||||||
?: run { setNode(entry.key.asName(), value.node) }
|
?: run { setNode(entry.key.asName(), value.node) }
|
||||||
@ -154,10 +157,10 @@ fun <M : MutableMeta<M>> M.update(meta: Meta) {
|
|||||||
|
|
||||||
/* Same name siblings generation */
|
/* Same name siblings generation */
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> M.setIndexedItems(
|
fun MutableMeta<*>.setIndexedItems(
|
||||||
name: Name,
|
name: Name,
|
||||||
items: Iterable<MetaItem<M>>,
|
items: Iterable<MetaItem<*>>,
|
||||||
indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() }
|
indexFactory: MetaItem<*>.(index: Int) -> String = { it.toString() }
|
||||||
) {
|
) {
|
||||||
val tokens = name.tokens.toMutableList()
|
val tokens = name.tokens.toMutableList()
|
||||||
val last = tokens.last()
|
val last = tokens.last()
|
||||||
@ -168,21 +171,21 @@ fun <M : MutableMeta<M>> M.setIndexedItems(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> M.setIndexed(
|
fun MutableMeta<*>.setIndexed(
|
||||||
name: Name,
|
name: Name,
|
||||||
metas: Iterable<Meta>,
|
metas: Iterable<Meta>,
|
||||||
indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() }
|
indexFactory: MetaItem<*>.(index: Int) -> String = { it.toString() }
|
||||||
) {
|
) {
|
||||||
setIndexedItems(name, metas.map { MetaItem.NodeItem(wrap(name, it)) }, indexFactory)
|
setIndexedItems(name, metas.map { MetaItem.NodeItem(it) }, indexFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <M : MutableMeta<M>> M.set(name: Name, metas: Iterable<Meta>) = setIndexed(name, metas)
|
operator fun MutableMeta<*>.set(name: Name, metas: Iterable<Meta>): Unit = setIndexed(name, metas)
|
||||||
operator fun <M : MutableMeta<M>> M.set(name: String, metas: Iterable<Meta>) = setIndexed(name.toName(), metas)
|
operator fun MutableMeta<*>.set(name: String, metas: Iterable<Meta>): Unit = setIndexed(name.toName(), metas)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the node with a same-name-sibling, automatically generating numerical index
|
* Append the node with a same-name-sibling, automatically generating numerical index
|
||||||
*/
|
*/
|
||||||
fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
fun MutableMeta<*>.append(name: Name, value: Any?) {
|
||||||
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
require(!name.isEmpty()) { "Name could not be empty for append operation" }
|
||||||
val newIndex = name.last()!!.index
|
val newIndex = name.last()!!.index
|
||||||
if (newIndex.isNotEmpty()) {
|
if (newIndex.isNotEmpty()) {
|
||||||
@ -193,4 +196,4 @@ fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)
|
fun MutableMeta<*>.append(name: String, value: Any?) = append(name.toName(), value)
|
@ -12,14 +12,11 @@ import kotlin.reflect.KProperty
|
|||||||
* @param style - the style
|
* @param style - the style
|
||||||
*/
|
*/
|
||||||
class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMutableMeta<Styled>() {
|
class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMutableMeta<Styled>() {
|
||||||
override fun wrap(name: Name, meta: Meta): Styled {
|
override fun wrapNode(meta: Meta): Styled = Styled(meta)
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun empty(): Styled {
|
override fun empty(): Styled = Styled(EmptyMeta)
|
||||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
override val items: Map<NameToken, MetaItem<Styled>>
|
override val items: Map<NameToken, MetaItem<Styled>>
|
||||||
get() = (base.items.keys + style.items.keys).associate { key ->
|
get() = (base.items.keys + style.items.keys).associate { key ->
|
||||||
val value = base.items[key]
|
val value = base.items[key]
|
||||||
@ -27,10 +24,10 @@ class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMut
|
|||||||
val item: MetaItem<Styled> = when (value) {
|
val item: MetaItem<Styled> = when (value) {
|
||||||
null -> when (styleValue) {
|
null -> when (styleValue) {
|
||||||
null -> error("Should be unreachable")
|
null -> error("Should be unreachable")
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem(styleValue.value)
|
|
||||||
is MetaItem.NodeItem -> MetaItem.NodeItem(Styled(style.empty(), styleValue.node))
|
is MetaItem.NodeItem -> MetaItem.NodeItem(Styled(style.empty(), styleValue.node))
|
||||||
|
else -> styleValue.value as MetaItem<Styled>
|
||||||
}
|
}
|
||||||
is MetaItem.ValueItem -> MetaItem.ValueItem(value.value)
|
is MetaItem.ValueItem -> value as MetaItem<Styled>
|
||||||
is MetaItem.NodeItem -> MetaItem.NodeItem(
|
is MetaItem.NodeItem -> MetaItem.NodeItem(
|
||||||
Styled(value.node, styleValue?.node ?: Config.empty())
|
Styled(value.node, styleValue?.node ?: Config.empty())
|
||||||
)
|
)
|
||||||
@ -38,7 +35,7 @@ class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMut
|
|||||||
key to item
|
key to item
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun set(name: Name, item: MetaItem<Styled>?) {
|
override fun set(name: Name, item: MetaItem<*>?) {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
style.remove(name)
|
style.remove(name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,6 +121,11 @@ fun Name.withIndex(index: String): Name {
|
|||||||
return Name(tokens)
|
return Name(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast [String]-based accessor for item map
|
||||||
|
*/
|
||||||
|
operator fun <T> Map<NameToken, T>.get(body: String, query: String = ""): T? = get(NameToken(body, query))
|
||||||
|
|
||||||
operator fun <T> Map<Name, T>.get(name: String) = get(name.toName())
|
operator fun <T> Map<Name, T>.get(name: String) = get(name.toName())
|
||||||
operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value)
|
operator fun <T> MutableMap<Name, T>.set(name: String, value: T) = set(name.toName(), value)
|
||||||
|
|
||||||
|
@ -35,12 +35,13 @@ class DynamicMeta(val obj: dynamic) : Meta {
|
|||||||
private fun isArray(@Suppress("UNUSED_PARAMETER") obj: dynamic): Boolean =
|
private fun isArray(@Suppress("UNUSED_PARAMETER") obj: dynamic): Boolean =
|
||||||
js("Array.isArray(obj)") as Boolean
|
js("Array.isArray(obj)") as Boolean
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun asItem(obj: dynamic): MetaItem<DynamicMeta>? {
|
private fun asItem(obj: dynamic): MetaItem<DynamicMeta>? {
|
||||||
if (obj == null) return MetaItem.ValueItem(Null)
|
if (obj == null) return MetaItem.ValueItem(Null) as MetaItem<DynamicMeta>
|
||||||
return when (jsTypeOf(obj)) {
|
return when (jsTypeOf(obj as? Any)) {
|
||||||
"boolean" -> MetaItem.ValueItem(Value.of(obj as Boolean))
|
"boolean" -> MetaItem.ValueItem(Value.of(obj as Boolean)) as MetaItem<DynamicMeta>
|
||||||
"number" -> MetaItem.ValueItem(Value.of(obj as Number))
|
"number" -> MetaItem.ValueItem(Value.of(obj as Number)) as MetaItem<DynamicMeta>
|
||||||
"string" -> MetaItem.ValueItem(Value.of(obj as String))
|
"string" -> MetaItem.ValueItem(Value.of(obj as String)) as MetaItem<DynamicMeta>
|
||||||
"object" -> MetaItem.NodeItem(DynamicMeta(obj))
|
"object" -> MetaItem.NodeItem(DynamicMeta(obj))
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -61,13 +61,13 @@ class SimpleWorkspaceTest {
|
|||||||
allData()
|
allData()
|
||||||
}
|
}
|
||||||
joinByGroup<Int, Double> { context ->
|
joinByGroup<Int, Double> { context ->
|
||||||
group("even", filter = { name, data -> name.toString().toInt() % 2 == 0 }) {
|
group("even", filter = { name, _ -> name.toString().toInt() % 2 == 0 }) {
|
||||||
result { data ->
|
result { data ->
|
||||||
context.logger.info { "Starting even" }
|
context.logger.info { "Starting even" }
|
||||||
data.values.average()
|
data.values.average()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group("odd", filter = { name, data -> name.toString().toInt() % 2 == 1 }) {
|
group("odd", filter = { name, _ -> name.toString().toInt() % 2 == 1 }) {
|
||||||
result { data ->
|
result { data ->
|
||||||
context.logger.info { "Starting odd" }
|
context.logger.info { "Starting odd" }
|
||||||
data.values.average()
|
data.values.average()
|
||||||
|
Loading…
Reference in New Issue
Block a user