From f906fbdb0a07e9ccbb09ad4fc8bdc6af09493615 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Wed, 29 Jan 2020 21:34:51 +0300 Subject: [PATCH] Tables basics A lot of refactoring --- build.gradle.kts | 2 +- .../hep/dataforge/descriptors/annotations.kt | 130 +++++++++++++++ .../descriptors/reflectiveDescriptors.kt | 65 ++++++++ .../kotlin/hep/dataforge/data/DataFilter.kt | 3 + .../hep/dataforge/io/yaml/YamlMetaFormat.kt | 3 +- .../hep/dataforge/io/BinaryMetaFormat.kt | 2 +- .../kotlin/hep/dataforge/io/JsonMetaFormat.kt | 6 +- .../kotlin/hep/dataforge/io/MetaFormat.kt | 2 +- .../io/functions/RemoteFunctionClient.kt | 1 + .../io/functions/RemoteFunctionServer.kt | 1 + .../io/serialization/MetaSerializer.kt | 2 +- .../kotlin/hep/dataforge/io/MultipartTest.kt | 1 + .../jvmMain/kotlin/hep/dataforge/io/fileIO.kt | 2 +- .../hep/dataforge/descriptors/annotations.kt | 149 ------------------ .../kotlin/hep/dataforge/meta/Config.kt | 11 +- .../kotlin/hep/dataforge/meta/MutableMeta.kt | 5 +- .../{ => meta}/descriptors/Described.kt | 2 +- .../{ => meta}/descriptors/DescriptorMeta.kt | 2 +- .../{ => meta}/descriptors/ItemDescriptor.kt | 55 +++++-- .../kotlin/hep/dataforge/meta/mapMeta.kt | 2 +- .../meta/{ => scheme}/Configurable.kt | 22 ++- .../meta/{ => scheme}/ConfigurableDelegate.kt | 37 ++++- .../hep/dataforge/meta/{ => scheme}/Scheme.kt | 25 ++- .../meta/{ => scheme}/Specification.kt | 10 +- .../MetaTransformation.kt | 39 +++-- .../hep/dataforge/meta/MetaDelegateTest.kt | 1 + .../kotlin/hep/dataforge/meta/SchemeTest.kt | 3 + .../hep/dataforge/meta/SpecificationTest.kt | 3 + .../{ => meta}/descriptors/DescriptorTest.kt | 10 +- .../dataforge-output-html}/build.gradle.kts | 0 .../hep/dataforge/output/html/HtmlRenderer.kt | 0 .../hep/dataforge/scripting/BuildersKtTest.kt | 1 + dataforge-tables/build.gradle | 25 --- dataforge-tables/build.gradle.kts | 14 ++ .../hep/dataforge/tables/ColumnScheme.kt | 8 + .../hep/dataforge/tables/ColumnTable.kt | 35 ++++ .../kotlin/hep/dataforge/tables/ListColumn.kt | 28 ++++ .../kotlin/hep/dataforge/tables/MapRow.kt | 19 +++ .../hep/dataforge/tables/NumberColumn.kt | 94 +++++++++++ .../kotlin/hep/dataforge/tables/RowTable.kt | 26 +++ .../kotlin/hep/dataforge/tables/Table.kt | 30 ++++ .../hep/dataforge/tables/TableAccessor.kt | 37 +++++ .../hep/dataforge/workspace/GenericTask.kt | 2 +- .../kotlin/hep/dataforge/workspace/Task.kt | 2 +- .../hep/dataforge/workspace/TaskBuilder.kt | 2 +- .../workspace/SimpleWorkspaceTest.kt | 1 + settings.gradle.kts | 3 +- 47 files changed, 664 insertions(+), 259 deletions(-) create mode 100644 dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/annotations.kt create mode 100644 dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/reflectiveDescriptors.kt delete mode 100644 dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/{ => meta}/descriptors/Described.kt (92%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/{ => meta}/descriptors/DescriptorMeta.kt (95%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/{ => meta}/descriptors/ItemDescriptor.kt (85%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{ => scheme}/Configurable.kt (71%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{ => scheme}/ConfigurableDelegate.kt (88%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{ => scheme}/Scheme.kt (81%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{ => scheme}/Specification.kt (90%) rename dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/{ => transformations}/MetaTransformation.kt (83%) rename dataforge-meta/src/commonTest/kotlin/hep/dataforge/{ => meta}/descriptors/DescriptorTest.kt (77%) rename {dataforge-output-html => dataforge-output/dataforge-output-html}/build.gradle.kts (100%) rename {dataforge-output-html => dataforge-output/dataforge-output-html}/src/commonMain/kotlin/hep/dataforge/output/html/HtmlRenderer.kt (100%) delete mode 100644 dataforge-tables/build.gradle create mode 100644 dataforge-tables/build.gradle.kts create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnScheme.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnTable.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ListColumn.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/MapRow.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/NumberColumn.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/RowTable.kt create mode 100644 dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/Table.kt create mode 100644 dataforge-tables/src/jvmMain/kotlin/hep/dataforge/tables/TableAccessor.kt diff --git a/build.gradle.kts b/build.gradle.kts index 53a45364..14ccd3e9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("scientifik.publish") version toolsVersion apply false } -val dataforgeVersion by extra("0.1.5-dev-7") +val dataforgeVersion by extra("0.1.5-dev-8") val bintrayRepo by extra("dataforge") val githubProject by extra("dataforge-core") diff --git a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/annotations.kt b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/annotations.kt new file mode 100644 index 00000000..cadd4231 --- /dev/null +++ b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/annotations.kt @@ -0,0 +1,130 @@ +/* + * Copyright 2018 Alexander Nozik. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package hep.dataforge.descriptors + +import hep.dataforge.meta.DFExperimental +import hep.dataforge.values.ValueType +import kotlin.reflect.KClass + +@MustBeDocumented +annotation class Attribute( + val key: String, + val value: String +) + +@MustBeDocumented +annotation class Attributes( + val attrs: Array +) + +@MustBeDocumented +annotation class ItemDef( + val info: String = "", + val multiple: Boolean = false, + val required: Boolean = false +) + +@Target(AnnotationTarget.PROPERTY) +@MustBeDocumented +annotation class ValueDef( + val type: Array = [ValueType.STRING], + val def: String = "", + val allowed: Array = [], + val enumeration: KClass<*> = Any::class +) + +///** +// * Description text for meta property, node or whole object +// */ +//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class Description(val value: String) +// +///** +// * Annotation for value property which states that lists are expected +// */ +//@Target(AnnotationTarget.PROPERTY) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class Multiple +// +///** +// * Descriptor target +// * The DataForge path to the resource containing the description. Following targets are supported: +// * 1. resource +// * 1. file +// * 1. class +// * 1. method +// * 1. property +// * +// * +// * Does not work if [type] is provided +// */ +//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class Descriptor(val value: String) +// +// +///** +// * Aggregator class for descriptor nodes +// */ +//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class DescriptorNodes(vararg val nodes: NodeDef) +// +///** +// * Aggregator class for descriptor values +// */ +//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class DescriptorValues(vararg val nodes: ValueDef) +// +///** +// * Alternative name for property descriptor declaration +// */ +//@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class DescriptorName(val name: String) +// +//@Target(AnnotationTarget.PROPERTY) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class DescriptorValue(val def: ValueDef) +////TODO enter fields directly? +// +//@Target(AnnotationTarget.PROPERTY) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class ValueProperty( +// val name: String = "", +// val type: Array = arrayOf(ValueType.STRING), +// val multiple: Boolean = false, +// val def: String = "", +// val enumeration: KClass<*> = Any::class, +// val tags: Array = emptyArray() +//) +// +// +//@Target(AnnotationTarget.PROPERTY) +//@Retention(AnnotationRetention.RUNTIME) +//@MustBeDocumented +//annotation class NodeProperty(val name: String = "") diff --git a/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/reflectiveDescriptors.kt b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/reflectiveDescriptors.kt new file mode 100644 index 00000000..0015436c --- /dev/null +++ b/dataforge-context/src/jvmMain/kotlin/hep/dataforge/descriptors/reflectiveDescriptors.kt @@ -0,0 +1,65 @@ +package hep.dataforge.descriptors + +import hep.dataforge.meta.* +import hep.dataforge.meta.descriptors.ItemDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.attributes +import hep.dataforge.meta.scheme.ConfigurableDelegate +import hep.dataforge.meta.scheme.Scheme +import hep.dataforge.values.parseValue +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.isSubclassOf +import kotlin.reflect.full.memberProperties + + +//inline fun T.buildDescriptor(): NodeDescriptor = NodeDescriptor { +// T::class.apply { +// findAnnotation()?.let { def -> +// info = def.info +// required = def.required +// multiple = def.multiple +// } +// findAnnotation()?.let { attr -> +// attributes { +// this[attr.key] = attr.value.parseValue() +// } +// } +// findAnnotation()?.attrs?.forEach { attr -> +// attributes { +// this[attr.key] = attr.value.parseValue() +// } +// } +// } +// T::class.memberProperties.forEach { property -> +// val delegate = property.getDelegate(this@buildDescriptor) +// +// val descriptor: ItemDescriptor = when (delegate) { +// is ConfigurableDelegate -> buildPropertyDescriptor(property, delegate) +// is ReadWriteDelegateWrapper<*, *> -> { +// if (delegate.delegate is ConfigurableDelegate) { +// buildPropertyDescriptor(property, delegate.delegate as ConfigurableDelegate) +// } else { +// return@forEach +// } +// } +// else -> return@forEach +// } +// defineItem(property.name, descriptor) +// } +//} + +//inline fun buildPropertyDescriptor( +// property: KProperty1, +// delegate: ConfigurableDelegate +//): ItemDescriptor { +// when { +// V::class.isSubclassOf(Scheme::class) -> NodeDescriptor { +// default = delegate.default.node +// } +// V::class.isSubclassOf(Meta::class) -> NodeDescriptor { +// default = delegate.default.node +// } +// +// } +//} diff --git a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataFilter.kt b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataFilter.kt index 08a0ea87..bc9caaec 100644 --- a/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataFilter.kt +++ b/dataforge-data/src/commonMain/kotlin/hep/dataforge/data/DataFilter.kt @@ -1,6 +1,9 @@ package hep.dataforge.data import hep.dataforge.meta.* +import hep.dataforge.meta.scheme.Scheme +import hep.dataforge.meta.scheme.SchemeSpec +import hep.dataforge.meta.scheme.string import hep.dataforge.names.toName diff --git a/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/YamlMetaFormat.kt b/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/YamlMetaFormat.kt index acd19652..d0543fd0 100644 --- a/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/YamlMetaFormat.kt +++ b/dataforge-io/dataforge-io-yaml/src/main/kotlin/hep/dataforge/io/yaml/YamlMetaFormat.kt @@ -1,12 +1,13 @@ package hep.dataforge.io.yaml import hep.dataforge.context.Context -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.io.MetaFormat import hep.dataforge.io.MetaFormatFactory import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.Meta import hep.dataforge.meta.toMap +import hep.dataforge.meta.scheme.toMeta import hep.dataforge.meta.toMeta import kotlinx.io.Input import kotlinx.io.Output diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/BinaryMetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/BinaryMetaFormat.kt index 1182bfbc..c86fe883 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/BinaryMetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/BinaryMetaFormat.kt @@ -1,7 +1,7 @@ package hep.dataforge.io import hep.dataforge.context.Context -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.* import hep.dataforge.values.* import kotlinx.io.* diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt index d27b0a97..8ec244a5 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/JsonMetaFormat.kt @@ -3,9 +3,9 @@ package hep.dataforge.io import hep.dataforge.context.Context -import hep.dataforge.descriptors.ItemDescriptor -import hep.dataforge.descriptors.NodeDescriptor -import hep.dataforge.descriptors.ValueDescriptor +import hep.dataforge.meta.descriptors.ItemDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.ValueDescriptor import hep.dataforge.meta.Meta import hep.dataforge.meta.MetaBase import hep.dataforge.meta.MetaItem diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt index d22359c8..4776e015 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/MetaFormat.kt @@ -1,7 +1,7 @@ package hep.dataforge.io import hep.dataforge.context.Context -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE import hep.dataforge.meta.Meta import hep.dataforge.names.Name diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionClient.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionClient.kt index 7c294891..1df4b42d 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionClient.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionClient.kt @@ -6,6 +6,7 @@ import hep.dataforge.io.* import hep.dataforge.meta.Meta import hep.dataforge.meta.get import hep.dataforge.meta.int +import hep.dataforge.meta.scheme.int import kotlin.reflect.KClass class RemoteFunctionClient(override val context: Context, val responder: Responder) : FunctionServer, ContextAware { diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionServer.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionServer.kt index 8252b1d3..efd4351e 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionServer.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/functions/RemoteFunctionServer.kt @@ -8,6 +8,7 @@ import hep.dataforge.io.Responder import hep.dataforge.io.type import hep.dataforge.meta.get import hep.dataforge.meta.int +import hep.dataforge.meta.scheme.int class RemoteFunctionServer( override val context: Context, diff --git a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/serialization/MetaSerializer.kt b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/serialization/MetaSerializer.kt index a1ac33a5..ef989869 100644 --- a/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/serialization/MetaSerializer.kt +++ b/dataforge-io/src/commonMain/kotlin/hep/dataforge/io/serialization/MetaSerializer.kt @@ -18,7 +18,7 @@ object ValueSerializer : KSerializer { private val valueTypeSerializer = EnumSerializer(ValueType::class) private val listSerializer by lazy { ArrayListSerializer(ValueSerializer) } - override val descriptor: SerialDescriptor = descriptor("hep.dataforge.values.Value") { + override val descriptor: SerialDescriptor = descriptor("Value") { boolean("isList") enum("valueType") element("value", null) diff --git a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MultipartTest.kt b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MultipartTest.kt index 0f60c077..04d097aa 100644 --- a/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MultipartTest.kt +++ b/dataforge-io/src/commonTest/kotlin/hep/dataforge/io/MultipartTest.kt @@ -3,6 +3,7 @@ package hep.dataforge.io import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.get import hep.dataforge.meta.int +import hep.dataforge.meta.scheme.int import kotlinx.io.text.writeRawString import kotlinx.io.text.writeUtf8String diff --git a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt index fb693057..1fe9d59d 100644 --- a/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt +++ b/dataforge-io/src/jvmMain/kotlin/hep/dataforge/io/fileIO.kt @@ -1,6 +1,6 @@ package hep.dataforge.io -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.DFExperimental import hep.dataforge.meta.EmptyMeta import hep.dataforge.meta.Meta diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt deleted file mode 100644 index d65a0e79..00000000 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/annotations.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2018 Alexander Nozik. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package hep.dataforge.descriptors - -import hep.dataforge.values.ValueType -import kotlin.reflect.KClass - -@Target(AnnotationTarget.PROPERTY) -@MustBeDocumented -annotation class ValueDef( - val key: String, - val type: Array = arrayOf(ValueType.STRING), - val multiple: Boolean = false, - val def: String = "", - val info: String = "", - val required: Boolean = true, - val allowed: Array = emptyArray(), - val enumeration: KClass<*> = Any::class, - val tags: Array = emptyArray() -) - -@MustBeDocumented -annotation class NodeDef( - val key: String, - val info: String = "", - val multiple: Boolean = false, - val required: Boolean = false, - val tags: Array = emptyArray(), - /** - * A list of child value descriptors - */ - val values: Array = emptyArray(), - /** - * A target class for this node to describe - * @return - */ - val type: KClass<*> = Any::class, - /** - * The DataForge path to the resource containing the description. Following targets are supported: - * - * 1. resource - * 1. file - * 1. class - * 1. method - * 1. property - * - * - * Does not work if [type] is provided - * - * @return - */ - val descriptor: String = "" -) - -/** - * Description text for meta property, node or whole object - */ -@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class Description(val value: String) - -/** - * Annotation for value property which states that lists are expected - */ -@Target(AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class Multiple - -/** - * Descriptor target - * The DataForge path to the resource containing the description. Following targets are supported: - * 1. resource - * 1. file - * 1. class - * 1. method - * 1. property - * - * - * Does not work if [type] is provided - */ -@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class Descriptor(val value: String) - - -/** - * Aggregator class for descriptor nodes - */ -@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class DescriptorNodes(vararg val nodes: NodeDef) - -/** - * Aggregator class for descriptor values - */ -@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class DescriptorValues(vararg val nodes: ValueDef) - -/** - * Alternative name for property descriptor declaration - */ -@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class DescriptorName(val name: String) - -@Target(AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class DescriptorValue(val def: ValueDef) -//TODO enter fields directly? - -@Target(AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class ValueProperty( - val name: String = "", - val type: Array = arrayOf(ValueType.STRING), - val multiple: Boolean = false, - val def: String = "", - val enumeration: KClass<*> = Any::class, - val tags: Array = emptyArray() -) - - -@Target(AnnotationTarget.PROPERTY) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class NodeProperty(val name: String = "") diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt index 087cb077..833117b5 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Config.kt @@ -12,10 +12,15 @@ data class MetaListener( val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit ) +interface ObservableMeta : Meta { + fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) + fun removeListener(owner: Any?) +} + /** * Mutable meta representing object state */ -class Config : AbstractMutableMeta() { +class Config : AbstractMutableMeta(), ObservableMeta { private val listeners = HashSet() @@ -26,14 +31,14 @@ class Config : AbstractMutableMeta() { /** * Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed */ - fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) { + override fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) { listeners.add(MetaListener(owner, action)) } /** * Remove all listeners belonging to given owner */ - fun removeListener(owner: Any?) { + override fun removeListener(owner: Any?) { listeners.removeAll { it.owner === owner } } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt index 950df7d6..88819f2c 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MutableMeta.kt @@ -1,5 +1,6 @@ package hep.dataforge.meta +import hep.dataforge.meta.scheme.Configurable import hep.dataforge.names.* import hep.dataforge.values.Value @@ -160,7 +161,7 @@ operator fun MutableMeta<*>.set(name: String, metas: Iterable): Unit = set /** * Append the node with a same-name-sibling, automatically generating numerical index */ -fun MutableMeta<*>.append(name: Name, value: Any?) { +fun > M.append(name: Name, value: Any?) { require(!name.isEmpty()) { "Name could not be empty for append operation" } val newIndex = name.last()!!.index if (newIndex.isNotEmpty()) { @@ -171,4 +172,4 @@ fun MutableMeta<*>.append(name: Name, value: Any?) { } } -fun MutableMeta<*>.append(name: String, value: Any?) = append(name.toName(), value) \ No newline at end of file +fun > M.append(name: String, value: Any?) = append(name.toName(), value) \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/Described.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt similarity index 92% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/Described.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt index 4bf6c9dd..0a09a0fb 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/Described.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/Described.kt @@ -1,4 +1,4 @@ -package hep.dataforge.descriptors +package hep.dataforge.meta.descriptors /** * An object which provides its descriptor diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/DescriptorMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt similarity index 95% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/DescriptorMeta.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt index 49aef28e..f95069d6 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/DescriptorMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/DescriptorMeta.kt @@ -1,4 +1,4 @@ -package hep.dataforge.descriptors +package hep.dataforge.meta.descriptors import hep.dataforge.meta.MetaBase import hep.dataforge.meta.MetaItem diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt similarity index 85% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt index 514349fe..9c5cf15f 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/descriptors/ItemDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/descriptors/ItemDescriptor.kt @@ -1,6 +1,7 @@ -package hep.dataforge.descriptors +package hep.dataforge.meta.descriptors import hep.dataforge.meta.* +import hep.dataforge.meta.scheme.* import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.asName @@ -41,6 +42,25 @@ sealed class ItemDescriptor : Scheme() { abstract var required: Boolean } +/** + * Configure attributes of the descriptor + */ +fun ItemDescriptor.attributes(block: Config.() -> Unit) { + (attributes ?: Config().also { this.config = it }).apply(block) +} + +/** + * Check if given item suits the descriptor + */ +fun ItemDescriptor.validateItem(item: MetaItem<*>?): Boolean { + return when (this) { + is ValueDescriptor -> isAllowedValue(item.value ?: return false) + is NodeDescriptor -> items.all { (key, d) -> + d.validateItem(item.node[key]) + } + } +} + /** * Descriptor for meta node. Could contain additional information for viewing * and editing. @@ -61,7 +81,7 @@ class NodeDescriptor : ItemDescriptor() { * * @return */ - var default: Config? by config() + var default by node() /** * The map of children node descriptors @@ -71,15 +91,21 @@ class NodeDescriptor : ItemDescriptor() { name to wrap(node.node ?: error("Node descriptor must be a node")) } - - fun node(name: String, descriptor: NodeDescriptor) { + /** + * Define a child item descriptor for this node + */ + fun defineItem(name: String, descriptor: ItemDescriptor) { if (items.keys.contains(name)) error("The key $name already exists in descriptor") - val token = NameToken(NODE_KEY, name) + val token = when (descriptor) { + is NodeDescriptor -> NameToken(NODE_KEY, name) + is ValueDescriptor -> NameToken(VALUE_KEY, name) + } config[token] = descriptor.config + } - fun node(name: String, block: NodeDescriptor.() -> Unit) { + fun defineNode(name: String, block: NodeDescriptor.() -> Unit) { val token = NameToken(NODE_KEY, name) if (config[token] == null) { config[token] = NodeDescriptor(block) @@ -100,7 +126,7 @@ class NodeDescriptor : ItemDescriptor() { } } - fun node(name: Name, block: NodeDescriptor.() -> Unit) { + fun defineNode(name: Name, block: NodeDescriptor.() -> Unit) { buildNode(name).apply(block) } @@ -112,28 +138,23 @@ class NodeDescriptor : ItemDescriptor() { name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node")) } - fun value(name: String, descriptor: ValueDescriptor) { - if (items.keys.contains(name)) error("The key $name already exists in descriptor") - val token = NameToken(VALUE_KEY, name) - config[token] = descriptor.config - } /** * Add a value descriptor using block for */ - fun value(name: String, block: ValueDescriptor.() -> Unit) { - value(name, ValueDescriptor(block)) + fun defineValue(name: String, block: ValueDescriptor.() -> Unit) { + defineItem(name, ValueDescriptor(block)) } - fun value(name: Name, block: ValueDescriptor.() -> Unit) { + fun defineValue(name: Name, block: ValueDescriptor.() -> Unit) { require(name.length >= 1) { "Name length for value descriptor must be non-empty" } - buildNode(name.cutLast()).value(name.last().toString(), block) + buildNode(name.cutLast()).defineValue(name.last().toString(), block) } val items: Map get() = nodes + values - //override val descriptor: NodeDescriptor = empty("descriptor") +//override val descriptor: NodeDescriptor = empty("descriptor") companion object : SchemeSpec(::NodeDescriptor) { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt index ab68212c..ddf049e3 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/mapMeta.kt @@ -1,6 +1,6 @@ package hep.dataforge.meta -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.values.Value /** diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Configurable.kt similarity index 71% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Configurable.kt index e95b5564..42aaeb07 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Configurable.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Configurable.kt @@ -1,9 +1,7 @@ -package hep.dataforge.meta +package hep.dataforge.meta.scheme -import hep.dataforge.descriptors.Described -import hep.dataforge.descriptors.NodeDescriptor -import hep.dataforge.descriptors.defaultItem -import hep.dataforge.descriptors.get +import hep.dataforge.meta.* +import hep.dataforge.meta.descriptors.* import hep.dataforge.names.Name import hep.dataforge.names.toName @@ -24,6 +22,14 @@ interface Configurable : Described { */ fun getDefaultItem(name: Name): MetaItem<*>? = null + /** + * Check if property with given [name] could be assigned to [value] + */ + fun validateItem(name: Name, item: MetaItem<*>?): Boolean { + val descriptor = descriptor?.get(name) + return descriptor?.validateItem(item) ?: true + } + override val descriptor: NodeDescriptor? get() = null } @@ -39,7 +45,11 @@ fun Configurable.getProperty(key: String) = getProperty(key.toName()) * Set a configurable property */ fun Configurable.setProperty(name: Name, item: MetaItem<*>?) { - config[name] = item + if(validateItem(name,item)) { + config[name] = item + } else { + error("Validation failed for property $name with value $item") + } } fun Configurable.setProperty(key: String, item: MetaItem<*>?) { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/ConfigurableDelegate.kt similarity index 88% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/ConfigurableDelegate.kt index 31cc2c9c..9b86abba 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/ConfigurableDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/ConfigurableDelegate.kt @@ -1,5 +1,6 @@ -package hep.dataforge.meta +package hep.dataforge.meta.scheme +import hep.dataforge.meta.* import hep.dataforge.names.Name import hep.dataforge.names.asName import hep.dataforge.values.* @@ -41,23 +42,35 @@ class LazyConfigurableDelegate( /** * A property delegate that uses custom key */ -fun Configurable.item(default: Any?, key: Name? = null): ConfigurableDelegate = - ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }) +fun Configurable.item(default: Any? = null, key: Name? = null): ConfigurableDelegate = + ConfigurableDelegate( + this, + key, + default?.let { MetaItem.of(it) }) /** * Generation of item delegate with lazy default. * Lazy default could be used also for validation */ fun Configurable.lazyItem(key: Name? = null, default: () -> Any?): ConfigurableDelegate = - LazyConfigurableDelegate(this, key) { default()?.let { MetaItem.of(it) } } + LazyConfigurableDelegate(this, key) { + default()?.let { + MetaItem.of(it) + } + } fun Configurable.item( default: T? = null, key: Name? = null, - writer: (T) -> MetaItem<*>? = { MetaItem.of(it) }, + writer: (T) -> MetaItem<*>? = { + MetaItem.of(it) + }, reader: (MetaItem<*>?) -> T ): ReadWriteProperty = - ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).map(reader = reader, writer = writer) + ConfigurableDelegate( + this, + key, + default?.let { MetaItem.of(it) }).map(reader = reader, writer = writer) fun Configurable.value(default: Any? = null, key: Name? = null): ReadWriteProperty = item(default, key).transform { it.value } @@ -68,9 +81,13 @@ fun Configurable.value( writer: (T) -> Value? = { Value.of(it) }, reader: (Value?) -> T ): ReadWriteProperty = - ConfigurableDelegate(this, key, default?.let { MetaItem.of(it) }).map( + ConfigurableDelegate( + this, + key, + default?.let { MetaItem.of(it) } + ).map( reader = { reader(it.value) }, - writer = { writer(it)?.let { MetaItem.ValueItem(it) } } + writer = { value -> writer(value)?.let { MetaItem.ValueItem(it) } } ) fun Configurable.string(default: String? = null, key: Name? = null): ReadWriteProperty = @@ -184,6 +201,10 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri fun Configurable.config(key: Name? = null): ReadWriteProperty = config.node(key) +fun Configurable.node(key: Name? = null): ReadWriteProperty = item().map( + reader = { it.node }, + writer = { it?.let { MetaItem.NodeItem(it) } } +) fun Configurable.spec(spec: Specification, key: Name? = null): ReadWriteProperty = object : ReadWriteProperty { diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Scheme.kt similarity index 81% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Scheme.kt index 84b350f1..c730eed2 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Scheme.kt @@ -1,6 +1,7 @@ -package hep.dataforge.meta +package hep.dataforge.meta.scheme -import hep.dataforge.descriptors.* +import hep.dataforge.meta.* +import hep.dataforge.meta.descriptors.* import hep.dataforge.names.Name import hep.dataforge.names.NameToken import hep.dataforge.names.plus @@ -8,7 +9,7 @@ import hep.dataforge.names.plus /** * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. */ -open class Scheme() : Configurable, Described { +open class Scheme() : Configurable, Described, MetaRepr { constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() { this.config = config this.defaultProvider = defaultProvider @@ -17,7 +18,8 @@ open class Scheme() : Configurable, Described { //constructor(config: Config, default: Meta) : this(config, { default[it] }) constructor(config: Config) : this(config, { null }) - final override var config: Config = Config() + final override var config: Config = + Config() internal set lateinit var defaultProvider: (Name) -> MetaItem<*>? @@ -37,6 +39,8 @@ open class Scheme() : Configurable, Described { */ open val defaultLayer: Meta get() = DefaultLayer(Name.EMPTY) + override fun toMeta(): Meta = config.seal() + private inner class DefaultLayer(val path: Name) : MetaBase() { override val items: Map> = (descriptor?.get(path) as? NodeDescriptor)?.items?.entries?.associate { (key, descriptor) -> @@ -55,7 +59,8 @@ open class Scheme() : Configurable, Described { /** * A specification for simplified generation of wrappers */ -open class SchemeSpec(val builder: () -> T) : Specification { +open class SchemeSpec(val builder: () -> T) : + Specification { override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T { return builder().apply { this.config = config @@ -75,14 +80,18 @@ open class MetaScheme( init { this.descriptor = descriptor } - override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node) + + override val defaultLayer: Meta + get() = Laminate(meta, descriptor?.defaultItem().node) } -fun Meta.asScheme() = MetaScheme(this) +fun Meta.asScheme() = + MetaScheme(this) fun Meta.toScheme(spec: Specification, block: T.() -> Unit) = spec.wrap(this).apply(block) /** * Create a snapshot laminate */ -fun Scheme.toMeta(): Laminate = Laminate(config, defaultLayer) \ No newline at end of file +fun Scheme.toMeta(): Laminate = + Laminate(config, defaultLayer) \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Specification.kt similarity index 90% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Specification.kt index 9c8b740a..4aa7bf02 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/Specification.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/scheme/Specification.kt @@ -1,5 +1,6 @@ -package hep.dataforge.meta +package hep.dataforge.meta.scheme +import hep.dataforge.meta.* import hep.dataforge.names.Name import kotlin.jvm.JvmName @@ -33,7 +34,9 @@ interface Specification { /** * Wrap a configuration using static meta as default */ - fun wrap(default: Meta): T = wrap(Config()){default[it]} + fun wrap(default: Meta): T = wrap( + Config() + ){default[it]} } /** @@ -54,7 +57,8 @@ fun > Configurable.update(spec: S, action fun > S.createStyle(action: C.() -> Unit): Meta = Config().also { update(it, action) } -fun MetaItem<*>.spec(spec: Specification): T? = node?.let { spec.wrap(Config(), it) } +fun MetaItem<*>.spec(spec: Specification): T? = node?.let { spec.wrap( + Config(), it) } @JvmName("configSpec") fun MetaItem.spec(spec: Specification): T? = node?.let { spec.wrap(it) } diff --git a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/transformations/MetaTransformation.kt similarity index 83% rename from dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt rename to dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/transformations/MetaTransformation.kt index 8deada19..4dad4466 100644 --- a/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/MetaTransformation.kt +++ b/dataforge-meta/src/commonMain/kotlin/hep/dataforge/meta/transformations/MetaTransformation.kt @@ -1,5 +1,6 @@ -package hep.dataforge.meta +package hep.dataforge.meta.transformations +import hep.dataforge.meta.* import hep.dataforge.names.Name /** @@ -8,7 +9,7 @@ import hep.dataforge.names.Name interface TransformationRule { /** - * Check if this transformation + * Check if this transformation should be applied to a node with given name and value */ fun matches(name: Name, item: MetaItem<*>?): Boolean @@ -29,7 +30,8 @@ interface TransformationRule { /** * A transformation which keeps all elements, matching [selector] unchanged. */ -data class KeepTransformationRule(val selector: (Name) -> Boolean) : TransformationRule { +data class KeepTransformationRule(val selector: (Name) -> Boolean) : + TransformationRule { override fun matches(name: Name, item: MetaItem<*>?): Boolean { return selector(name) } @@ -87,25 +89,27 @@ inline class MetaTransformation(val transformations: Collection - rule.selectItems(source).forEach { name -> - rule.transformItem(name, source[name], this) + fun transform(source: Meta): Meta = + buildMeta { + transformations.forEach { rule -> + rule.selectItems(source).forEach { name -> + rule.transformItem(name, source[name], this) + } } } - } /** * Transform a meta, replacing all elements found in rules with transformed entries */ - fun apply(source: Meta): Meta = buildMeta(source) { - transformations.forEach { rule -> - rule.selectItems(source).forEach { name -> - remove(name) - rule.transformItem(name, source[name], this) + fun apply(source: Meta): Meta = + buildMeta(source) { + transformations.forEach { rule -> + rule.selectItems(source).forEach { name -> + remove(name) + rule.transformItem(name, source[name], this) + } } } - } /** * Listens for changes in the source node and translates them into second node if transformation set contains a corresponding rule. @@ -150,9 +154,10 @@ class MetaTransformationBuilder { * Keep nodes by regex */ fun keep(regex: String) { - transformations.add(RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem -> - setItem(name, metaItem) - }) + transformations.add( + RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem -> + setItem(name, metaItem) + }) } /** diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/MetaDelegateTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/MetaDelegateTest.kt index 93aad8e5..2461c363 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/MetaDelegateTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/MetaDelegateTest.kt @@ -1,5 +1,6 @@ package hep.dataforge.meta +import hep.dataforge.meta.scheme.* import kotlin.test.Test import kotlin.test.assertEquals diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt index 0246fb10..09a3e03c 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SchemeTest.kt @@ -1,5 +1,8 @@ package hep.dataforge.meta +import hep.dataforge.meta.scheme.asScheme +import hep.dataforge.meta.scheme.getProperty +import hep.dataforge.meta.scheme.toMeta import kotlin.test.Test import kotlin.test.assertEquals diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SpecificationTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SpecificationTest.kt index f21c5b2c..6d99101a 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SpecificationTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/SpecificationTest.kt @@ -1,5 +1,8 @@ package hep.dataforge.meta +import hep.dataforge.meta.scheme.Scheme +import hep.dataforge.meta.scheme.Specification +import hep.dataforge.meta.scheme.numberList import hep.dataforge.names.Name import kotlin.test.Test import kotlin.test.assertEquals diff --git a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/descriptors/DescriptorTest.kt b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt similarity index 77% rename from dataforge-meta/src/commonTest/kotlin/hep/dataforge/descriptors/DescriptorTest.kt rename to dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt index 81d25285..1fa07382 100644 --- a/dataforge-meta/src/commonTest/kotlin/hep/dataforge/descriptors/DescriptorTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/hep/dataforge/meta/descriptors/DescriptorTest.kt @@ -1,4 +1,4 @@ -package hep.dataforge.descriptors +package hep.dataforge.meta.descriptors import hep.dataforge.values.ValueType import kotlin.test.Test @@ -7,14 +7,14 @@ import kotlin.test.assertEquals class DescriptorTest { val descriptor = NodeDescriptor { - node("aNode") { + defineNode("aNode") { info = "A root demo node" - value("b") { + defineValue("b") { info = "b number value" type(ValueType.NUMBER) } - node("otherNode") { - value("otherValue") { + defineNode("otherNode") { + defineValue("otherValue") { type(ValueType.BOOLEAN) default(false) info = "default value" diff --git a/dataforge-output-html/build.gradle.kts b/dataforge-output/dataforge-output-html/build.gradle.kts similarity index 100% rename from dataforge-output-html/build.gradle.kts rename to dataforge-output/dataforge-output-html/build.gradle.kts diff --git a/dataforge-output-html/src/commonMain/kotlin/hep/dataforge/output/html/HtmlRenderer.kt b/dataforge-output/dataforge-output-html/src/commonMain/kotlin/hep/dataforge/output/html/HtmlRenderer.kt similarity index 100% rename from dataforge-output-html/src/commonMain/kotlin/hep/dataforge/output/html/HtmlRenderer.kt rename to dataforge-output/dataforge-output-html/src/commonMain/kotlin/hep/dataforge/output/html/HtmlRenderer.kt diff --git a/dataforge-scripting/src/jvmTest/kotlin/hep/dataforge/scripting/BuildersKtTest.kt b/dataforge-scripting/src/jvmTest/kotlin/hep/dataforge/scripting/BuildersKtTest.kt index 6dd61105..9fb1c919 100644 --- a/dataforge-scripting/src/jvmTest/kotlin/hep/dataforge/scripting/BuildersKtTest.kt +++ b/dataforge-scripting/src/jvmTest/kotlin/hep/dataforge/scripting/BuildersKtTest.kt @@ -3,6 +3,7 @@ package hep.dataforge.scripting import hep.dataforge.context.Global import hep.dataforge.meta.get import hep.dataforge.meta.int +import hep.dataforge.meta.scheme.int import hep.dataforge.workspace.SimpleWorkspaceBuilder import hep.dataforge.workspace.context import hep.dataforge.workspace.target diff --git a/dataforge-tables/build.gradle b/dataforge-tables/build.gradle deleted file mode 100644 index a0011494..00000000 --- a/dataforge-tables/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id "org.jetbrains.kotlin.multiplatform" -} - -repositories { - jcenter() -} - -kotlin { - targets { - fromPreset(presets.jvm, 'jvm') - //fromPreset(presets.js, 'js') - // For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64 - // For Linux, preset should be changed to e.g. presets.linuxX64 - // For MacOS, preset should be changed to e.g. presets.macosX64 - //fromPreset(presets.iosX64, 'ios') - } - sourceSets { - commonMain { - dependencies { - api project(":dataforge-context") - } - } - } -} \ No newline at end of file diff --git a/dataforge-tables/build.gradle.kts b/dataforge-tables/build.gradle.kts new file mode 100644 index 00000000..6c0a1e53 --- /dev/null +++ b/dataforge-tables/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + id("scientifik.mpp") +} + +kotlin { + sourceSets { + val commonMain by getting{ + dependencies { + api(project(":dataforge-context")) + api(project(":dataforge-io")) + } + } + } +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnScheme.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnScheme.kt new file mode 100644 index 00000000..aa0d2aec --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnScheme.kt @@ -0,0 +1,8 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.scheme.Scheme +import hep.dataforge.meta.scheme.SchemeSpec + +class ColumnScheme : Scheme() { + companion object : SchemeSpec(::ColumnScheme) +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnTable.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnTable.kt new file mode 100644 index 00000000..ce7b7dae --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ColumnTable.kt @@ -0,0 +1,35 @@ +package hep.dataforge.tables + +import kotlin.reflect.KClass + +class ColumnTable(override val columns: Map>) : + Table { + private val rowsNum = columns.values.first().size + + init { + require(columns.values.all { it.size == rowsNum }) { "All columns must be of the same size" } + } + + override val rows: List + get() = (0 until rowsNum).map { VirtualRow(it) } + + @Suppress("UNCHECKED_CAST") + override fun getValue(row: Int, column: String, type: KClass): T? { + val value = columns[column]?.get(row) + return when { + value == null -> null + type.isInstance(value) -> value as T + else -> error("Expected type is $type, but found ${value::class}") + } + } + + private inner class VirtualRow(val index: Int) : Row { + override fun getValue(column: String, type: KClass): T? = getValue(index, column, type) + } +} + +class ColumnTableBuilder { + private val columns = ArrayList>() + + fun build() = ColumnTable(columns.associateBy { it.name }) +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ListColumn.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ListColumn.kt new file mode 100644 index 00000000..a926a2ad --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/ListColumn.kt @@ -0,0 +1,28 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.Meta +import kotlin.reflect.KClass + +class ListColumn( + override val name: String, + private val data: List, + override val type: KClass, + override val meta: Meta +) : Column { + override val size: Int get() = data.size + + override fun get(index: Int): T? = data[index] + + companion object { + inline operator fun invoke( + name: String, + data: List, + noinline metaBuilder: ColumnScheme.() -> Unit + ): ListColumn = ListColumn(name, data, T::class, ColumnScheme(metaBuilder).toMeta()) + } +} + +inline fun Column.map(meta: Meta = this.meta, noinline block: (T?) -> R): Column { + val data = List(size) { block(get(it)) } + return ListColumn(name, data, R::class, meta) +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/MapRow.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/MapRow.kt new file mode 100644 index 00000000..0a78ca9e --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/MapRow.kt @@ -0,0 +1,19 @@ +package hep.dataforge.tables + +import kotlin.reflect.KClass + +class MapRow(val values: Map) : Row { + @Suppress("UNCHECKED_CAST") + override fun getValue(column: String, type: KClass): T? { + val value = values[column] + return when { + value == null -> null + type.isInstance(value) -> { + value as T? + } + else -> { + error("Expected type is $type, but found ${value::class}") + } + } + } +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/NumberColumn.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/NumberColumn.kt new file mode 100644 index 00000000..1bd8d6a3 --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/NumberColumn.kt @@ -0,0 +1,94 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.Meta +import kotlin.reflect.KClass + +//interface NumberColumn : Column + +data class RealColumn( + override val name: String, + val data: DoubleArray, + override val meta: Meta = Meta.EMPTY +) : Column { + override val type: KClass get() = Double::class + + override val size: Int get() = data.size + + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun get(index: Int): Double = data[index] + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RealColumn) return false + + if (name != other.name) return false + if (!data.contentEquals(other.data)) return false + if (meta != other.meta) return false + + return true + } + + override fun hashCode(): Int { + var result = name.hashCode() + result = 31 * result + data.contentHashCode() + result = 31 * result + meta.hashCode() + return result + } + + companion object { + inline operator fun invoke( + name: String, + data: DoubleArray, + noinline metaBuilder: ColumnScheme.() -> Unit + ): RealColumn = RealColumn(name, data, ColumnScheme(metaBuilder).toMeta()) + } +} + +fun Column.map(meta: Meta = this.meta, block: (T?) -> Double): RealColumn { + val data = DoubleArray(size) { block(get(it)) } + return RealColumn(name, data, meta) +} + +data class IntColumn( + override val name: String, + val data: IntArray, + override val meta: Meta = Meta.EMPTY +) : Column { + override val type: KClass get() = Int::class + + override val size: Int get() = data.size + + @Suppress("OVERRIDE_BY_INLINE", "NOTHING_TO_INLINE") + override inline fun get(index: Int): Int = data[index] + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is IntColumn) return false + + if (name != other.name) return false + if (!data.contentEquals(other.data)) return false + if (meta != other.meta) return false + + return true + } + + override fun hashCode(): Int { + var result = name.hashCode() + result = 31 * result + data.contentHashCode() + result = 31 * result + meta.hashCode() + return result + } + + companion object { + inline operator fun invoke( + name: String, + data: IntArray, + noinline metaBuilder: ColumnScheme.() -> Unit + ): IntColumn = IntColumn(name, data, ColumnScheme(metaBuilder).toMeta()) + } +} + +fun Column.map(meta: Meta = this.meta, block: (T?) -> Int): IntColumn { + val data = IntArray(size) { block(get(it)) } + return IntColumn(name, data, meta) +} \ No newline at end of file diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/RowTable.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/RowTable.kt new file mode 100644 index 00000000..fbcec0b7 --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/RowTable.kt @@ -0,0 +1,26 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.Meta +import kotlin.reflect.KClass + +data class ColumnDef(val name: String, val type: KClass, val meta: Meta) + +class RowTable(override val rows: List, private val columnDefs: List>) : Table { + override fun getValue(row: Int, column: String, type: KClass): T? = + rows[row].getValue(column, type) + + override val columns: Map> + get() = columnDefs.associate { it.name to VirtualColumn(it) } + + private inner class VirtualColumn(val def: ColumnDef) : + Column { + + override val name: String get() = def.name + override val type: KClass get() = def.type + override val meta: Meta get() = def.meta + override val size: Int get() = rows.size + + override fun get(index: Int): T? = rows[index].getValue(name, type) + } +} + diff --git a/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/Table.kt b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/Table.kt new file mode 100644 index 00000000..52171625 --- /dev/null +++ b/dataforge-tables/src/commonMain/kotlin/hep/dataforge/tables/Table.kt @@ -0,0 +1,30 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.Meta +import kotlin.reflect.KClass + +interface Table { + fun getValue(row: Int, column: String, type: KClass): T? + val columns: Map> + val rows: List +} + +interface Column { + val name: String + val type: KClass + val meta: Meta + val size: Int + operator fun get(index: Int): T? +} + +val Column<*>.indices get() = (0 until size) + +operator fun Column.iterator() = iterator { + for (i in indices){ + yield(get(i)) + } +} + +interface Row { + fun getValue(column: String, type: KClass): T? +} \ No newline at end of file diff --git a/dataforge-tables/src/jvmMain/kotlin/hep/dataforge/tables/TableAccessor.kt b/dataforge-tables/src/jvmMain/kotlin/hep/dataforge/tables/TableAccessor.kt new file mode 100644 index 00000000..21453426 --- /dev/null +++ b/dataforge-tables/src/jvmMain/kotlin/hep/dataforge/tables/TableAccessor.kt @@ -0,0 +1,37 @@ +package hep.dataforge.tables + +import hep.dataforge.meta.Meta +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KClass +import kotlin.reflect.KProperty +import kotlin.reflect.full.cast +import kotlin.reflect.full.isSubclassOf + +class TableAccessor(val table: Table) : Table by table { + inline fun column() = ColumnProperty(table, T::class) +} + +@Suppress("UNCHECKED_CAST") +fun Column<*>.cast(type: KClass): Column { + return if (type.isSubclassOf(this.type)) { + this as Column + } else { + ColumnWrapper(this, type) + } +} + +class ColumnWrapper(val column: Column<*>, override val type: KClass) : Column { + override val name: String get() = column.name + override val meta: Meta get() = column.meta + override val size: Int get() = column.size + + + override fun get(index: Int): T? = type.cast(column[index]) +} + +class ColumnProperty(val table: Table, val type: KClass) : ReadOnlyProperty?> { + override fun getValue(thisRef: Any?, property: KProperty<*>): Column? { + val name = property.name + return table.columns[name]?.cast(type) + } +} \ No newline at end of file diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/GenericTask.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/GenericTask.kt index ff499888..4e0ca715 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/GenericTask.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/GenericTask.kt @@ -1,7 +1,7 @@ package hep.dataforge.workspace import hep.dataforge.data.DataNode -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.Meta import hep.dataforge.meta.get import hep.dataforge.meta.node diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt index 0b11a7d5..7511bda9 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/Task.kt @@ -2,7 +2,7 @@ package hep.dataforge.workspace import hep.dataforge.context.Named import hep.dataforge.data.DataNode -import hep.dataforge.descriptors.Described +import hep.dataforge.meta.descriptors.Described import hep.dataforge.meta.Meta import hep.dataforge.provider.Type import hep.dataforge.workspace.Task.Companion.TYPE diff --git a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt index 87736c01..7f359914 100644 --- a/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/hep/dataforge/workspace/TaskBuilder.kt @@ -2,7 +2,7 @@ package hep.dataforge.workspace import hep.dataforge.context.Context import hep.dataforge.data.* -import hep.dataforge.descriptors.NodeDescriptor +import hep.dataforge.meta.descriptors.NodeDescriptor import hep.dataforge.meta.DFBuilder import hep.dataforge.meta.Meta import hep.dataforge.meta.get diff --git a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt index a4df6a4b..8bd02c35 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/hep/dataforge/workspace/SimpleWorkspaceTest.kt @@ -6,6 +6,7 @@ import hep.dataforge.meta.boolean import hep.dataforge.meta.builder import hep.dataforge.meta.get import hep.dataforge.meta.int +import hep.dataforge.meta.scheme.int import hep.dataforge.names.plus import kotlin.test.Test import kotlin.test.assertEquals diff --git a/settings.gradle.kts b/settings.gradle.kts index 42033ac1..e0d250bf 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -28,7 +28,8 @@ include( ":dataforge-context", ":dataforge-data", ":dataforge-output", - ":dataforge-output-html", + ":dataforge-output:dataforge-output-html", + ":dataforge-tables", ":dataforge-workspace", ":dataforge-scripting" )