Tables basics
A lot of refactoring
This commit is contained in:
parent
fe6760eee6
commit
f906fbdb0a
@ -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")
|
||||
|
@ -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<Attribute>
|
||||
)
|
||||
|
||||
@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> = [ValueType.STRING],
|
||||
val def: String = "",
|
||||
val allowed: Array<String> = [],
|
||||
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<ValueType> = arrayOf(ValueType.STRING),
|
||||
// val multiple: Boolean = false,
|
||||
// val def: String = "",
|
||||
// val enumeration: KClass<*> = Any::class,
|
||||
// val tags: Array<String> = emptyArray()
|
||||
//)
|
||||
//
|
||||
//
|
||||
//@Target(AnnotationTarget.PROPERTY)
|
||||
//@Retention(AnnotationRetention.RUNTIME)
|
||||
//@MustBeDocumented
|
||||
//annotation class NodeProperty(val name: String = "")
|
@ -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 <reified T : Scheme> T.buildDescriptor(): NodeDescriptor = NodeDescriptor {
|
||||
// T::class.apply {
|
||||
// findAnnotation<ItemDef>()?.let { def ->
|
||||
// info = def.info
|
||||
// required = def.required
|
||||
// multiple = def.multiple
|
||||
// }
|
||||
// findAnnotation<Attribute>()?.let { attr ->
|
||||
// attributes {
|
||||
// this[attr.key] = attr.value.parseValue()
|
||||
// }
|
||||
// }
|
||||
// findAnnotation<Attributes>()?.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 <T : Scheme, reified V : Any?> buildPropertyDescriptor(
|
||||
// property: KProperty1<T, V>,
|
||||
// delegate: ConfigurableDelegate
|
||||
//): ItemDescriptor {
|
||||
// when {
|
||||
// V::class.isSubclassOf(Scheme::class) -> NodeDescriptor {
|
||||
// default = delegate.default.node
|
||||
// }
|
||||
// V::class.isSubclassOf(Meta::class) -> NodeDescriptor {
|
||||
// default = delegate.default.node
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
@ -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
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -18,7 +18,7 @@ object ValueSerializer : KSerializer<Value> {
|
||||
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>("valueType")
|
||||
element("value", null)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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<ValueType> = arrayOf(ValueType.STRING),
|
||||
val multiple: Boolean = false,
|
||||
val def: String = "",
|
||||
val info: String = "",
|
||||
val required: Boolean = true,
|
||||
val allowed: Array<String> = emptyArray(),
|
||||
val enumeration: KClass<*> = Any::class,
|
||||
val tags: Array<String> = emptyArray()
|
||||
)
|
||||
|
||||
@MustBeDocumented
|
||||
annotation class NodeDef(
|
||||
val key: String,
|
||||
val info: String = "",
|
||||
val multiple: Boolean = false,
|
||||
val required: Boolean = false,
|
||||
val tags: Array<String> = emptyArray(),
|
||||
/**
|
||||
* A list of child value descriptors
|
||||
*/
|
||||
val values: Array<ValueDef> = 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<ValueType> = arrayOf(ValueType.STRING),
|
||||
val multiple: Boolean = false,
|
||||
val def: String = "",
|
||||
val enumeration: KClass<*> = Any::class,
|
||||
val tags: Array<String> = emptyArray()
|
||||
)
|
||||
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
annotation class NodeProperty(val name: String = "")
|
@ -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<Config>() {
|
||||
class Config : AbstractMutableMeta<Config>(), ObservableMeta {
|
||||
|
||||
private val listeners = HashSet<MetaListener>()
|
||||
|
||||
@ -26,14 +31,14 @@ class Config : AbstractMutableMeta<Config>() {
|
||||
/**
|
||||
* 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 }
|
||||
}
|
||||
|
||||
|
@ -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<Meta>): Unit = set
|
||||
/**
|
||||
* Append the node with a same-name-sibling, automatically generating numerical index
|
||||
*/
|
||||
fun MutableMeta<*>.append(name: Name, value: Any?) {
|
||||
fun <M: MutableMeta<M>> 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)
|
||||
fun <M: MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value)
|
@ -1,4 +1,4 @@
|
||||
package hep.dataforge.descriptors
|
||||
package hep.dataforge.meta.descriptors
|
||||
|
||||
/**
|
||||
* An object which provides its descriptor
|
@ -1,4 +1,4 @@
|
||||
package hep.dataforge.descriptors
|
||||
package hep.dataforge.meta.descriptors
|
||||
|
||||
import hep.dataforge.meta.MetaBase
|
||||
import hep.dataforge.meta.MetaItem
|
@ -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<String, ItemDescriptor> get() = nodes + values
|
||||
|
||||
|
||||
//override val descriptor: NodeDescriptor = empty("descriptor")
|
||||
//override val descriptor: NodeDescriptor = empty("descriptor")
|
||||
|
||||
companion object : SchemeSpec<NodeDescriptor>(::NodeDescriptor) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.descriptors.NodeDescriptor
|
||||
import hep.dataforge.meta.descriptors.NodeDescriptor
|
||||
import hep.dataforge.values.Value
|
||||
|
||||
/**
|
||||
|
@ -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<*>?) {
|
||||
if(validateItem(name,item)) {
|
||||
config[name] = item
|
||||
} else {
|
||||
error("Validation failed for property $name with value $item")
|
||||
}
|
||||
}
|
||||
|
||||
fun Configurable.setProperty(key: String, item: MetaItem<*>?) {
|
@ -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 <T> Configurable.item(
|
||||
default: T? = null,
|
||||
key: Name? = null,
|
||||
writer: (T) -> MetaItem<*>? = { MetaItem.of(it) },
|
||||
writer: (T) -> MetaItem<*>? = {
|
||||
MetaItem.of(it)
|
||||
},
|
||||
reader: (MetaItem<*>?) -> T
|
||||
): ReadWriteProperty<Any?, T> =
|
||||
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<Any?, Value?> =
|
||||
item(default, key).transform { it.value }
|
||||
@ -68,9 +81,13 @@ fun <T> Configurable.value(
|
||||
writer: (T) -> Value? = { Value.of(it) },
|
||||
reader: (Value?) -> T
|
||||
): ReadWriteProperty<Any?, T> =
|
||||
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<Any?, String?> =
|
||||
@ -184,6 +201,10 @@ fun Configurable.doubleArray(vararg doubles: Double, key: Name? = null): ReadWri
|
||||
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> =
|
||||
config.node(key)
|
||||
|
||||
fun Configurable.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item().map(
|
||||
reader = { it.node },
|
||||
writer = { it?.let { MetaItem.NodeItem(it) } }
|
||||
)
|
||||
|
||||
fun <T : Configurable> Configurable.spec(spec: Specification<T>, key: Name? = null): ReadWriteProperty<Any?, T?> =
|
||||
object : ReadWriteProperty<Any?, T?> {
|
@ -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<NameToken, MetaItem<*>> =
|
||||
(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<T : Scheme>(val builder: () -> T) : Specification<T> {
|
||||
open class SchemeSpec<T : Scheme>(val builder: () -> T) :
|
||||
Specification<T> {
|
||||
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 <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit) = spec.wrap(this).apply(block)
|
||||
|
||||
/**
|
||||
* Create a snapshot laminate
|
||||
*/
|
||||
fun Scheme.toMeta(): Laminate = Laminate(config, defaultLayer)
|
||||
fun Scheme.toMeta(): Laminate =
|
||||
Laminate(config, defaultLayer)
|
@ -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<T : Configurable> {
|
||||
/**
|
||||
* 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 <C : Configurable, S : Specification<C>> Configurable.update(spec: S, action
|
||||
fun <C : Configurable, S : Specification<C>> S.createStyle(action: C.() -> Unit): Meta =
|
||||
Config().also { update(it, action) }
|
||||
|
||||
fun <T : Configurable> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(Config(), it) }
|
||||
fun <T : Configurable> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(
|
||||
Config(), it) }
|
||||
|
||||
@JvmName("configSpec")
|
||||
fun <T : Configurable> MetaItem<Config>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(it) }
|
@ -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,7 +89,8 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
|
||||
/**
|
||||
* Produce new meta using only those items that match transformation rules
|
||||
*/
|
||||
fun transform(source: Meta): Meta = buildMeta {
|
||||
fun transform(source: Meta): Meta =
|
||||
buildMeta {
|
||||
transformations.forEach { rule ->
|
||||
rule.selectItems(source).forEach { name ->
|
||||
rule.transformItem(name, source[name], this)
|
||||
@ -98,7 +101,8 @@ inline class MetaTransformation(val transformations: Collection<TransformationRu
|
||||
/**
|
||||
* Transform a meta, replacing all elements found in rules with transformed entries
|
||||
*/
|
||||
fun apply(source: Meta): Meta = buildMeta(source) {
|
||||
fun apply(source: Meta): Meta =
|
||||
buildMeta(source) {
|
||||
transformations.forEach { rule ->
|
||||
rule.selectItems(source).forEach { name ->
|
||||
remove(name)
|
||||
@ -150,7 +154,8 @@ class MetaTransformationBuilder {
|
||||
* Keep nodes by regex
|
||||
*/
|
||||
fun keep(regex: String) {
|
||||
transformations.add(RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem ->
|
||||
transformations.add(
|
||||
RegexItemTransformationRule(regex.toRegex()) { name, _, metaItem ->
|
||||
setItem(name, metaItem)
|
||||
})
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.meta.scheme.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
dataforge-tables/build.gradle.kts
Normal file
14
dataforge-tables/build.gradle.kts
Normal file
@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
id("scientifik.mpp")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
val commonMain by getting{
|
||||
dependencies {
|
||||
api(project(":dataforge-context"))
|
||||
api(project(":dataforge-io"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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>(::ColumnScheme)
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ColumnTable(override val columns: Map<String, Column<*>>) :
|
||||
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<Row>
|
||||
get() = (0 until rowsNum).map { VirtualRow(it) }
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : Any> getValue(row: Int, column: String, type: KClass<out T>): 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 <T : Any> getValue(column: String, type: KClass<out T>): T? = getValue(index, column, type)
|
||||
}
|
||||
}
|
||||
|
||||
class ColumnTableBuilder {
|
||||
private val columns = ArrayList<Column<*>>()
|
||||
|
||||
fun build() = ColumnTable(columns.associateBy { it.name })
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class ListColumn<T : Any>(
|
||||
override val name: String,
|
||||
private val data: List<T?>,
|
||||
override val type: KClass<out T>,
|
||||
override val meta: Meta
|
||||
) : Column<T> {
|
||||
override val size: Int get() = data.size
|
||||
|
||||
override fun get(index: Int): T? = data[index]
|
||||
|
||||
companion object {
|
||||
inline operator fun <reified T : Any> invoke(
|
||||
name: String,
|
||||
data: List<T>,
|
||||
noinline metaBuilder: ColumnScheme.() -> Unit
|
||||
): ListColumn<T> = ListColumn(name, data, T::class, ColumnScheme(metaBuilder).toMeta())
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T : Any, reified R : Any> Column<T>.map(meta: Meta = this.meta, noinline block: (T?) -> R): Column<R> {
|
||||
val data = List(size) { block(get(it)) }
|
||||
return ListColumn(name, data, R::class, meta)
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class MapRow(val values: Map<String, Any>) : Row {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : Any> getValue(column: String, type: KClass<out T>): 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}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
//interface NumberColumn<N : Number> : Column<N>
|
||||
|
||||
data class RealColumn(
|
||||
override val name: String,
|
||||
val data: DoubleArray,
|
||||
override val meta: Meta = Meta.EMPTY
|
||||
) : Column<Double> {
|
||||
override val type: KClass<out Double> 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 <reified T : Any> invoke(
|
||||
name: String,
|
||||
data: DoubleArray,
|
||||
noinline metaBuilder: ColumnScheme.() -> Unit
|
||||
): RealColumn = RealColumn(name, data, ColumnScheme(metaBuilder).toMeta())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> Column<T>.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<Int> {
|
||||
override val type: KClass<out Int> 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 <reified T : Any> invoke(
|
||||
name: String,
|
||||
data: IntArray,
|
||||
noinline metaBuilder: ColumnScheme.() -> Unit
|
||||
): IntColumn = IntColumn(name, data, ColumnScheme(metaBuilder).toMeta())
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : Any> Column<T>.map(meta: Meta = this.meta, block: (T?) -> Int): IntColumn {
|
||||
val data = IntArray(size) { block(get(it)) }
|
||||
return IntColumn(name, data, meta)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
data class ColumnDef<T : Any>(val name: String, val type: KClass<T>, val meta: Meta)
|
||||
|
||||
class RowTable<R : Row>(override val rows: List<R>, private val columnDefs: List<ColumnDef<*>>) : Table {
|
||||
override fun <T : Any> getValue(row: Int, column: String, type: KClass<out T>): T? =
|
||||
rows[row].getValue(column, type)
|
||||
|
||||
override val columns: Map<String, Column<*>>
|
||||
get() = columnDefs.associate { it.name to VirtualColumn(it) }
|
||||
|
||||
private inner class VirtualColumn<T : Any>(val def: ColumnDef<T>) :
|
||||
Column<T> {
|
||||
|
||||
override val name: String get() = def.name
|
||||
override val type: KClass<out T> 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)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package hep.dataforge.tables
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
interface Table {
|
||||
fun <T : Any> getValue(row: Int, column: String, type: KClass<out T>): T?
|
||||
val columns: Map<String, Column<*>>
|
||||
val rows: List<Row>
|
||||
}
|
||||
|
||||
interface Column<out T : Any> {
|
||||
val name: String
|
||||
val type: KClass<out T>
|
||||
val meta: Meta
|
||||
val size: Int
|
||||
operator fun get(index: Int): T?
|
||||
}
|
||||
|
||||
val Column<*>.indices get() = (0 until size)
|
||||
|
||||
operator fun <T : Any> Column<T>.iterator() = iterator {
|
||||
for (i in indices){
|
||||
yield(get(i))
|
||||
}
|
||||
}
|
||||
|
||||
interface Row {
|
||||
fun <T : Any> getValue(column: String, type: KClass<out T>): T?
|
||||
}
|
@ -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 <reified T : Any> column() = ColumnProperty(table, T::class)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> Column<*>.cast(type: KClass<T>): Column<T> {
|
||||
return if (type.isSubclassOf(this.type)) {
|
||||
this as Column<T>
|
||||
} else {
|
||||
ColumnWrapper(this, type)
|
||||
}
|
||||
}
|
||||
|
||||
class ColumnWrapper<T : Any>(val column: Column<*>, override val type: KClass<T>) : Column<T> {
|
||||
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<T : Any>(val table: Table, val type: KClass<T>) : ReadOnlyProperty<Any?, Column<T>?> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): Column<T>? {
|
||||
val name = property.name
|
||||
return table.columns[name]?.cast(type)
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user