From 47bde02488084521897d75fda7af113b5aedc7fc Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Tue, 9 Aug 2022 12:49:01 +0300 Subject: [PATCH] [WIP] Completed solid refactoring --- .../kscience/visionforge/AbstractVision.kt | 99 ++----------------- .../space/kscience/visionforge/Vision.kt | 7 +- .../kscience/visionforge/VisionContainer.kt | 12 ++- .../space/kscience/visionforge/VisionGroup.kt | 21 ++-- .../kscience/visionforge/VisionProperties.kt | 89 ++++++++++++++++- .../visionforge/solid/SolidReference.kt | 49 +++++---- 6 files changed, 147 insertions(+), 130 deletions(-) diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt index 0e0e043d..e7df2198 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/AbstractVision.kt @@ -1,19 +1,10 @@ package space.kscience.visionforge -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.SharedFlow -import kotlinx.coroutines.launch import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.isEmpty -import space.kscience.dataforge.values.Value -import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties -import kotlin.jvm.Synchronized @Serializable @@ -23,91 +14,17 @@ public abstract class AbstractVision : Vision { override var parent: Vision? = null @SerialName("properties") - protected var _properties: MutableMeta? = null + protected var propertiesInternal: MutableMeta? = null - protected open val defaultProperties: Meta? get() = descriptor?.defaultNode - - @Transient - final override val properties: MutableVisionProperties = object : MutableVisionProperties { - override val descriptor: MetaDescriptor? get() = this@AbstractVision.descriptor - override val default: Meta? get() = defaultProperties - - @Synchronized - private fun getOrCreateProperties(): MutableMeta { - if (_properties == null) { - //TODO check performance issues - val newProperties = MutableMeta() - _properties = newProperties - } - return _properties!! + final override val properties: MutableVisionProperties by lazy { + object : AbstractVisionProperties(this) { + override var properties: MutableMeta? + get() = propertiesInternal + set(value) { + propertiesInternal = value + } } - - override val raw: Meta? get() = _properties - - override fun getValue( - name: Name, - inherit: Boolean, - includeStyles: Boolean, - ): Value? { - raw?.get(name)?.value?.let { return it } - if (includeStyles) { - getStyleProperty(name)?.value?.let { return it } - } - if (inherit) { - parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it } - } - return default?.get(name)?.value - } - - override fun set(name: Name, node: Meta?) { - //TODO check old value? - if (name.isEmpty()) { - _properties = node?.asMutableMeta() - } else if (node == null) { - _properties?.setMeta(name, node) - } else { - getOrCreateProperties().setMeta(name, node) - } - invalidate(name) - } - - override fun setValue(name: Name, value: Value?) { - //TODO check old value? - if (value == null) { - _properties?.getMeta(name)?.value = null - } else { - getOrCreateProperties().setValue(name, value) - } - invalidate(name) - } - - @Transient - private val _changes = MutableSharedFlow(10) - override val changes: SharedFlow get() = _changes - - override fun invalidate(propertyName: Name) { - if (propertyName == Vision.STYLE_KEY) { - styles.asSequence() - .mapNotNull { getStyle(it) } - .flatMap { it.items.asSequence() } - .distinctBy { it.key } - .forEach { - invalidate(it.key.asName()) - } - } - manager.context.launch { - _changes.emit(propertyName) - } - } - } override val descriptor: MetaDescriptor? get() = null - - - override fun update(change: VisionChange) { - change.properties?.let { - updateProperties(it, Name.EMPTY) - } - } } \ No newline at end of file diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt index e538b226..7bdcbe54 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/Vision.kt @@ -12,6 +12,7 @@ import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.boolean +import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties import space.kscience.visionforge.Vision.Companion.TYPE import kotlin.reflect.KProperty1 @@ -37,7 +38,11 @@ public interface Vision : Described { /** * Update this vision using a dif represented by [VisionChange]. */ - public fun update(change: VisionChange) + public fun update(change: VisionChange) { + change.properties?.let { + updateProperties(it, Name.EMPTY) + } + } override val descriptor: MetaDescriptor? diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt index 4ce69047..529c01a1 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionContainer.kt @@ -5,6 +5,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import space.kscience.dataforge.names.* +import kotlin.jvm.Synchronized @DslMarker public annotation class VisionBuilder @@ -113,8 +114,15 @@ internal abstract class VisionChildrenImpl( private val updateJobs = HashMap() - abstract val items: MutableMap? - abstract fun buildItems(): MutableMap + abstract var items: MutableMap? + + @Synchronized + private fun buildItems(): MutableMap { + if (items == null) { + items = LinkedHashMap() + } + return items!! + } private val scope: CoroutineScope get() = group.manager.context diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt index 9535fbd9..f666fcd8 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionGroup.kt @@ -11,7 +11,6 @@ import space.kscience.dataforge.names.plus import space.kscience.dataforge.values.ValueType import space.kscience.visionforge.Vision.Companion.STYLE_KEY import kotlin.js.JsName -import kotlin.jvm.Synchronized public interface VisionGroup : Vision { @@ -47,26 +46,20 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup } @SerialName("children") - protected var _children: MutableMap? = null + protected var childrenInternal: MutableMap? = null init { - _children?.forEach { it.value.parent = this } + childrenInternal?.forEach { it.value.parent = this } } override val children: MutableVisionChildren by lazy { - object : VisionChildrenImpl(this){ - override val items: MutableMap? - get() = this@AbstractVisionGroup._children - - @Synchronized - override fun buildItems(): MutableMap { - if (_children == null) { - _children = LinkedHashMap() + object : VisionChildrenImpl(this) { + override var items: MutableMap? + get() = this@AbstractVisionGroup.childrenInternal + set(value) { + this@AbstractVisionGroup.childrenInternal = value } - return _children!! - } - } } diff --git a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt index b4ca16ec..a750df5b 100644 --- a/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt +++ b/visionforge-core/src/commonMain/kotlin/space/kscience/visionforge/VisionProperties.kt @@ -1,17 +1,20 @@ package space.kscience.visionforge import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch +import kotlinx.serialization.Transient import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta +import space.kscience.dataforge.meta.asMutableMeta import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.get -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.NameToken -import space.kscience.dataforge.names.parseAsName -import space.kscience.dataforge.names.plus +import space.kscience.dataforge.names.* import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.asValue +import kotlin.jvm.Synchronized public interface VisionProperties { @@ -21,7 +24,6 @@ public interface VisionProperties { public val raw: Meta? public val descriptor: MetaDescriptor? - public val default: Meta? public fun getValue( name: Name, @@ -130,6 +132,83 @@ private class VisionPropertiesItem( override fun hashCode(): Int = Meta.hashCode(this) } +public abstract class AbstractVisionProperties( + private val vision: Vision, +) : MutableVisionProperties { + override val descriptor: MetaDescriptor? get() = vision.descriptor + protected val default: Meta? get() = descriptor?.defaultNode + + protected abstract var properties: MutableMeta? + + override val raw: Meta? get() = properties + + @Synchronized + protected fun getOrCreateProperties(): MutableMeta { + if (properties == null) { + //TODO check performance issues + val newProperties = MutableMeta() + properties = newProperties + } + return properties!! + } + + override fun getValue( + name: Name, + inherit: Boolean, + includeStyles: Boolean, + ): Value? { + raw?.get(name)?.value?.let { return it } + if (includeStyles) { + vision.getStyleProperty(name)?.value?.let { return it } + } + if (inherit) { + vision.parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it } + } + return default?.get(name)?.value + } + + override fun set(name: Name, node: Meta?) { + //TODO check old value? + if (name.isEmpty()) { + properties = node?.asMutableMeta() + } else if (node == null) { + properties?.setMeta(name, node) + } else { + getOrCreateProperties().setMeta(name, node) + } + invalidate(name) + } + + override fun setValue(name: Name, value: Value?) { + //TODO check old value? + if (value == null) { + properties?.getMeta(name)?.value = null + } else { + getOrCreateProperties().setValue(name, value) + } + invalidate(name) + } + + @Transient + private val _changes = MutableSharedFlow(10) + override val changes: SharedFlow get() = _changes + + override fun invalidate(propertyName: Name) { + if (propertyName == Vision.STYLE_KEY) { + vision.styles.asSequence() + .mapNotNull { vision.getStyle(it) } + .flatMap { it.items.asSequence() } + .distinctBy { it.key } + .forEach { + invalidate(it.key.asName()) + } + } + vision.manager.context.launch { + _changes.emit(propertyName) + } + } +} + public fun VisionProperties.getValue( name: Name, inherit: Boolean? = null, diff --git a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt index aa79734f..5428a7dd 100644 --- a/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt +++ b/visionforge-solid/src/commonMain/kotlin/space/kscience/visionforge/solid/SolidReference.kt @@ -28,7 +28,10 @@ public val Vision.unref: Solid @SerialName("solid.ref") public class SolidReference( @SerialName("prototype") public val prototypeName: Name, -) : SolidBase(), VisionGroup { +) : VisionGroup, Solid { + + @Transient + override var parent: Vision? = null /** * The prototype for this reference. @@ -40,11 +43,30 @@ public class SolidReference( (parent as? PrototypeHolder)?.getPrototype(prototypeName) ?: error("Prototype with name $prototypeName not found") } - override val descriptor: MetaDescriptor get() = prototype.descriptor - override val defaultProperties: Meta - get() = prototype.properties.raw?.withDefault(descriptor.defaultNode) ?: descriptor.defaultNode + @SerialName("properties") + private var propertiesInternal: MutableMeta? = null + + override val properties: MutableVisionProperties by lazy { + object : AbstractVisionProperties(this) { + override var properties: MutableMeta? + get() = propertiesInternal + set(value) { + propertiesInternal = value + } + + override val raw: Meta? get() = properties + + override fun get(name: Name, inherit: Boolean, includeStyles: Boolean): MutableMeta { + return properties?.getMeta(name) ?: prototype.properties.get(name, inherit, includeStyles) + } + + override fun getValue(name: Name, inherit: Boolean, includeStyles: Boolean): Value? { + return properties?.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles) + } + } + } override val children: VisionChildren get() = object : VisionChildren { @@ -66,7 +88,7 @@ public class SolidReference( } /** - * @param name A name of reference child relative to prototype root + * @param childName A name of reference child relative to prototype root */ internal class SolidReferenceChild( val owner: SolidReference, @@ -83,25 +105,17 @@ internal class SolidReferenceChild( @Transient override val properties: MutableVisionProperties = object : MutableVisionProperties { override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor - override val default: Meta - get() = prototype.properties.raw?.withDefault(descriptor.defaultNode) ?: descriptor.defaultNode override val raw: MutableMeta by lazy { owner.properties[childToken(childName).asName()] } + override fun get(name: Name, inherit: Boolean, includeStyles: Boolean): MutableMeta = + raw.getMeta(name) ?: prototype.properties.get(name, inherit, includeStyles) + override fun getValue( name: Name, inherit: Boolean, includeStyles: Boolean, - ): Value? { - raw[name]?.value?.let { return it } - if (includeStyles) { - getStyleProperty(name)?.value?.let { return it } - } - if (inherit) { - parent?.properties?.getValue(name, inherit, includeStyles)?.let { return it } - } - return default[name]?.value - } + ): Value? = raw.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles) override fun set(name: Name, node: Meta?) { raw.setMeta(name, node) @@ -110,6 +124,7 @@ internal class SolidReferenceChild( override fun setValue(name: Name, value: Value?) { raw.setValue(name, value) } + override val changes: Flow get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) } override fun invalidate(propertyName: Name) {