Simplified mutable meta hierarchy

This commit is contained in:
Alexander Nozik 2019-05-28 19:24:23 +03:00
parent cffb02d483
commit 59c46344fa
6 changed files with 42 additions and 33 deletions

View File

@ -9,7 +9,7 @@ import hep.dataforge.names.asName
/** /**
* Mutable meta representing object state * Mutable meta representing object state
*/ */
open class Config : MutableMetaNode<Config>() { open class Config : AbstractMutableMeta<Config>() {
/** /**
* Attach configuration node instead of creating one * Attach configuration node instead of creating one

View File

@ -327,7 +327,7 @@ class MutableSafeEnumvDelegate<M : MutableMeta<M>, E : Enum<E>>(
//Child node delegate //Child node delegate
class MutableNodeDelegate<M : MutableMetaNode<M>>( class MutableNodeDelegate<M : MutableMeta<M>>(
val meta: M, val meta: M,
private val key: String? = null private val key: String? = null
) : ReadWriteProperty<Any?, Meta?> { ) : ReadWriteProperty<Any?, Meta?> {
@ -340,7 +340,7 @@ class MutableNodeDelegate<M : MutableMetaNode<M>>(
} }
} }
class MutableMorphDelegate<M : MutableMetaNode<M>, T : Configurable>( class MutableMorphDelegate<M : MutableMeta<M>, T : Configurable>(
val meta: M, val meta: M,
private val key: String? = null, private val key: String? = null,
private val converter: (Meta) -> T private val converter: (Meta) -> T
@ -390,7 +390,7 @@ fun <M : MutableMeta<M>> M.boolean(default: Boolean? = null, key: String? = null
fun <M : MutableMeta<M>> M.number(default: Number? = null, key: String? = null) = fun <M : MutableMeta<M>> M.number(default: Number? = null, key: String? = null) =
MutableNumberDelegate(this, key, default) MutableNumberDelegate(this, key, default)
fun <M : MutableMetaNode<M>> M.node(key: String? = null) = MutableNodeDelegate(this, key) fun <M : MutableMeta<M>> M.node(key: String? = null) = MutableNodeDelegate(this, key)
@JvmName("safeString") @JvmName("safeString")
fun <M : MutableMeta<M>> M.string(default: String, key: String? = null) = fun <M : MutableMeta<M>> M.string(default: String, key: String? = null) =

View File

@ -7,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 : MutableMetaNode<MetaBuilder>() { class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
override fun wrap(name: Name, meta: Meta): MetaBuilder = meta.builder() override fun wrap(name: Name, meta: Meta): MetaBuilder = meta.builder()
override fun empty(): MetaBuilder = MetaBuilder() override fun empty(): MetaBuilder = MetaBuilder()

View File

@ -23,7 +23,7 @@ interface TransformationRule {
/** /**
* Apply transformation for a single item (Node or Value) and return resulting tree with absolute path * Apply transformation for a single item (Node or Value) and return resulting tree with absolute path
*/ */
fun <M : MutableMetaNode<M>> transformItem(name: Name, item: MetaItem<*>?, target: M): Unit fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M): Unit
} }
/** /**
@ -36,7 +36,7 @@ data class SelfTransformationRule(val name: Name) : TransformationRule {
override fun selectItems(meta: Meta): Sequence<Name> = sequenceOf(name) override fun selectItems(meta: Meta): Sequence<Name> = sequenceOf(name)
override fun <M : MutableMetaNode<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) { override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) {
if (name == this.name) target[name] = item if (name == this.name) target[name] = item
} }
} }
@ -47,7 +47,7 @@ data class SelfTransformationRule(val name: Name) : TransformationRule {
data class SingleItemTransformationRule( data class SingleItemTransformationRule(
val from: Name, val from: Name,
val to: Name, val to: Name,
val transform: MutableMetaNode<*>.(MetaItem<*>?) -> Unit val transform: MutableMeta<*>.(MetaItem<*>?) -> Unit
) : TransformationRule { ) : TransformationRule {
override fun matches(name: Name, item: MetaItem<*>?): Boolean { override fun matches(name: Name, item: MetaItem<*>?): Boolean {
return name == from return name == from
@ -55,7 +55,7 @@ data class SingleItemTransformationRule(
override fun selectItems(meta: Meta): Sequence<Name> = sequenceOf(from) override fun selectItems(meta: Meta): Sequence<Name> = sequenceOf(from)
override fun <M : MutableMetaNode<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) { override fun <M : MutableMeta<M>> transformItem(name: Name, item: MetaItem<*>?, target: M) {
if (name == this.from) { if (name == this.from) {
target.transform(item) target.transform(item)
} }

View File

@ -10,6 +10,13 @@ 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<M>?)
fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
@ -21,7 +28,7 @@ interface MutableMeta<M : MutableMeta<M>> : MetaNode<M> {
* *
* Changes in Meta are not thread safe. * Changes in Meta are not thread safe.
*/ */
abstract class MutableMetaNode<M : MutableMetaNode<M>> : AbstractMetaNode<M>(), MutableMeta<M> { abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
private val listeners = HashSet<MetaListener>() private val listeners = HashSet<MetaListener>()
/** /**
@ -62,13 +69,6 @@ abstract class MutableMetaNode<M : MutableMetaNode<M>> : AbstractMetaNode<M>(),
itemChanged(key.asName(), oldItem, newItem) itemChanged(key.asName(), oldItem, newItem)
} }
/**
* 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
*/
internal abstract fun wrap(name: Name, meta: Meta): M
/** /**
* Create empty node * Create empty node
*/ */
@ -97,30 +97,31 @@ fun <M : MutableMeta<M>> MutableMeta<M>.remove(name: String) = remove(name.toNam
fun <M : MutableMeta<M>> MutableMeta<M>.setValue(name: Name, value: Value) = fun <M : MutableMeta<M>> MutableMeta<M>.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 <M : MutableMeta<M>> MutableMeta<M>.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 <M : MutableMeta<M>> MutableMeta<M>.setItem(token: NameToken, item: MetaItem<M>?) = set(token.asName(), item)
//fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<M>) = set(name.toName(), item) //fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<M>) = set(name.toName(), item)
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setItem(name: Name, item: MetaItem<*>) { fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: Name, item: MetaItem<*>) {
when (item) { when (item) {
is MetaItem.ValueItem<*> -> setValue(name, item.value) is MetaItem.ValueItem<*> -> setValue(name, item.value)
is MetaItem.NodeItem<*> -> setNode(name, item.node) is MetaItem.NodeItem<*> -> setNode(name, item.node)
} }
} }
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setItem(name: String, item: MetaItem<*>) = setItem(name.toName(), item) fun <M : MutableMeta<M>> MutableMeta<M>.setItem(name: String, item: MetaItem<*>) = setItem(name.toName(), item)
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setNode(name: Name, node: Meta) = fun <M : MutableMeta<M>> MutableMeta<M>.setNode(name: Name, node: Meta) =
set(name, MetaItem.NodeItem(wrap(name, node))) set(name, MetaItem.NodeItem(wrap(name, node)))
fun <M : MutableMetaNode<M>> MutableMetaNode<M>.setNode(name: String, node: Meta) = setNode(name.toName(), node) fun <M : MutableMeta<M>> MutableMeta<M>.setNode(name: String, node: Meta) = setNode(name.toName(), node)
/** /**
* Universal set method * Universal set method
*/ */
operator fun <M : MutableMetaNode<M>> MutableMetaNode<M>.set(name: Name, value: Any?) { operator fun <M : MutableMeta<M>> MutableMeta<M>.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)
@ -130,9 +131,9 @@ operator fun <M : MutableMetaNode<M>> MutableMetaNode<M>.set(name: Name, value:
} }
} }
operator fun <M : MutableMetaNode<M>> M.set(name: NameToken, value: Any?) = set(name.asName(), value) operator fun <M : MutableMeta<M>> M.set(name: NameToken, value: Any?) = set(name.asName(), value)
operator fun <M : MutableMetaNode<M>> M.set(key: String, value: Any?) = set(key.toName(), value) operator fun <M : MutableMeta<M>> M.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:
@ -140,7 +141,7 @@ operator fun <M : MutableMetaNode<M>> M.set(key: String, value: Any?) = set(key.
* * node updates node and replaces anything but node * * node updates node and replaces anything but node
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise * * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
*/ */
fun <M : MutableMetaNode<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 val value = entry.value
when (value) { when (value) {
@ -153,7 +154,7 @@ fun <M : MutableMetaNode<M>> M.update(meta: Meta) {
/* Same name siblings generation */ /* Same name siblings generation */
fun <M : MutableMeta<M>> M.setIndexed( fun <M : MutableMeta<M>> M.setIndexedItems(
name: Name, name: Name,
items: Iterable<MetaItem<M>>, items: Iterable<MetaItem<M>>,
indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() } indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() }
@ -167,21 +168,21 @@ fun <M : MutableMeta<M>> M.setIndexed(
} }
} }
fun <M : MutableMetaNode<M>> M.setIndexed( fun <M : MutableMeta<M>> M.setIndexed(
name: Name, name: Name,
metas: Iterable<Meta>, metas: Iterable<Meta>,
indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() } indexFactory: MetaItem<M>.(index: Int) -> String = { it.toString() }
) { ) {
setIndexed(name, metas.map { MetaItem.NodeItem(wrap(name, it)) }, indexFactory) setIndexedItems(name, metas.map { MetaItem.NodeItem(wrap(name, it)) }, indexFactory)
} }
operator fun <M : MutableMetaNode<M>> M.set(name: Name, metas: Iterable<Meta>) = setIndexed(name, metas) operator fun <M : MutableMeta<M>> M.set(name: Name, metas: Iterable<Meta>) = setIndexed(name, metas)
operator fun <M : MutableMetaNode<M>> M.set(name: String, metas: Iterable<Meta>) = setIndexed(name.toName(), metas) operator fun <M : MutableMeta<M>> M.set(name: String, metas: Iterable<Meta>) = 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 : MutableMetaNode<M>> M.append(name: Name, value: Any?) { fun <M : MutableMeta<M>> M.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()) {
@ -192,4 +193,4 @@ fun <M : MutableMetaNode<M>> M.append(name: Name, value: Any?) {
} }
} }
fun <M : MutableMetaNode<M>> M.append(name: String, value: Any?) = append(name.toName(), value) fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)

View File

@ -11,7 +11,15 @@ import kotlin.reflect.KProperty
* @param base - unchangeable base * @param base - unchangeable base
* @param style - the style * @param style - the style
*/ */
class Styled(val base: Meta, val style: Config = Config().empty()) : MutableMeta<Styled> { class Styled(val base: Meta, val style: Config = Config().empty()) : AbstractMutableMeta<Styled>() {
override fun wrap(name: Name, meta: Meta): Styled {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun empty(): Styled {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
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]