[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
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!!
}
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())
final override val properties: MutableVisionProperties by lazy {
object : AbstractVisionProperties(this) {
override var properties: MutableMeta?
get() = propertiesInternal
set(value) {
propertiesInternal = value
}
}
manager.context.launch {
_changes.emit(propertyName)
}
}
}
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.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?

View File

@ -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<NameToken, Job>()
abstract val items: MutableMap<NameToken, Vision>?
abstract fun buildItems(): MutableMap<NameToken, Vision>
abstract var items: 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

View File

@ -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<NameToken, Vision>? = null
protected var childrenInternal: MutableMap<NameToken, Vision>? = 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<NameToken, Vision>?
get() = this@AbstractVisionGroup._children
@Synchronized
override fun buildItems(): MutableMap<NameToken, Vision> {
if (_children == null) {
_children = LinkedHashMap()
override var items: MutableMap<NameToken, Vision>?
get() = this@AbstractVisionGroup.childrenInternal
set(value) {
this@AbstractVisionGroup.childrenInternal = value
}
return _children!!
}
}
}

View File

@ -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<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(
name: Name,
inherit: Boolean? = null,

View File

@ -28,7 +28,10 @@ public val Vision.unref: Solid
@SerialName("solid.ref")
public class SolidReference(
@SerialName("prototype") public val prototypeName: Name,
) : SolidBase<SolidReference>(), 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<Name> get() = owner.properties.changes.filter { it.startsWith(childToken(childName)) }
override fun invalidate(propertyName: Name) {