diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e2861e2..d6daac6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Add Meta and MutableMeta delegates for convertable and serializeable ### Changed +- Descriptor `children` renamed to `nodes` ### Deprecated - `node(key,converter)` in favor of `serializable` delegate diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/MetaProperty.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/MetaProperty.kt index e79ce931..85435602 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/MetaProperty.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/MetaProperty.kt @@ -1,11 +1,7 @@ package space.kscience.dataforge.properties -import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.meta.ObservableMutableMeta -import space.kscience.dataforge.meta.transformations.MetaConverter -import space.kscience.dataforge.meta.transformations.nullableMetaToObject -import space.kscience.dataforge.meta.transformations.nullableObjectToMeta +import space.kscience.dataforge.meta.* import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.startsWith @@ -18,14 +14,14 @@ public class MetaProperty( ) : Property { override var value: T? - get() = converter.nullableMetaToObject(meta[name]) + get() = converter.readNullable(meta[name]) set(value) { - meta[name] = converter.nullableObjectToMeta(value) ?: Meta.EMPTY + meta[name] = converter.convertNullable(value) ?: Meta.EMPTY } override fun onChange(owner: Any?, callback: (T?) -> Unit) { meta.onChange(owner) { name -> - if (name.startsWith(this@MetaProperty.name)) callback(converter.nullableMetaToObject(this[name])) + if (name.startsWith(this@MetaProperty.name)) callback(converter.readNullable(this[name])) } } diff --git a/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt b/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt index c1271537..617e85cc 100644 --- a/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt +++ b/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt @@ -3,9 +3,11 @@ package space.kscience.dataforge.descriptors import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.junit.jupiter.api.Test -import space.kscience.dataforge.meta.* +import space.kscience.dataforge.meta.Scheme +import space.kscience.dataforge.meta.SchemeSpec import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.transformations.MetaConverter +import space.kscience.dataforge.meta.int +import space.kscience.dataforge.meta.string private class TestScheme: Scheme(){ diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/JsonMeta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/JsonMeta.kt index 36373582..8da8b2d3 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/JsonMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/JsonMeta.kt @@ -31,7 +31,7 @@ private fun Meta.toJsonWithIndex(descriptor: MetaDescriptor?, index: String?): J val pairs: MutableList> = items.entries.groupBy { it.key.body }.mapTo(ArrayList()) { (body, list) -> - val childDescriptor = descriptor?.children?.get(body) + val childDescriptor = descriptor?.nodes?.get(body) if (list.size == 1) { val (token, element) = list.first() //do not add an empty element diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaConverter.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt similarity index 61% rename from dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaConverter.kt rename to dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt index 17774913..0da36d17 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaConverter.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt @@ -1,19 +1,19 @@ -package space.kscience.dataforge.meta.transformations +package space.kscience.dataforge.meta import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToJsonElement import kotlinx.serialization.serializer -import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.misc.DFExperimental import kotlin.reflect.KType import kotlin.reflect.typeOf + /** * A converter of generic object to and from [Meta] */ -public interface MetaConverter { +public interface MetaConverter: MetaSpec { /** * Runtime type of [T] @@ -23,32 +23,32 @@ public interface MetaConverter { /** * A descriptor for resulting meta */ - public val descriptor: MetaDescriptor get() = MetaDescriptor.EMPTY + override val descriptor: MetaDescriptor get() = MetaDescriptor.EMPTY /** - * Attempt conversion of [meta] to an object or return null if conversion failed + * Attempt conversion of [source] to an object or return null if conversion failed */ - public fun metaToObjectOrNull(meta: Meta): T? + override fun readOrNull(source: Meta): T? - public fun metaToObject(meta: Meta): T = - metaToObjectOrNull(meta) ?: error("Meta $meta could not be interpreted by $this") + override fun read(source: Meta): T = + readOrNull(source) ?: error("Meta $source could not be interpreted by $this") - public fun objectToMeta(obj: T): Meta + public fun convert(obj: T): Meta public companion object { public val meta: MetaConverter = object : MetaConverter { override val type: KType = typeOf() - override fun metaToObjectOrNull(meta: Meta): Meta = meta - override fun objectToMeta(obj: Meta): Meta = obj + override fun readOrNull(source: Meta): Meta = source + override fun convert(obj: Meta): Meta = obj } public val value: MetaConverter = object : MetaConverter { override val type: KType = typeOf() - override fun metaToObjectOrNull(meta: Meta): Value? = meta.value - override fun objectToMeta(obj: Value): Meta = Meta(obj) + override fun readOrNull(source: Meta): Value? = source.value + override fun convert(obj: Value): Meta = Meta(obj) } public val string: MetaConverter = object : MetaConverter { @@ -59,8 +59,8 @@ public interface MetaConverter { } - override fun metaToObjectOrNull(meta: Meta): String? = meta.string - override fun objectToMeta(obj: String): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): String? = source.string + override fun convert(obj: String): Meta = Meta(obj.asValue()) } public val boolean: MetaConverter = object : MetaConverter { @@ -70,8 +70,8 @@ public interface MetaConverter { valueType(ValueType.BOOLEAN) } - override fun metaToObjectOrNull(meta: Meta): Boolean? = meta.boolean - override fun objectToMeta(obj: Boolean): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Boolean? = source.boolean + override fun convert(obj: Boolean): Meta = Meta(obj.asValue()) } public val number: MetaConverter = object : MetaConverter { @@ -81,8 +81,8 @@ public interface MetaConverter { valueType(ValueType.NUMBER) } - override fun metaToObjectOrNull(meta: Meta): Number? = meta.number - override fun objectToMeta(obj: Number): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Number? = source.number + override fun convert(obj: Number): Meta = Meta(obj.asValue()) } public val double: MetaConverter = object : MetaConverter { @@ -92,8 +92,8 @@ public interface MetaConverter { valueType(ValueType.NUMBER) } - override fun metaToObjectOrNull(meta: Meta): Double? = meta.double - override fun objectToMeta(obj: Double): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Double? = source.double + override fun convert(obj: Double): Meta = Meta(obj.asValue()) } public val float: MetaConverter = object : MetaConverter { @@ -103,8 +103,8 @@ public interface MetaConverter { valueType(ValueType.NUMBER) } - override fun metaToObjectOrNull(meta: Meta): Float? = meta.float - override fun objectToMeta(obj: Float): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Float? = source.float + override fun convert(obj: Float): Meta = Meta(obj.asValue()) } public val int: MetaConverter = object : MetaConverter { @@ -114,8 +114,8 @@ public interface MetaConverter { valueType(ValueType.NUMBER) } - override fun metaToObjectOrNull(meta: Meta): Int? = meta.int - override fun objectToMeta(obj: Int): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Int? = source.int + override fun convert(obj: Int): Meta = Meta(obj.asValue()) } public val long: MetaConverter = object : MetaConverter { @@ -125,8 +125,8 @@ public interface MetaConverter { valueType(ValueType.NUMBER) } - override fun metaToObjectOrNull(meta: Meta): Long? = meta.long - override fun objectToMeta(obj: Long): Meta = Meta(obj.asValue()) + override fun readOrNull(source: Meta): Long? = source.long + override fun convert(obj: Long): Meta = Meta(obj.asValue()) } public inline fun > enum(): MetaConverter = object : MetaConverter { @@ -138,9 +138,9 @@ public interface MetaConverter { } @Suppress("USELESS_CAST") - override fun metaToObjectOrNull(meta: Meta): E = meta.enum() as? E ?: error("The Item is not a Enum") + override fun readOrNull(source: Meta): E = source.enum() as? E ?: error("The Item is not a Enum") - override fun objectToMeta(obj: E): Meta = Meta(obj.asValue()) + override fun convert(obj: E): Meta = Meta(obj.asValue()) } public fun valueList( @@ -153,9 +153,9 @@ public interface MetaConverter { valueType(ValueType.LIST) } - override fun metaToObjectOrNull(meta: Meta): List? = meta.value?.list?.map(reader) + override fun readOrNull(source: Meta): List? = source.value?.list?.map(reader) - override fun objectToMeta(obj: List): Meta = Meta(obj.map(writer).asValue()) + override fun convert(obj: List): Meta = Meta(obj.map(writer).asValue()) } /** @@ -168,12 +168,12 @@ public interface MetaConverter { override val type: KType = typeOf() private val serializer: KSerializer = serializer() - override fun metaToObjectOrNull(meta: Meta): T? { - val json = meta.toJson(descriptor) + override fun readOrNull(source: Meta): T? { + val json = source.toJson(descriptor) return Json.decodeFromJsonElement(serializer, json) } - override fun objectToMeta(obj: T): Meta { + override fun convert(obj: T): Meta { val json = Json.encodeToJsonElement(obj) return json.toMeta(descriptor) } @@ -183,7 +183,7 @@ public interface MetaConverter { } } -public fun MetaConverter.nullableMetaToObject(item: Meta?): T? = item?.let { metaToObject(it) } -public fun MetaConverter.nullableObjectToMeta(obj: T?): Meta? = obj?.let { objectToMeta(it) } +public fun MetaConverter.readNullable(item: Meta?): T? = item?.let { read(it) } +public fun MetaConverter.convertNullable(obj: T?): Meta? = obj?.let { convert(it) } -public fun MetaConverter.valueToObject(value: Value): T? = metaToObject(Meta(value)) +public fun MetaConverter.readValue(value: Value): T? = read(Meta(value)) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt index 42e4fe14..70ff460d 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt @@ -1,7 +1,6 @@ package space.kscience.dataforge.meta import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName @@ -20,7 +19,7 @@ public fun MetaProvider.convertable( converter: MetaConverter, key: Name? = null, ): ReadOnlyProperty = ReadOnlyProperty { _, property -> - get(key ?: property.name.asName())?.let { converter.metaToObject(it) } + get(key ?: property.name.asName())?.let { converter.read(it) } } /** @@ -46,7 +45,7 @@ public fun Meta.listOfConvertable( key: Name? = null, ): ReadOnlyProperty> = ReadOnlyProperty{_, property -> val name = key ?: property.name.asName() - getIndexed(name).values.map { converter.metaToObject(it) } + getIndexed(name).values.map { converter.read(it) } } @DFExperimental diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt new file mode 100644 index 00000000..be21cef7 --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt @@ -0,0 +1,18 @@ +package space.kscience.dataforge.meta + +import space.kscience.dataforge.meta.descriptors.Described + +public interface MetaSpec : Described { + + /** + * Read the source meta into an object and return null if Meta could not be interpreted as a target type + */ + public fun readOrNull(source: Meta): T? + + /** + * Read generic read-only meta with this [MetaSpec] producing instance of the desired type. + * Throws an error if conversion could not be done. + */ + public fun read(source: Meta): T = readOrNull(source) ?: error("Meta $source could not be interpreted by $this") +} + diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaTransformation.kt similarity index 98% rename from dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt rename to dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaTransformation.kt index d41365a6..dbf94f0f 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/transformations/MetaTransformation.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaTransformation.kt @@ -1,6 +1,5 @@ -package space.kscience.dataforge.meta.transformations +package space.kscience.dataforge.meta -import space.kscience.dataforge.meta.* import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import kotlin.jvm.JvmInline diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt index d77348dd..f6e96109 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt @@ -1,7 +1,6 @@ package space.kscience.dataforge.meta import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName @@ -33,12 +32,12 @@ public fun MutableMetaProvider.convertable( object : ReadWriteProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T? { val name = key ?: property.name.asName() - return get(name)?.let { converter.metaToObject(it) } + return get(name)?.let { converter.read(it) } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { val name = key ?: property.name.asName() - set(name, value?.let { converter.objectToMeta(it) }) + set(name, value?.let { converter.convert(it) }) } } @@ -66,12 +65,12 @@ public fun MutableMeta.listOfConvertable( ): ReadWriteProperty> = object : ReadWriteProperty> { override fun getValue(thisRef: Any?, property: KProperty<*>): List { val name = key ?: property.name.asName() - return getIndexed(name).values.map { converter.metaToObject(it) } + return getIndexed(name).values.map { converter.read(it) } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: List) { val name = key ?: property.name.asName() - setIndexed(name, value.map { converter.objectToMeta(it) }) + setIndexed(name, value.map { converter.convert(it) }) } } 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 ab504733..ff8d8095 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 @@ -7,9 +7,11 @@ import space.kscience.dataforge.meta.descriptors.validate import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.ThreadSafe import space.kscience.dataforge.names.* +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty /** - * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. + * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaSpec]. * Default item provider and [MetaDescriptor] are optional */ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurable { @@ -165,23 +167,124 @@ public inline fun T.copy(spec: SchemeSpec, block: T.() -> Unit = */ public open class SchemeSpec( private val builder: () -> T, -) : Specification { +) : MetaSpec { override val descriptor: MetaDescriptor? get() = null - override fun read(source: Meta): T = builder().also { + override fun readOrNull(source: Meta): T = builder().also { it.initialize(MutableMeta(), source, descriptor) } - override fun write(target: MutableMeta): T = empty().also { + public fun write(target: MutableMeta): T = empty().also { it.initialize(target, Meta.EMPTY, descriptor) } - override fun empty(): T = builder().also { + /** + * Generate an empty object + */ + public fun empty(): T = builder().also { it.initialize(MutableMeta(), Meta.EMPTY, descriptor) } - @Suppress("OVERRIDE_BY_INLINE") - final override inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action) + /** + * A convenience method to use specifications in builders + */ + public inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action) -} \ No newline at end of file +} + + + +/** + * Update a [MutableMeta] using given specification + */ +public fun MutableMeta.updateWith( + spec: SchemeSpec, + action: T.() -> Unit, +): T = spec.write(this).apply(action) + + +/** + * Update configuration using given specification + */ +public fun Configurable.updateWith( + spec: SchemeSpec, + action: T.() -> Unit, +): T = spec.write(meta).apply(action) + + +/** + * A delegate that uses a [MetaSpec] to wrap a child of this provider + */ +public fun MutableMeta.scheme( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty = object : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T { + val name = key ?: property.name.asName() + return spec.write(getOrCreate(name)) + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { + val name = key ?: property.name.asName() + set(name, value.toMeta()) + } +} + +public fun Scheme.scheme( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty = meta.scheme(spec, key) + +/** + * A delegate that uses a [MetaSpec] to wrap a child of this provider. + * Returns null if meta with given name does not exist. + */ +public fun MutableMeta.schemeOrNull( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty = object : ReadWriteProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T? { + val name = key ?: property.name.asName() + return if (get(name) == null) null else spec.write(getOrCreate(name)) + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { + val name = key ?: property.name.asName() + if (value == null) remove(name) + else set(name, value.toMeta()) + } +} + +public fun Scheme.schemeOrNull( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty = meta.schemeOrNull(spec, key) + +/** + * A delegate that uses a [MetaSpec] to wrap a list of child providers. + * If children are mutable, the changes in list elements are reflected on them. + * The list is a snapshot of children state, so change in structure is not reflected on its composition. + */ +@DFExperimental +public fun MutableMeta.listOfScheme( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty> = object : ReadWriteProperty> { + override fun getValue(thisRef: Any?, property: KProperty<*>): List { + val name = key ?: property.name.asName() + return getIndexed(name).values.map { spec.write(it as MutableMeta) } + } + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: List) { + val name = key ?: property.name.asName() + setIndexed(name, value.map { it.toMeta() }) + } +} + + +@DFExperimental +public fun Scheme.listOfScheme( + spec: SchemeSpec, + key: Name? = null, +): ReadWriteProperty> = meta.listOfScheme(spec, key) 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 deleted file mode 100644 index 7f3dd2a6..00000000 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Specification.kt +++ /dev/null @@ -1,137 +0,0 @@ -package space.kscience.dataforge.meta - -import space.kscience.dataforge.meta.descriptors.Described -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty - -public interface ReadOnlySpecification : Described { - - /** - * Read generic read-only meta with this [Specification] producing instance of desired type. - * The source is not mutated even if it is in theory mutable - */ - public fun read(source: Meta): T - - /** - * Generate an empty object - */ - public fun empty(): T - - /** - * A convenience method to use specifications in builders - */ - public operator fun invoke(action: T.() -> Unit): T = empty().apply(action) -} - - -/** - * Allows to apply custom configuration in a type safe way to simple untyped configuration. - * By convention [Scheme] companion should inherit this class - * - */ -public interface Specification : ReadOnlySpecification { - /** - * Wrap [MutableMeta], using it as inner storage (changes to [Specification] are reflected on [MutableMeta] - */ - public fun write(target: MutableMeta): T -} - -/** - * Update a [MutableMeta] using given specification - */ -public fun MutableMeta.updateWith( - spec: Specification, - action: T.() -> Unit, -): T = spec.write(this).apply(action) - - -/** - * Update configuration using given specification - */ -public fun Configurable.updateWith( - spec: Specification, - action: T.() -> Unit, -): T = spec.write(meta).apply(action) - -// -//public fun > MutableMeta.withSpec(spec: Specification): M? = -// spec.write(it) - -/** - * A delegate that uses a [Specification] to wrap a child of this provider - */ -public fun MutableMeta.spec( - spec: Specification, - key: Name? = null, -): ReadWriteProperty = object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T { - val name = key ?: property.name.asName() - return spec.write(getOrCreate(name)) - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { - val name = key ?: property.name.asName() - set(name, value.toMeta()) - } -} - -public fun Scheme.spec( - spec: Specification, - key: Name? = null, -): ReadWriteProperty = meta.spec(spec, key) - -/** - * A delegate that uses a [Specification] to wrap a child of this provider. - * Returns null if meta with given name does not exist. - */ -public fun MutableMeta.specOrNull( - spec: Specification, - key: Name? = null, -): ReadWriteProperty = object : ReadWriteProperty { - override fun getValue(thisRef: Any?, property: KProperty<*>): T? { - val name = key ?: property.name.asName() - return if (get(name) == null) null else spec.write(getOrCreate(name)) - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { - val name = key ?: property.name.asName() - if (value == null) remove(name) - else set(name, value.toMeta()) - } -} - -public fun Scheme.specOrNull( - spec: Specification, - key: Name? = null, -): ReadWriteProperty = meta.specOrNull(spec, key) - -/** - * A delegate that uses a [Specification] to wrap a list of child providers. - * If children are mutable, the changes in list elements are reflected on them. - * The list is a snapshot of children state, so change in structure is not reflected on its composition. - */ -@DFExperimental -public fun MutableMeta.listOfSpec( - spec: Specification, - key: Name? = null, -): ReadWriteProperty> = object : ReadWriteProperty> { - override fun getValue(thisRef: Any?, property: KProperty<*>): List { - val name = key ?: property.name.asName() - return getIndexed(name).values.map { spec.write(it as MutableMeta) } - } - - override fun setValue(thisRef: Any?, property: KProperty<*>, value: List) { - val name = key ?: property.name.asName() - setIndexed(name, value.map { it.toMeta() }) - } -} - - -@DFExperimental -public fun Scheme.listOfSpec( - spec: Specification, - key: Name? = null, -): ReadWriteProperty> = meta.listOfSpec(spec, key) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptor.kt index 742b89ed..12bbd5d4 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptor.kt @@ -27,7 +27,7 @@ public enum class ValueRestriction { /** * The descriptor for a meta * @param description description text - * @param children child descriptors for this node + * @param nodes child descriptors for this node * @param multiple True if same name siblings with this name are allowed * @param valueRestriction The requirements for node content * @param valueTypes list of allowed types for [Meta.value], null if all values are allowed. @@ -39,7 +39,7 @@ public enum class ValueRestriction { @Serializable public data class MetaDescriptor( public val description: String? = null, - public val children: Map = emptyMap(), + public val nodes: Map = emptyMap(), public val multiple: Boolean = false, public val valueRestriction: ValueRestriction = ValueRestriction.NONE, public val valueTypes: List? = null, @@ -47,6 +47,9 @@ public data class MetaDescriptor( public val defaultValue: Value? = null, public val attributes: Meta = Meta.EMPTY, ) { + @Deprecated("Replace by nodes", ReplaceWith("nodes")) + public val children: Map get() = nodes + /** * A node constructed of default values for this descriptor and its children */ @@ -55,7 +58,7 @@ public data class MetaDescriptor( defaultValue?.let { defaultValue -> this.value = defaultValue } - children.forEach { (key, descriptor) -> + nodes.forEach { (key, descriptor) -> set(key, descriptor.defaultNode) } } @@ -67,13 +70,13 @@ public data class MetaDescriptor( } } -public val MetaDescriptor.required: Boolean get() = valueRestriction == ValueRestriction.REQUIRED || children.values.any { required } +public val MetaDescriptor.required: Boolean get() = valueRestriction == ValueRestriction.REQUIRED || nodes.values.any { required } public val MetaDescriptor.allowedValues: List? get() = attributes[MetaDescriptor.ALLOWED_VALUES_KEY]?.value?.list public operator fun MetaDescriptor.get(name: Name): MetaDescriptor? = when (name.length) { 0 -> this - 1 -> children[name.firstOrNull()!!.toString()] + 1 -> nodes[name.firstOrNull()!!.toString()] else -> get(name.firstOrNull()!!.asName())?.get(name.cutFirst()) } @@ -95,7 +98,7 @@ public fun MetaDescriptor.validate(item: Meta?): Boolean { if (item == null) return !required if (!validate(item.value)) return false - children.forEach { (key, childDescriptor) -> + nodes.forEach { (key, childDescriptor) -> if (!childDescriptor.validate(item[key])) return false } return true diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt index 751d2525..5d4d81ad 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt @@ -80,7 +80,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() { public fun from(descriptor: MetaDescriptor) { description = descriptor.description - children.putAll(descriptor.children.mapValues { it.value.toBuilder() }) + children.putAll(descriptor.nodes.mapValues { it.value.toBuilder() }) multiple = descriptor.multiple valueRestriction = descriptor.valueRestriction valueTypes = descriptor.valueTypes @@ -92,7 +92,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() { @PublishedApi internal fun build(): MetaDescriptor = MetaDescriptor( description = description, - children = children.mapValues { it.value.build() }, + nodes = children.mapValues { it.value.build() }, multiple = multiple, valueRestriction = valueRestriction, valueTypes = valueTypes, @@ -143,7 +143,7 @@ public fun MetaDescriptorBuilder.required() { private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply { description = this@toBuilder.description - children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() } + children = this@toBuilder.nodes.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() } multiple = this@toBuilder.multiple valueRestriction = this@toBuilder.valueRestriction valueTypes = this@toBuilder.valueTypes diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaDelegateTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaDelegateTest.kt index 7a2dbc22..4b99cc3b 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaDelegateTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaDelegateTest.kt @@ -20,7 +20,7 @@ class MetaDelegateTest { var myValue by string() var safeValue by double(2.2) var enumValue by enum(TestEnum.YES) - var inner by spec(InnerScheme) + var inner by scheme(InnerScheme) companion object : SchemeSpec(::TestScheme) } diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt index 329d9c5a..19d16c68 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt @@ -6,7 +6,7 @@ import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.GoalExecutionRestriction import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MetaRepr -import space.kscience.dataforge.meta.Specification +import space.kscience.dataforge.meta.MetaSpec import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.misc.DfType @@ -43,10 +43,10 @@ public interface Task : Described { } /** - * A [Task] with [Specification] for wrapping and unwrapping task configuration + * A [Task] with [MetaSpec] for wrapping and unwrapping task configuration */ public interface TaskWithSpec : Task { - public val spec: Specification + public val spec: MetaSpec override val descriptor: MetaDescriptor? get() = spec.descriptor public suspend fun execute(workspace: Workspace, taskName: Name, configuration: C): TaskResult @@ -55,11 +55,11 @@ public interface TaskWithSpec : Task { execute(workspace, taskName, spec.read(taskMeta)) } -public suspend fun TaskWithSpec.execute( - workspace: Workspace, - taskName: Name, - block: C.() -> Unit = {}, -): TaskResult = execute(workspace, taskName, spec(block)) +//public suspend fun TaskWithSpec.execute( +// workspace: Workspace, +// taskName: Name, +// block: C.() -> Unit = {}, +//): TaskResult = execute(workspace, taskName, spec(block)) public class TaskResultBuilder( public val workspace: Workspace, @@ -76,7 +76,6 @@ public class TaskResultBuilder( * @param descriptor of meta accepted by this task * @param builder for resulting data set */ -@Suppress("FunctionName") public fun Task( resultType: KType, descriptor: MetaDescriptor? = null, @@ -98,7 +97,6 @@ public fun Task( } } -@Suppress("FunctionName") public inline fun Task( descriptor: MetaDescriptor? = null, noinline builder: suspend TaskResultBuilder.() -> Unit, @@ -116,10 +114,10 @@ public inline fun Task( @Suppress("FunctionName") public fun Task( resultType: KType, - specification: Specification, + specification: MetaSpec, builder: suspend TaskResultBuilder.(C) -> Unit, ): TaskWithSpec = object : TaskWithSpec { - override val spec: Specification = specification + override val spec: MetaSpec = specification override suspend fun execute( workspace: Workspace, @@ -135,8 +133,7 @@ public fun Task( } } -@Suppress("FunctionName") public inline fun Task( - specification: Specification, + specification: MetaSpec, noinline builder: suspend TaskResultBuilder.(C) -> Unit, ): Task = Task(typeOf(), specification, builder) \ No newline at end of file diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt index 1538460f..5489e200 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt @@ -7,8 +7,8 @@ import space.kscience.dataforge.context.Global import space.kscience.dataforge.data.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MetaRepr +import space.kscience.dataforge.meta.MetaSpec import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.meta.Specification import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder import space.kscience.dataforge.misc.DFBuilder @@ -68,7 +68,7 @@ public inline fun TaskContainer.task( } public inline fun TaskContainer.task( - specification: Specification, + specification: MetaSpec, noinline builder: suspend TaskResultBuilder.(C) -> Unit, ): PropertyDelegateProvider>> = PropertyDelegateProvider { _, property -> val taskName = Name.parse(property.name)