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
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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?
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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!!
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user