[WIP] Completed solid refactoring

This commit is contained in:
Alexander Nozik 2022-08-09 12:49:01 +03:00
parent c71042ae06
commit 47bde02488
No known key found for this signature in database
GPG Key ID: F7FCF2DD25C71357
6 changed files with 147 additions and 130 deletions

View File

@ -1,19 +1,10 @@
package space.kscience.visionforge 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.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor 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 @Serializable
@ -23,91 +14,17 @@ public abstract class AbstractVision : Vision {
override var parent: Vision? = null override var parent: Vision? = null
@SerialName("properties") @SerialName("properties")
protected var _properties: MutableMeta? = null protected var propertiesInternal: MutableMeta? = null
protected open val defaultProperties: Meta? get() = descriptor?.defaultNode final override val properties: MutableVisionProperties by lazy {
object : AbstractVisionProperties(this) {
@Transient override var properties: MutableMeta?
final override val properties: MutableVisionProperties = object : MutableVisionProperties { get() = propertiesInternal
override val descriptor: MetaDescriptor? get() = this@AbstractVision.descriptor set(value) {
override val default: Meta? get() = defaultProperties propertiesInternal = value
@Synchronized
private fun getOrCreateProperties(): MutableMeta {
if (_properties == null) {
//TODO check performance issues
val newProperties = MutableMeta()
_properties = newProperties
}
return _properties!!
}
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<Name>(10)
override val changes: SharedFlow<Name> 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 val descriptor: MetaDescriptor? get() = null
override fun update(change: VisionChange) {
change.properties?.let {
updateProperties(it, Name.EMPTY)
}
}
} }

View File

@ -12,6 +12,7 @@ import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import space.kscience.dataforge.values.boolean import space.kscience.dataforge.values.boolean
import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
import space.kscience.visionforge.Vision.Companion.TYPE import space.kscience.visionforge.Vision.Companion.TYPE
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
@ -37,7 +38,11 @@ public interface Vision : Described {
/** /**
* Update this vision using a dif represented by [VisionChange]. * 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? override val descriptor: MetaDescriptor?

View File

@ -5,6 +5,7 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.jvm.Synchronized
@DslMarker @DslMarker
public annotation class VisionBuilder public annotation class VisionBuilder
@ -113,8 +114,15 @@ internal abstract class VisionChildrenImpl(
private val updateJobs = HashMap<NameToken, Job>() private val updateJobs = HashMap<NameToken, Job>()
abstract val items: MutableMap<NameToken, Vision>? abstract var items: MutableMap<NameToken, Vision>?
abstract fun buildItems(): MutableMap<NameToken, Vision>
@Synchronized
private fun buildItems(): MutableMap<NameToken, Vision> {
if (items == null) {
items = LinkedHashMap()
}
return items!!
}
private val scope: CoroutineScope get() = group.manager.context private val scope: CoroutineScope get() = group.manager.context

View File

@ -11,7 +11,6 @@ import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.ValueType import space.kscience.dataforge.values.ValueType
import space.kscience.visionforge.Vision.Companion.STYLE_KEY import space.kscience.visionforge.Vision.Companion.STYLE_KEY
import kotlin.js.JsName import kotlin.js.JsName
import kotlin.jvm.Synchronized
public interface VisionGroup : Vision { public interface VisionGroup : Vision {
@ -47,26 +46,20 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
} }
@SerialName("children") @SerialName("children")
protected var _children: MutableMap<NameToken, Vision>? = null protected var childrenInternal: MutableMap<NameToken, Vision>? = null
init { init {
_children?.forEach { it.value.parent = this } childrenInternal?.forEach { it.value.parent = this }
} }
override val children: MutableVisionChildren by lazy { override val children: MutableVisionChildren by lazy {
object : VisionChildrenImpl(this) { object : VisionChildrenImpl(this) {
override val items: MutableMap<NameToken, Vision>? override var items: MutableMap<NameToken, Vision>?
get() = this@AbstractVisionGroup._children get() = this@AbstractVisionGroup.childrenInternal
set(value) {
@Synchronized this@AbstractVisionGroup.childrenInternal = value
override fun buildItems(): MutableMap<NameToken, Vision> {
if (_children == null) {
_children = LinkedHashMap()
} }
return _children!!
}
} }
} }

View File

@ -1,17 +1,20 @@
package space.kscience.visionforge package space.kscience.visionforge
import kotlinx.coroutines.flow.Flow 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.Meta
import space.kscience.dataforge.meta.MutableMeta 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.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.*
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import kotlin.jvm.Synchronized
public interface VisionProperties { public interface VisionProperties {
@ -21,7 +24,6 @@ public interface VisionProperties {
public val raw: Meta? public val raw: Meta?
public val descriptor: MetaDescriptor? public val descriptor: MetaDescriptor?
public val default: Meta?
public fun getValue( public fun getValue(
name: Name, name: Name,
@ -130,6 +132,83 @@ private class VisionPropertiesItem(
override fun hashCode(): Int = Meta.hashCode(this) 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<Name>(10)
override val changes: SharedFlow<Name> 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( public fun VisionProperties.getValue(
name: Name, name: Name,
inherit: Boolean? = null, inherit: Boolean? = null,

View File

@ -28,7 +28,10 @@ public val Vision.unref: Solid
@SerialName("solid.ref") @SerialName("solid.ref")
public class SolidReference( public class SolidReference(
@SerialName("prototype") public val prototypeName: Name, @SerialName("prototype") public val prototypeName: Name,
) : SolidBase<SolidReference>(), VisionGroup { ) : VisionGroup, Solid {
@Transient
override var parent: Vision? = null
/** /**
* The prototype for this reference. * The prototype for this reference.
@ -40,11 +43,30 @@ public class SolidReference(
(parent as? PrototypeHolder)?.getPrototype(prototypeName) (parent as? PrototypeHolder)?.getPrototype(prototypeName)
?: error("Prototype with name $prototypeName not found") ?: error("Prototype with name $prototypeName not found")
} }
override val descriptor: MetaDescriptor get() = prototype.descriptor override val descriptor: MetaDescriptor get() = prototype.descriptor
override val defaultProperties: Meta @SerialName("properties")
get() = prototype.properties.raw?.withDefault(descriptor.defaultNode) ?: descriptor.defaultNode 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 override val children: VisionChildren
get() = object : 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( internal class SolidReferenceChild(
val owner: SolidReference, val owner: SolidReference,
@ -83,25 +105,17 @@ internal class SolidReferenceChild(
@Transient @Transient
override val properties: MutableVisionProperties = object : MutableVisionProperties { override val properties: MutableVisionProperties = object : MutableVisionProperties {
override val descriptor: MetaDescriptor get() = this@SolidReferenceChild.descriptor 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 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( override fun getValue(
name: Name, name: Name,
inherit: Boolean, inherit: Boolean,
includeStyles: Boolean, includeStyles: Boolean,
): Value? { ): Value? = raw.getValue(name) ?: prototype.properties.getValue(name, inherit, includeStyles)
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
}
override fun set(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
raw.setMeta(name, node) raw.setMeta(name, node)
@ -110,6 +124,7 @@ internal class SolidReferenceChild(
override fun setValue(name: Name, value: Value?) { override fun setValue(name: Name, value: Value?) {
raw.setValue(name, value) raw.setValue(name, value)
} }
override val changes: Flow<Name> get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) } override val changes: Flow<Name> get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
override fun invalidate(propertyName: Name) { override fun invalidate(propertyName: Name) {