forked from kscience/visionforge
[WIP] Completed solid refactoring
This commit is contained in:
parent
c71042ae06
commit
47bde02488
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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?
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()
|
||||
object : VisionChildrenImpl(this) {
|
||||
override var items: MutableMap<NameToken, Vision>?
|
||||
get() = this@AbstractVisionGroup.childrenInternal
|
||||
set(value) {
|
||||
this@AbstractVisionGroup.childrenInternal = value
|
||||
}
|
||||
return _children!!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user