[WIP] great refactoring in progress
This commit is contained in:
parent
9b1ca8332b
commit
c71042ae06
@ -4,6 +4,7 @@ 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
|
||||
@ -15,13 +16,14 @@ import space.kscience.visionforge.AbstractVisionGroup.Companion.updateProperties
|
||||
import kotlin.jvm.Synchronized
|
||||
|
||||
|
||||
@Serializable
|
||||
public abstract class AbstractVision : Vision {
|
||||
|
||||
@Transient
|
||||
override var parent: Vision? = null
|
||||
|
||||
@SerialName("properties")
|
||||
internal var _properties: MutableMeta? = null
|
||||
protected var _properties: MutableMeta? = null
|
||||
|
||||
protected open val defaultProperties: Meta? get() = descriptor?.defaultNode
|
||||
|
||||
@ -80,7 +82,7 @@ public abstract class AbstractVision : Vision {
|
||||
}
|
||||
|
||||
@Transient
|
||||
private val _changes = MutableSharedFlow<Name>()
|
||||
private val _changes = MutableSharedFlow<Name>(10)
|
||||
override val changes: SharedFlow<Name> get() = _changes
|
||||
|
||||
override fun invalidate(propertyName: Name) {
|
||||
|
@ -16,7 +16,7 @@ import kotlin.time.Duration
|
||||
/**
|
||||
* Create a deep copy of given Vision without external connections.
|
||||
*/
|
||||
private fun Vision.deepCopy(): Vision {
|
||||
private fun Vision.deepCopy(manager: VisionManager): Vision {
|
||||
//Assuming that unrooted visions are already isolated
|
||||
//TODO replace by efficient deep copy
|
||||
val json = manager.encodeToJsonElement(this)
|
||||
@ -26,7 +26,7 @@ private fun Vision.deepCopy(): Vision {
|
||||
/**
|
||||
* An update for a [Vision]
|
||||
*/
|
||||
public class VisionChangeBuilder : MutableVisionContainer<Vision> {
|
||||
public class VisionChangeBuilder(private val manager: VisionManager) : MutableVisionContainer<Vision> {
|
||||
|
||||
private var reset: Boolean = false
|
||||
private var vision: Vision? = null
|
||||
@ -37,7 +37,7 @@ public class VisionChangeBuilder : MutableVisionContainer<Vision> {
|
||||
|
||||
@Synchronized
|
||||
private fun getOrPutChild(visionName: Name): VisionChangeBuilder =
|
||||
children.getOrPut(visionName) { VisionChangeBuilder() }
|
||||
children.getOrPut(visionName) { VisionChangeBuilder(manager) }
|
||||
|
||||
public fun propertyChanged(visionName: Name, propertyName: Name, item: Meta?) {
|
||||
if (visionName == Name.EMPTY) {
|
||||
@ -61,7 +61,7 @@ public class VisionChangeBuilder : MutableVisionContainer<Vision> {
|
||||
*/
|
||||
public fun deepCopy(): VisionChange = VisionChange(
|
||||
reset,
|
||||
vision?.deepCopy(),
|
||||
vision?.deepCopy(manager),
|
||||
if (propertyChange.isEmpty()) null else propertyChange.seal(),
|
||||
if (children.isEmpty()) null else children.mapValues { it.value.deepCopy() }
|
||||
)
|
||||
@ -81,8 +81,8 @@ public data class VisionChange(
|
||||
public val children: Map<Name, VisionChange>? = null,
|
||||
)
|
||||
|
||||
public inline fun VisionChange(block: VisionChangeBuilder.() -> Unit): VisionChange =
|
||||
VisionChangeBuilder().apply(block).deepCopy()
|
||||
public inline fun VisionManager.VisionChange(block: VisionChangeBuilder.() -> Unit): VisionChange =
|
||||
VisionChangeBuilder(this).apply(block).deepCopy()
|
||||
|
||||
|
||||
private fun CoroutineScope.collectChange(
|
||||
@ -119,14 +119,15 @@ private fun CoroutineScope.collectChange(
|
||||
*/
|
||||
public fun Vision.flowChanges(
|
||||
collectionDuration: Duration,
|
||||
manager: VisionManager = this.manager,
|
||||
): Flow<VisionChange> = flow {
|
||||
|
||||
var collector = VisionChangeBuilder()
|
||||
var collector = VisionChangeBuilder(manager)
|
||||
coroutineScope {
|
||||
collectChange(Name.EMPTY, this@flowChanges) { collector }
|
||||
|
||||
//Send initial vision state
|
||||
val initialChange = VisionChange(vision = deepCopy())
|
||||
val initialChange = VisionChange(vision = deepCopy(manager))
|
||||
emit(initialChange)
|
||||
|
||||
while (currentCoroutineContext().isActive) {
|
||||
@ -137,7 +138,7 @@ public fun Vision.flowChanges(
|
||||
//emit changes
|
||||
emit(collector.deepCopy())
|
||||
//Reset the collector
|
||||
collector = VisionChangeBuilder()
|
||||
collector = VisionChangeBuilder(manager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,6 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.serializer
|
||||
import space.kscience.dataforge.names.*
|
||||
|
||||
@DslMarker
|
||||
@ -60,9 +54,9 @@ public inline fun VisionChildren.forEach(block: (NameToken, Vision) -> Unit) {
|
||||
keys.forEach { block(it, get(it)!!) }
|
||||
}
|
||||
|
||||
@Serializable(VisionChildrenContainerSerializer::class)
|
||||
public interface MutableVisionChildren : VisionChildren, MutableVisionContainer<Vision> {
|
||||
public override val group: MutableVisionGroup?
|
||||
|
||||
public override val group: MutableVisionGroup
|
||||
|
||||
public operator fun set(token: NameToken, value: Vision?)
|
||||
|
||||
@ -83,9 +77,9 @@ public interface MutableVisionChildren : VisionChildren, MutableVisionContainer<
|
||||
else -> {
|
||||
val currentParent = get(name.first())
|
||||
if (currentParent != null && currentParent !is MutableVisionGroup) error("Can't assign a child to $currentParent")
|
||||
val parent: MutableVisionGroup = currentParent as? MutableVisionGroup ?: group?.createGroup().also {
|
||||
val parent: MutableVisionGroup = currentParent as? MutableVisionGroup ?: group.createGroup().also {
|
||||
set(name.first(), it)
|
||||
} ?: error("Container owner not set")
|
||||
}
|
||||
parent.children[name.cutFirst()] = child
|
||||
}
|
||||
}
|
||||
@ -113,27 +107,26 @@ public operator fun <V : Vision> MutableVisionContainer<V>.set(
|
||||
str: String?, vision: V?,
|
||||
): Unit = set(str?.parseAsName(), vision)
|
||||
|
||||
internal class VisionChildrenImpl(
|
||||
items: Map<NameToken, Vision>,
|
||||
internal abstract class VisionChildrenImpl(
|
||||
override val group: MutableVisionGroup,
|
||||
) : MutableVisionChildren {
|
||||
|
||||
override var group: MutableVisionGroup? = null
|
||||
internal set
|
||||
|
||||
private val items = LinkedHashMap(items)
|
||||
private val updateJobs = HashMap<NameToken, Job>()
|
||||
|
||||
private val scope: CoroutineScope? get() = group?.manager?.context
|
||||
abstract val items: MutableMap<NameToken, Vision>?
|
||||
abstract fun buildItems(): MutableMap<NameToken, Vision>
|
||||
|
||||
override val keys: Set<NameToken> get() = items.keys
|
||||
private val scope: CoroutineScope get() = group.manager.context
|
||||
|
||||
override fun get(token: NameToken): Vision? = items[token]
|
||||
override val keys: Set<NameToken> get() = items?.keys ?: emptySet()
|
||||
|
||||
override fun get(token: NameToken): Vision? = items?.get(token)
|
||||
|
||||
private val _changes = MutableSharedFlow<Name>()
|
||||
override val changes: SharedFlow<Name> get() = _changes
|
||||
|
||||
private fun onChange(name: Name) {
|
||||
scope?.launch {
|
||||
scope.launch {
|
||||
_changes.emit(name)
|
||||
}
|
||||
}
|
||||
@ -149,16 +142,16 @@ internal class VisionChildrenImpl(
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
items.remove(token)
|
||||
items?.remove(token)
|
||||
} else {
|
||||
items[token] = value
|
||||
(items ?: buildItems())[token] = value
|
||||
//check if parent already exists and is different from the current one
|
||||
if (value.parent != null && value.parent != group) error("Can't reassign parent Vision for $value")
|
||||
//set parent
|
||||
value.parent = group
|
||||
//start update jobs (only if the vision is rooted)
|
||||
scope?.let { scope ->
|
||||
val job = (value.children as? VisionChildrenImpl)?.changes?.onEach {
|
||||
scope.let { scope ->
|
||||
val job = value.children?.changes?.onEach {
|
||||
onChange(token + it)
|
||||
}?.launchIn(scope)
|
||||
if (job != null) {
|
||||
@ -171,30 +164,30 @@ internal class VisionChildrenImpl(
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
if (items.isNotEmpty()) {
|
||||
if (!items.isNullOrEmpty()) {
|
||||
updateJobs.values.forEach {
|
||||
it.cancel()
|
||||
}
|
||||
updateJobs.clear()
|
||||
items.clear()
|
||||
items?.clear()
|
||||
onChange(Name.EMPTY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object VisionChildrenContainerSerializer : KSerializer<MutableVisionChildren> {
|
||||
private val mapSerializer = serializer<Map<NameToken, Vision>>()
|
||||
|
||||
override val descriptor: SerialDescriptor = mapSerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): MutableVisionChildren {
|
||||
val map = decoder.decodeSerializableValue(mapSerializer)
|
||||
return VisionChildrenImpl(map)
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: MutableVisionChildren) {
|
||||
val map = value.keys.associateWith { value[it]!! }
|
||||
encoder.encodeSerializableValue(mapSerializer, map)
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
//internal object VisionChildrenContainerSerializer : KSerializer<MutableVisionChildren> {
|
||||
// private val mapSerializer = serializer<Map<NameToken, Vision>>()
|
||||
//
|
||||
// override val descriptor: SerialDescriptor = mapSerializer.descriptor
|
||||
//
|
||||
// override fun deserialize(decoder: Decoder): MutableVisionChildren {
|
||||
// val map = decoder.decodeSerializableValue(mapSerializer)
|
||||
// return VisionChildrenImpl(map)
|
||||
// }
|
||||
//
|
||||
// override fun serialize(encoder: Encoder, value: MutableVisionChildren) {
|
||||
// val map = value.keys.associateWith { value[it]!! }
|
||||
// encoder.encodeSerializableValue(mapSerializer, map)
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package space.kscience.visionforge
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.value
|
||||
@ -33,6 +30,7 @@ public val Vision.children: VisionChildren? get() = (this as? VisionGroup)?.chil
|
||||
/**
|
||||
* A full base implementation for a [Vision]
|
||||
*/
|
||||
@Serializable
|
||||
public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup {
|
||||
|
||||
override fun update(change: VisionChange) {
|
||||
@ -49,38 +47,26 @@ public abstract class AbstractVisionGroup : AbstractVision(), MutableVisionGroup
|
||||
}
|
||||
|
||||
@SerialName("children")
|
||||
protected var _children: MutableVisionChildren? = null
|
||||
protected var _children: MutableMap<NameToken, Vision>? = null
|
||||
|
||||
@Transient
|
||||
override val children: MutableVisionChildren = object : MutableVisionChildren {
|
||||
|
||||
init {
|
||||
_children?.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
|
||||
fun getOrCreateChildren(): MutableVisionChildren {
|
||||
override fun buildItems(): MutableMap<NameToken, Vision> {
|
||||
if (_children == null) {
|
||||
_children = VisionChildrenImpl(emptyMap()).apply {
|
||||
group = this@AbstractVisionGroup
|
||||
}
|
||||
_children = LinkedHashMap()
|
||||
}
|
||||
return _children!!
|
||||
}
|
||||
|
||||
override val group: MutableVisionGroup get() = this@AbstractVisionGroup
|
||||
|
||||
override val keys: Set<NameToken> get() = _children?.keys ?: emptySet()
|
||||
override val changes: Flow<Name> get() = _children?.changes ?: emptyFlow()
|
||||
|
||||
override fun get(token: NameToken): Vision? = _children?.get(token)
|
||||
|
||||
override fun set(token: NameToken, value: Vision?) {
|
||||
getOrCreateChildren()[token] = value
|
||||
}
|
||||
|
||||
override fun set(name: Name?, child: Vision?) {
|
||||
getOrCreateChildren()[name] = child
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
_children?.clear()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
}
|
||||
|
||||
val plotlyVersion = "0.5.0"
|
||||
val plotlyVersion = "0.5.3-dev-1"
|
||||
|
||||
kscience {
|
||||
useSerialization()
|
||||
|
@ -15,6 +15,11 @@ kotlin {
|
||||
api(project(":visionforge-core"))
|
||||
}
|
||||
}
|
||||
commonTest{
|
||||
dependencies{
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,30 +60,6 @@ public class SolidReference(
|
||||
}
|
||||
}
|
||||
|
||||
// override fun getPropertyValue(
|
||||
// name: Name,
|
||||
// inherit: Boolean,
|
||||
// includeStyles: Boolean,
|
||||
// includeDefaults: Boolean,
|
||||
// ): Value? {
|
||||
// meta?.getValue(name)?.let { return it }
|
||||
// if (includeStyles) {
|
||||
// getStyleProperty(name)?.value?.let { return it }
|
||||
// }
|
||||
// prototype.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||
// if (inherit) {
|
||||
// parent?.getPropertyValue(name, inherit, includeStyles, includeDefaults)?.let { return it }
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
//
|
||||
// override fun getProperty(
|
||||
// name: Name,
|
||||
// inherit: Boolean,
|
||||
// includeStyles: Boolean,
|
||||
// includeDefaults: Boolean,
|
||||
// ): MutableMeta = VisionProperties(this, name, descriptor[name], inherit, includeStyles, prototype.meta)
|
||||
|
||||
public companion object {
|
||||
public const val REFERENCE_CHILD_PROPERTY_PREFIX: String = "@child"
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.values.int
|
||||
import space.kscience.dataforge.values.string
|
||||
@ -10,8 +14,8 @@ import kotlin.test.assertEquals
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
class PropertyTest {
|
||||
@Test
|
||||
fun testColor(){
|
||||
val box = Box(10.0f, 10.0f,10.0f)
|
||||
fun testColor() {
|
||||
val box = Box(10.0f, 10.0f, 10.0f)
|
||||
box.material {
|
||||
//meta["color"] = "pink"
|
||||
color.set("pink")
|
||||
@ -20,14 +24,17 @@ class PropertyTest {
|
||||
assertEquals("pink", box.color.string)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun testColorUpdate(){
|
||||
val box = Box(10.0f, 10.0f,10.0f)
|
||||
fun testColorUpdate() = runTest {
|
||||
val box = Box(10.0f, 10.0f, 10.0f)
|
||||
|
||||
val c = CompletableDeferred<String?>()
|
||||
|
||||
|
||||
var c: String? = null
|
||||
box.onPropertyChange {
|
||||
if(it == SolidMaterial.MATERIAL_COLOR_KEY){
|
||||
c = box.color.string
|
||||
if (it == SolidMaterial.MATERIAL_COLOR_KEY) {
|
||||
c.complete(box.color.string)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +42,8 @@ class PropertyTest {
|
||||
color.set("pink")
|
||||
}
|
||||
|
||||
assertEquals("pink", c)
|
||||
assertEquals("pink", withTimeout(50) { c.await() })
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -53,7 +61,7 @@ class PropertyTest {
|
||||
@Test
|
||||
fun testStyleProperty() {
|
||||
var box: Box? = null
|
||||
val group = SolidGroup{
|
||||
val group = SolidGroup {
|
||||
styleSheet {
|
||||
update("testStyle") {
|
||||
"test" put 22
|
||||
@ -89,7 +97,7 @@ class PropertyTest {
|
||||
@Test
|
||||
fun testReferenceStyleProperty() {
|
||||
var box: SolidReference? = null
|
||||
val group = SolidGroup{
|
||||
val group = SolidGroup {
|
||||
styleSheet {
|
||||
update("testStyle") {
|
||||
SolidMaterial.MATERIAL_COLOR_KEY put "#555555"
|
||||
|
@ -2,6 +2,7 @@ package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.serialization.json.encodeToJsonElement
|
||||
import space.kscience.dataforge.misc.DFExperimental
|
||||
import space.kscience.dataforge.names.get
|
||||
import space.kscience.visionforge.get
|
||||
import space.kscience.visionforge.style
|
||||
import space.kscience.visionforge.useStyle
|
||||
@ -30,6 +31,7 @@ class SolidReferenceTest {
|
||||
fun testReferenceSerialization(){
|
||||
val serialized = Solids.jsonForSolids.encodeToJsonElement(groupWithReference)
|
||||
val deserialized = Solids.jsonForSolids.decodeFromJsonElement(SolidGroup.serializer(), serialized)
|
||||
assertEquals(groupWithReference.items["test"]?.color.string, deserialized.items["test"]?.color.string)
|
||||
assertEquals("blue", (deserialized.children["test"] as Solid).color.string)
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class VisionUpdateTest {
|
||||
internal class VisionUpdateTest {
|
||||
val solidManager = Global.fetch(Solids)
|
||||
val visionManager = solidManager.visionManager
|
||||
|
||||
@ -20,7 +20,7 @@ class VisionUpdateTest {
|
||||
val targetVision = SolidGroup {
|
||||
box(200,200,200, name = "origin")
|
||||
}
|
||||
val dif = VisionChange{
|
||||
val dif = visionManager.VisionChange{
|
||||
group ("top") {
|
||||
color.set(123)
|
||||
box(100,100,100)
|
||||
@ -36,7 +36,7 @@ class VisionUpdateTest {
|
||||
|
||||
@Test
|
||||
fun testVisionChangeSerialization(){
|
||||
val change = VisionChange{
|
||||
val change = visionManager.VisionChange{
|
||||
group("top") {
|
||||
color.set(123)
|
||||
box(100,100,100)
|
||||
|
@ -2,7 +2,7 @@ plugins {
|
||||
id("ru.mipt.npm.gradle.mpp")
|
||||
}
|
||||
|
||||
val tablesVersion = "0.2.0-dev-1"
|
||||
val tablesVersion = "0.2.0-dev-3"
|
||||
|
||||
kscience {
|
||||
useSerialization()
|
||||
|
Loading…
Reference in New Issue
Block a user