Fix tests with new prototype location

This commit is contained in:
Alexander Nozik 2021-07-12 10:01:21 +03:00
parent 42e2530f6f
commit 073d374a9e
9 changed files with 96 additions and 130 deletions

View File

@ -10,7 +10,7 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
class GDMLVisualTest {
class GDMLVisionTest {
// @Test
// fun testCubesStyles(){

View File

@ -28,11 +28,10 @@ internal data class PropertyListener(
*/
@Serializable
@SerialName("vision")
public open class VisionBase : Vision {
public open class VisionBase(
override @Transient var parent: VisionGroup? = null,
protected var properties: Config? = null
@Transient
override var parent: VisionGroup? = null
) : Vision {
@Synchronized
protected fun getOrCreateProperties(): Config {

View File

@ -0,0 +1,23 @@
package space.kscience.visionforge.gdml
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus
import space.kscience.visionforge.VisionGroup
private fun VisionGroup.countChildren(namePrefix: Name, cache: MutableMap<Name, Int> = hashMapOf()): Int {
var counter = 0
children.forEach { (token, child) ->
if (child is VisionGroup) {
counter += child.countChildren(namePrefix + token, cache)
} else {
counter++
}
}
cache[namePrefix] = counter
return counter
}
public fun VisionGroup.processLayers() {
}

View File

@ -26,7 +26,7 @@ class TestCubes {
val smallBoxPrototype = vision.getPrototype("solids.smallBox".toName()) as? Box
assertNotNull(smallBoxPrototype)
assertEquals(30.0, smallBoxPrototype.xSize.toDouble())
val smallBoxVision = vision["composite-111.smallBox"]?.prototype as? Box
val smallBoxVision = vision["composite-111.smallBox"]?.unref as? Box
assertNotNull(smallBoxVision)
assertEquals(30.0, smallBoxVision.xSize.toDouble())
}

View File

@ -5,7 +5,6 @@ import kotlinx.coroutines.withContext
import nl.adaptivity.xmlutil.StAXReader
import space.kscience.gdml.Gdml
import space.kscience.gdml.decodeFromReader
import space.kscience.visionforge.solid.prototype
import space.kscience.visionforge.visitor.countDistinct
import space.kscience.visionforge.visitor.flowStatistics
import java.io.File
@ -23,7 +22,7 @@ suspend fun main() {
vision.flowStatistics<KClass<*>>{ _, child ->
child.prototype::class
child::class
}.countDistinct().forEach { (depth, size) ->
println("$depth\t$size")
}

View File

@ -34,6 +34,7 @@ import kotlin.reflect.KProperty
* Interface for 3-dimensional [Vision]
*/
public interface Solid : Vision {
override val descriptor: NodeDescriptor get() = Companion.descriptor
public companion object {

View File

@ -12,11 +12,7 @@ import space.kscience.visionforge.VisionChange
@Serializable
@SerialName("solid")
public open class SolidBase(
// override var position: Point3D? = null,
// override var rotation: Point3D? = null,
// override var scale: Point3D? = null,
) : VisionBase(), Solid {
public open class SolidBase : VisionBase(), Solid {
override val descriptor: NodeDescriptor get() = Solid.descriptor
override fun update(change: VisionChange) {

View File

@ -1,14 +1,7 @@
package space.kscience.visionforge.solid
import kotlinx.serialization.KSerializer
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import space.kscience.dataforge.meta.MetaItem
import space.kscience.dataforge.meta.descriptors.NodeDescriptor
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
@ -27,37 +20,35 @@ public interface PrototypeHolder {
*/
@Serializable
@SerialName("group.solid")
public class SolidGroup(
@Serializable(PrototypeSerializer::class) internal var prototypes: MutableVisionGroup? = null,
) : VisionGroupBase(), Solid, PrototypeHolder {
public class SolidGroup : VisionGroupBase(), Solid, PrototypeHolder {
override val children: Map<NameToken, Vision> get() = super.childrenInternal.filter { it.key != PROTOTYPES_TOKEN }
public var prototypes: MutableVisionGroup?
get() = childrenInternal[PROTOTYPES_TOKEN] as? MutableVisionGroup
set(value) {
set(PROTOTYPES_TOKEN, value)
}
init {
prototypes?.parent = this
}
override val descriptor: NodeDescriptor get() = Solid.descriptor
/**
* Ger a prototype redirecting the request to the parent if prototype is not found
* Get a prototype redirecting the request to the parent if prototype is not found.
* If prototype is a ref, then it is unfolded until
*/
override fun getPrototype(name: Name): Solid? =
(prototypes?.get(name) as? Solid) ?: (parent as? PrototypeHolder)?.getPrototype(name)
prototypes?.get(name)?.unref ?: (parent as? PrototypeHolder)?.getPrototype(name)
/**
* Create or edit prototype node as a group
*/
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit): Unit {
(prototypes ?: Prototypes().also {
(prototypes ?: SolidGroup().also {
prototypes = it
it.parent = this
}).run(builder)
}
// /**
// * TODO add special static group to hold statics without propagation
// */
// override fun addStatic(child: VisualObject) = setChild(NameToken("@static(${child.hashCode()})"), child)
override fun createGroup(): SolidGroup = SolidGroup()
override fun update(change: VisionChange) {
@ -87,50 +78,3 @@ public fun VisionContainerBuilder<Vision>.group(
@VisionBuilder
public fun VisionContainerBuilder<Vision>.group(name: String, action: SolidGroup.() -> Unit = {}): SolidGroup =
SolidGroup().apply(action).also { set(name, it) }
/**
* A special class which works as a holder for prototypes
*/
internal class Prototypes(
children: MutableMap<NameToken, Vision> = hashMapOf(),
) : VisionGroupBase(children), PrototypeHolder {
override fun getProperty(
name: Name,
inherit: Boolean,
includeStyles: Boolean,
includeDefaults: Boolean,
): MetaItem? = null
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
error("Can't set property of a prototypes container")
}
override val descriptor: NodeDescriptor? = null
override fun prototypes(builder: VisionContainerBuilder<Solid>.() -> Unit) {
apply(builder)
}
override fun getPrototype(name: Name): Solid? = get(name) as? Solid
}
internal class PrototypeSerializer : KSerializer<MutableVisionGroup> {
private val mapSerializer: KSerializer<Map<NameToken, Vision>> =
MapSerializer(
NameToken.serializer(),
PolymorphicSerializer(Vision::class)
)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
override fun deserialize(decoder: Decoder): MutableVisionGroup {
val map = mapSerializer.deserialize(decoder)
return Prototypes(map.toMutableMap())
}
override fun serialize(encoder: Encoder, value: MutableVisionGroup) {
mapSerializer.serialize(encoder, value.children)
}
}

View File

@ -11,10 +11,27 @@ import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.*
import space.kscience.visionforge.*
public interface SolidReference : Solid {
public interface SolidReference : VisionGroup {
/**
* The prototype for this reference. Always returns a "real" prototype, not a reference
*/
public val prototype: Solid
}
/**
* Get a vision prototype if it is a [SolidReference] or vision itself if it is not.
* Unref is recursive, so it always returns a non-reference.
*/
public val Vision.unref: Solid
get() = when (this) {
is SolidReference -> prototype.unref
is Solid -> this
else -> error("This Vision is neither Solid nor SolidReference")
}
private fun SolidReference.getRefProperty(
name: Name,
inherit: Boolean,
@ -31,6 +48,12 @@ private fun SolidReference.getRefProperty(
}
}.merge()
private fun childToken(childName: Name): NameToken =
NameToken(SolidReferenceGroup.REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
private fun childPropertyName(childName: Name, propertyName: Name): Name =
childToken(childName) + propertyName
/**
* A reference [Solid] to reuse a template object
*/
@ -38,48 +61,24 @@ private fun SolidReference.getRefProperty(
@SerialName("solid.ref")
public class SolidReferenceGroup(
public val refName: Name,
) : SolidBase(), SolidReference, VisionGroup {
) : VisionBase(), SolidReference, VisionGroup, Solid {
/**
* Recursively search for defined template in the parent
*/
override val prototype: Solid
get() {
if (parent == null) error("No parent is present for SolidReferenceGroup")
if (parent !is SolidGroup) error("Reference parent is not a group")
return (parent as? SolidGroup)?.getPrototype(refName)
?: error("Prototype with name $refName not found")
}
override val prototype: Solid by lazy {
if (parent == null) error("No parent is present for SolidReferenceGroup")
if (parent !is PrototypeHolder) error("Parent does not hold prototypes")
(parent as? PrototypeHolder)?.getPrototype(refName) ?: error("Prototype with name $refName not found")
}
override val children: Map<NameToken, Vision>
get() = (prototype as? VisionGroup)?.children
?.filter { !it.key.toString().startsWith("@") }
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
?.mapValues {
ReferenceChild(it.key.asName())
ReferenceChild(this, it.key.asName())
} ?: emptyMap()
private fun childToken(childName: Name): NameToken =
NameToken(REFERENCE_CHILD_PROPERTY_PREFIX, childName.toString())
private fun childPropertyName(childName: Name, propertyName: Name): Name =
childToken(childName) + propertyName
private fun getChildProperty(childName: Name, propertyName: Name): MetaItem? {
return getOwnProperty(childPropertyName(childName, propertyName))
}
private fun setChildProperty(childName: Name, propertyName: Name, item: MetaItem?, notify: Boolean) {
setProperty(childPropertyName(childName, propertyName), item, notify)
}
private fun prototypeFor(name: Name): Solid {
return if (name.isEmpty()) prototype else {
val proto = (prototype as? SolidGroup)?.get(name)
?: error("Prototype with name $name not found in SolidReferenceGroup $refName")
proto as? Solid ?: error("Prototype with name $name is ${proto::class} but expected Solid")
}
}
override fun getProperty(
name: Name,
inherit: Boolean,
@ -94,20 +93,31 @@ public class SolidReferenceGroup(
* A ProxyChild is created temporarily only to interact with properties, it does not store any values
* (properties are stored in external cache) and created and destroyed on-demand).
*/
private inner class ReferenceChild(private val childName: Name) : SolidReference, VisionGroup {
override val prototype: Solid get() = prototypeFor(childName)
private class ReferenceChild(
val owner: SolidReferenceGroup,
private val childName: Name
) : SolidReference, VisionGroup {
override val prototype: Solid by lazy {
if (childName.isEmpty()) owner.prototype else {
val proto = (owner.prototype as? VisionGroup)?.get(childName)
?: error("Prototype with name $childName not found in SolidReferenceGroup ${owner.refName}")
proto.unref as? Solid ?: error("Prototype with name $childName is ${proto::class} but expected Solid")
}
}
override val children: Map<NameToken, Vision>
get() = (prototype as? VisionGroup)?.children
?.filter { !it.key.toString().startsWith("@") }
?.filter { it.key != SolidGroup.PROTOTYPES_TOKEN }
?.mapValues { (key, _) ->
ReferenceChild(childName + key.asName())
ReferenceChild(owner, childName + key.asName())
} ?: emptyMap()
override fun getOwnProperty(name: Name): MetaItem? = getChildProperty(childName, name)
override fun getOwnProperty(name: Name): MetaItem? =
owner.getOwnProperty(childPropertyName(childName, name))
override fun setProperty(name: Name, item: MetaItem?, notify: Boolean) {
setChildProperty(childName, name, item, notify)
owner.setProperty(childPropertyName(childName, name), item, notify)
}
override fun getProperty(
@ -124,7 +134,7 @@ public class SolidReferenceGroup(
override var parent: VisionGroup?
get() {
val parentName = childName.cutLast()
return if (parentName.isEmpty()) this@SolidReferenceGroup else ReferenceChild(parentName)
return if (parentName.isEmpty()) owner else ReferenceChild(owner, parentName)
}
set(_) {
error("Setting a parent for a reference child is not possible")
@ -132,7 +142,7 @@ public class SolidReferenceGroup(
@DFExperimental
override val propertyChanges: Flow<Name>
get() = this@SolidReferenceGroup.propertyChanges.mapNotNull { name ->
get() = owner.propertyChanges.mapNotNull { name ->
if (name.startsWith(childToken(childName))) {
name.cutFirst()
} else {
@ -141,7 +151,7 @@ public class SolidReferenceGroup(
}
override fun invalidateProperty(propertyName: Name) {
this@SolidReferenceGroup.invalidateProperty(childPropertyName(childName, propertyName))
owner.invalidateProperty(childPropertyName(childName, propertyName))
}
override fun update(change: VisionChange) {
@ -159,12 +169,6 @@ public class SolidReferenceGroup(
}
}
/**
* Get a vision prototype if it is a [SolidReferenceGroup] or vision itself if it is not
*/
public val Vision.prototype: Vision
get() = if (this is SolidReference) prototype.prototype else this
/**
* Create ref for existing prototype
*/