Simplify Scheme even more. Add serialization

This commit is contained in:
Alexander Nozik 2021-07-18 16:33:37 +03:00
parent 14455c2b2b
commit 679175391a
8 changed files with 89 additions and 82 deletions

View File

@ -4,7 +4,7 @@ plugins {
allprojects {
group = "space.kscience"
version = "0.5.0"
version = "0.5.0-dev-2"
}
subprojects {

View File

@ -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 <init> ()V
public synthetic fun <init> (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 <init> ()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 <init> ()V
public fun <init> (Lspace/kscience/dataforge/meta/ObservableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;Lspace/kscience/dataforge/meta/ItemProvider;)V
public synthetic fun <init> (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 <init> (Lspace/kscience/dataforge/meta/MutableItemProvider;Lspace/kscience/dataforge/meta/descriptors/NodeDescriptor;)V
public synthetic fun <init> (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 {

View File

@ -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<MetaBuilder>() {
override val children: MutableMap<NameToken, TypedMetaItem<MetaBuilder>> = LinkedHashMap()

View File

@ -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<MutableItemProvider> {
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())

View File

@ -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<NameToken, MetaItem> = 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 <T : Scheme, S : Specification<T>> 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 : Scheme> T.retarget(provider: MutableItemProvider): T = apply { wrap(provider) }
public fun <T : Scheme> 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<out T : Scheme>(
private val builder: () -> T,
) : Specification<T>, 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)
}

View File

@ -35,7 +35,7 @@ public interface Specification<out T : MutableItemProvider> : 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
}
/**

View File

@ -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

View File

@ -9,16 +9,7 @@ internal class TestScheme : Scheme() {
var a by int()
var b by string()
companion object : Specification<TestScheme> {
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>(::TestScheme)
}
class SpecificationTest {