From 679175391abd12cce5c42ae932148894ed4a8f47 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 18 Jul 2021 16:33:37 +0300 Subject: [PATCH] Simplify Scheme even more. Add serialization --- build.gradle.kts | 2 +- dataforge-meta/api/dataforge-meta.api | 37 ++++++-- .../kscience/dataforge/meta/MetaBuilder.kt | 2 + .../dataforge/meta/MutableItemProvider.kt | 23 +++++ .../space/kscience/dataforge/meta/Scheme.kt | 84 ++++++------------- .../kscience/dataforge/meta/Specification.kt | 2 +- .../kscience/dataforge/meta/SchemeTest.kt | 10 +-- .../dataforge/meta/SpecificationTest.kt | 11 +-- 8 files changed, 89 insertions(+), 82 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 246b515d..46d44b9d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { allprojects { group = "space.kscience" - version = "0.5.0" + version = "0.5.0-dev-2" } subprojects { diff --git a/dataforge-meta/api/dataforge-meta.api b/dataforge-meta/api/dataforge-meta.api index 26a017bf..d36e6135 100644 --- a/dataforge-meta/api/dataforge-meta.api +++ b/dataforge-meta/api/dataforge-meta.api @@ -169,7 +169,9 @@ public final class space/kscience/dataforge/meta/MetaBase$Companion { } public final class space/kscience/dataforge/meta/MetaBuilder : space/kscience/dataforge/meta/AbstractMutableMeta { + public static final field Companion Lspace/kscience/dataforge/meta/MetaBuilder$Companion; public fun ()V + public synthetic fun (ILjava/util/Map;Lkotlinx/serialization/internal/SerializationConstructorMarker;)V public synthetic fun empty$dataforge_meta ()Lspace/kscience/dataforge/meta/MutableMeta; public final fun put (Ljava/lang/String;Ljava/lang/Boolean;)V public final fun put (Ljava/lang/String;Ljava/lang/Enum;)V @@ -198,6 +200,22 @@ public final class space/kscience/dataforge/meta/MetaBuilder : space/kscience/da public synthetic fun wrapNode (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/MutableMeta; } +public final class space/kscience/dataforge/meta/MetaBuilder$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Lspace/kscience/dataforge/meta/MetaBuilder$$serializer; + public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/MetaBuilder; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/MetaBuilder;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class space/kscience/dataforge/meta/MetaBuilder$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public final class space/kscience/dataforge/meta/MetaBuilderKt { public static final fun Meta (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MetaBuilder; public static final fun toMutableMeta (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/MetaBuilder; @@ -364,6 +382,15 @@ public final class space/kscience/dataforge/meta/MutableItemProviderKt { public static final fun withDefault (Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/ItemProvider;)Lspace/kscience/dataforge/meta/MutableItemProvider; } +public final class space/kscience/dataforge/meta/MutableItemProviderSerializer : kotlinx/serialization/KSerializer { + public fun ()V + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/MutableItemProvider; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/MutableItemProvider;)V +} + public abstract interface class space/kscience/dataforge/meta/MutableMeta : space/kscience/dataforge/meta/MutableItemProvider, space/kscience/dataforge/meta/TypedMeta { public abstract fun getItems ()Ljava/util/Map; } @@ -410,10 +437,8 @@ public abstract interface class space/kscience/dataforge/meta/ReadOnlySpecificat public class space/kscience/dataforge/meta/Scheme : space/kscience/dataforge/meta/MetaRepr, space/kscience/dataforge/meta/ObservableItemProvider, space/kscience/dataforge/meta/descriptors/Described { public fun ()V - public fun (Lspace/kscience/dataforge/meta/ObservableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;Lspace/kscience/dataforge/meta/ItemProvider;)V - public synthetic fun (Lspace/kscience/dataforge/meta/ObservableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;Lspace/kscience/dataforge/meta/ItemProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - protected fun getDefaultItem (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMetaItem; - public fun getDefaultLayer ()Lspace/kscience/dataforge/meta/Meta; + public fun (Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;)V + public synthetic fun (Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/ItemDescriptor; public final fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor; public fun getItem (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMetaItem; @@ -430,8 +455,8 @@ public final class space/kscience/dataforge/meta/SchemeKt { public static final fun invoke (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme; public static final fun isEmpty (Lspace/kscience/dataforge/meta/Scheme;)Z public static final fun retarget (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/MutableItemProvider;)Lspace/kscience/dataforge/meta/Scheme; - public static final fun wrap (Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/ItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;)Lspace/kscience/dataforge/meta/Scheme; - public static synthetic fun wrap$default (Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/ItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Scheme; + public static final fun wrap (Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/ItemProvider;)Lspace/kscience/dataforge/meta/Scheme; + public static synthetic fun wrap$default (Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/ItemProvider;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Scheme; } public class space/kscience/dataforge/meta/SchemeSpec : space/kscience/dataforge/meta/Specification, space/kscience/dataforge/meta/descriptors/Described { diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaBuilder.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaBuilder.kt index 4574ce4b..c1870a77 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaBuilder.kt @@ -1,5 +1,6 @@ package space.kscience.dataforge.meta +import kotlinx.serialization.Serializable import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken @@ -13,6 +14,7 @@ import kotlin.jvm.JvmName * DSL builder for meta. Is not intended to store mutable state */ @DFBuilder +@Serializable public class MetaBuilder : AbstractMutableMeta() { override val children: MutableMap> = LinkedHashMap() diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableItemProvider.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableItemProvider.kt index 97b1af0f..c9c51556 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableItemProvider.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableItemProvider.kt @@ -1,12 +1,35 @@ package space.kscience.dataforge.meta +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder import space.kscience.dataforge.names.* import space.kscience.dataforge.values.Value +@Serializable(MutableItemProviderSerializer::class) public interface MutableItemProvider : ItemProvider { public fun setItem(name: Name, item: MetaItem?) } +/** + * A serializer form [MutableItemProvider] + */ +public class MutableItemProviderSerializer : KSerializer { + override val descriptor: SerialDescriptor = MetaSerializer.descriptor + + + override fun deserialize(decoder: Decoder): MutableItemProvider { + val meta = decoder.decodeSerializableValue(MetaSerializer) + return (meta as? MetaBuilder) ?: meta.toMutableMeta() + } + + override fun serialize(encoder: Encoder, value: MutableItemProvider) { + encoder.encodeSerializableValue(MetaSerializer, value.rootItem?.node ?: Meta.EMPTY) + } +} + public operator fun MutableItemProvider.set(name: Name, item: MetaItem?): Unit = setItem(name, item) public operator fun MutableItemProvider.set(name: Name, value: Value?): Unit = set(name, value?.asMetaItem()) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt index 1632bd51..f9768a9a 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt @@ -5,8 +5,6 @@ import space.kscience.dataforge.meta.descriptors.NodeDescriptor import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.validateItem import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.NameToken -import space.kscience.dataforge.names.asName import kotlin.jvm.Synchronized /** @@ -15,8 +13,7 @@ import kotlin.jvm.Synchronized */ public open class Scheme( private var items: ObservableItemProvider = ObservableMeta(), - final override var descriptor: NodeDescriptor? = null, - private var default: ItemProvider? = null + final override var descriptor: NodeDescriptor? = null ) : Described, MetaRepr, ObservableItemProvider { /** @@ -38,24 +35,15 @@ public open class Scheme( internal fun wrap( items: MutableItemProvider, - default: ItemProvider? = null, - descriptor: NodeDescriptor? = null, + preserveDefault: Boolean = false ) { - //use properties in the init block as default - this.default = this.items.withDefault(default) - //reset values, defaults are already saved - this.items = items.asObservable() - this.descriptor = descriptor - } - - protected open fun getDefaultItem(name: Name): MetaItem? { - return default?.get(name) ?: descriptor?.get(name)?.defaultValue + this.items = if (preserveDefault) items.withDefault(this.items).asObservable() else items.asObservable() } /** * Get a property with default */ - override fun getItem(name: Name): MetaItem? = items[name] ?: getDefaultItem(name) + override fun getItem(name: Name): MetaItem? = items[name] ?: descriptor?.get(name)?.defaultValue /** * Check if property with given [name] could be assigned to [item] @@ -70,34 +58,16 @@ public open class Scheme( */ override fun setItem(name: Name, item: MetaItem?) { val oldItem = items[name] - if (validateItem(name, item)) { - items[name] = item - } else { - error("Validation failed for property $name with value $item") + if (oldItem != item) { + if (validateItem(name, item)) { + items[name] = item + } else { + error("Validation failed for property $name with value $item") + } } } - - /** - * Provide a default layer which returns items from [default] and falls back to descriptor - * values if default value is unavailable. - * Values from [default] completely replace - */ - public open val defaultLayer: Meta - get() = object : MetaBase() { - override val items: Map = buildMap { - descriptor?.items?.forEach { (key, itemDescriptor) -> - val token = NameToken(key) - val name = token.asName() - val item = default?.get(name) ?: itemDescriptor.defaultValue - if (item != null) { - put(token, item) - } - } - } - } - - override fun toMeta(): Laminate = Laminate(items.rootNode, defaultLayer) + override fun toMeta(): Laminate = Laminate(items.rootNode, descriptor?.defaultMeta) } /** @@ -105,23 +75,13 @@ public open class Scheme( */ public fun Scheme.isEmpty(): Boolean = rootItem == null -/** - * Create a new empty [Scheme] object (including defaults) and inflate it around existing [MutableItemProvider]. - * Items already present in the scheme are used as defaults. - */ -public fun > S.wrap( - items: MutableItemProvider, - default: ItemProvider? = null, - descriptor: NodeDescriptor? = null, -): T = empty().apply { - wrap(items, default, descriptor) -} - /** * Relocate scheme target onto given [MutableItemProvider]. Old provider does not get updates anymore. * Current state of the scheme used as a default. */ -public fun T.retarget(provider: MutableItemProvider): T = apply { wrap(provider) } +public fun T.retarget(provider: MutableItemProvider): T = apply { + wrap(provider, true) +} /** * A shortcut to edit a [Scheme] object in-place @@ -135,16 +95,22 @@ public open class SchemeSpec( private val builder: () -> T, ) : Specification, Described { - override fun empty(): T = builder() + override fun read(items: ItemProvider): T = empty().also { + it.wrap(ObservableMeta().withDefault(items)) + } - override fun read(items: ItemProvider): T = wrap(ObservableMeta(), items, descriptor) - - override fun write(target: MutableItemProvider, defaultProvider: ItemProvider): T = - wrap(target, defaultProvider, descriptor) + override fun write(target: MutableItemProvider): T = empty().also { + it.wrap(target) + } //TODO Generate descriptor from Scheme class override val descriptor: NodeDescriptor? get() = null + override fun empty(): T = builder().also { + it.descriptor = descriptor + } + @Suppress("OVERRIDE_BY_INLINE") final override inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action) + } \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt index 4590785d..10562cd5 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt @@ -35,7 +35,7 @@ public interface Specification : ReadOnlySpecificat /** * Wrap [MutableItemProvider], using it as inner storage (changes to [Specification] are reflected on [MutableItemProvider] */ - public fun write(target: MutableItemProvider, defaultProvider: ItemProvider = ItemProvider.EMPTY): T + public fun write(target: MutableItemProvider): T } /** diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt index 4d614d21..308f6eee 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt @@ -7,15 +7,15 @@ import kotlin.test.assertEquals @DFExperimental class SchemeTest { @Test - fun testSchemeWrappingBeforeEdit(){ + fun testSchemeWrappingBeforeEdit() { val config = MetaBuilder() - val scheme = TestScheme.wrap(config) + val scheme = TestScheme.write(config) scheme.a = 29 assertEquals(29, config["a"].int) } @Test - fun testSchemeWrappingAfterEdit(){ + fun testSchemeWrappingAfterEdit() { val scheme = TestScheme.empty() scheme.a = 29 val config = MetaBuilder() @@ -24,10 +24,10 @@ class SchemeTest { } @Test - fun testSchemeSubscription(){ + fun testSchemeSubscription() { val scheme = TestScheme.empty() var flag: Int? = null - scheme.useProperty(TestScheme::a){a-> + scheme.useProperty(TestScheme::a) { a -> flag = a } scheme.a = 2 diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt index dfd9de19..9a57298f 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt @@ -9,16 +9,7 @@ internal class TestScheme : Scheme() { var a by int() var b by string() - companion object : Specification { - override fun empty(): TestScheme = TestScheme() - - override fun read(items: ItemProvider): TestScheme = - wrap(MetaBuilder(), items) - - override fun write(target: MutableItemProvider, defaultProvider: ItemProvider): TestScheme = - wrap(target, defaultProvider) - - } + companion object : SchemeSpec(::TestScheme) } class SpecificationTest {