Clean up scheme and descriptor logic
This commit is contained in:
parent
6e20fc3929
commit
282b43a05a
@ -8,7 +8,7 @@ plugins {
|
||||
|
||||
allprojects {
|
||||
group = "space.kscience"
|
||||
version = "0.7.2-dev-2"
|
||||
version = "0.8.0-dev-1"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
|
@ -1,126 +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 space.kscience.dataforge.descriptors
|
||||
|
||||
//@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 = "")
|
@ -1,53 +1,124 @@
|
||||
package space.kscience.dataforge.descriptors
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import org.slf4j.LoggerFactory
|
||||
import space.kscience.dataforge.meta.Scheme
|
||||
import space.kscience.dataforge.meta.SchemeSpec
|
||||
import space.kscience.dataforge.meta.ValueType
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
|
||||
import space.kscience.dataforge.meta.descriptors.node
|
||||
import java.net.URL
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
//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
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
||||
/**
|
||||
* Description text for meta property, node or whole object
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
public annotation class Description(val value: String)
|
||||
|
||||
@Target(AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
public annotation class Multiple()
|
||||
|
||||
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
public annotation class DescriptorResource(val resourceName: String)
|
||||
|
||||
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
public annotation class DescriptorUrl(val url: String)
|
||||
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
private fun MetaDescriptorBuilder.loadDescriptorFromUrl(url: URL) {
|
||||
url.openStream().use {
|
||||
from(Json.decodeFromStream(MetaDescriptor.serializer(), it))
|
||||
}
|
||||
}
|
||||
|
||||
private fun MetaDescriptorBuilder.loadDescriptorFromResource(resource: DescriptorResource) {
|
||||
val url = {}.javaClass.getResource(resource.resourceName)
|
||||
if (url != null) {
|
||||
loadDescriptorFromUrl(url)
|
||||
} else {
|
||||
LoggerFactory.getLogger("System")
|
||||
.error("Can't find descriptor resource with name ${resource.resourceName}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public fun <T : Any> MetaDescriptor.Companion.forClass(
|
||||
kClass: KClass<T>,
|
||||
mod: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptor = MetaDescriptor {
|
||||
when {
|
||||
kClass.isSubclassOf(Number::class) -> valueType(ValueType.NUMBER)
|
||||
kClass == String::class -> ValueType.STRING
|
||||
kClass == Boolean::class -> ValueType.BOOLEAN
|
||||
kClass == DoubleArray::class -> ValueType.LIST
|
||||
}
|
||||
|
||||
kClass.annotations.forEach {
|
||||
when (it) {
|
||||
is Description -> description = it.value
|
||||
|
||||
is DescriptorResource -> loadDescriptorFromResource(it)
|
||||
|
||||
is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url))
|
||||
}
|
||||
}
|
||||
kClass.memberProperties.forEach { property ->
|
||||
|
||||
var flag = false
|
||||
|
||||
val descriptor = MetaDescriptor {
|
||||
//use base type descriptor as a base
|
||||
(property.returnType.classifier as? KClass<*>)?.let {
|
||||
from(forClass(it))
|
||||
}
|
||||
property.annotations.forEach {
|
||||
when (it) {
|
||||
is Description -> {
|
||||
description = it.value
|
||||
flag = true
|
||||
}
|
||||
|
||||
is Multiple -> {
|
||||
multiple = true
|
||||
flag = true
|
||||
}
|
||||
|
||||
is DescriptorResource -> {
|
||||
loadDescriptorFromResource(it)
|
||||
flag = true
|
||||
}
|
||||
|
||||
is DescriptorUrl -> {
|
||||
loadDescriptorFromUrl(URL(it.url))
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
node(property.name, descriptor)
|
||||
}
|
||||
}
|
||||
mod()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
public inline fun <reified T : Scheme> SchemeSpec<T>.autoDescriptor( noinline mod: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptor =
|
||||
MetaDescriptor.forClass(typeOf<T>().classifier as KClass<T>, mod)
|
@ -0,0 +1,29 @@
|
||||
package space.kscience.dataforge.descriptors
|
||||
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.junit.jupiter.api.Test
|
||||
import space.kscience.dataforge.meta.*
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.transformations.MetaConverter
|
||||
|
||||
private class TestScheme: Scheme(){
|
||||
|
||||
@Description("A")
|
||||
val a by string()
|
||||
|
||||
@Description("B")
|
||||
val b by int()
|
||||
|
||||
companion object: SchemeSpec<TestScheme>(::TestScheme){
|
||||
override val descriptor: MetaDescriptor = autoDescriptor()
|
||||
}
|
||||
}
|
||||
|
||||
class TestAutoDescriptors {
|
||||
@Test
|
||||
fun autoDescriptor(){
|
||||
val autoDescriptor = MetaDescriptor.forClass(TestScheme::class)
|
||||
println(Json{prettyPrint = true}.encodeToString(autoDescriptor))
|
||||
}
|
||||
}
|
@ -71,6 +71,11 @@ internal class ByteArrayBinary(
|
||||
|
||||
override fun view(offset: Int, binarySize: Int): ByteArrayBinary =
|
||||
ByteArrayBinary(array, start + offset, binarySize)
|
||||
|
||||
override fun toString(): String =
|
||||
"ByteArrayBinary(array=$array, start=$start, size=$size)"
|
||||
|
||||
|
||||
}
|
||||
|
||||
public fun ByteArray.asBinary(): Binary = ByteArrayBinary(this)
|
||||
|
@ -15,28 +15,38 @@ import space.kscience.dataforge.names.*
|
||||
public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurable {
|
||||
|
||||
/**
|
||||
* Meta to be mutated by this schme
|
||||
* Meta to be mutated by this scheme
|
||||
*/
|
||||
private var targetMeta: MutableMeta = MutableMeta()
|
||||
private var target: MutableMeta? = null
|
||||
get() {
|
||||
// automatic initialization of target if it is missing
|
||||
if (field == null) {
|
||||
field = MutableMeta()
|
||||
}
|
||||
return field
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values provided by this scheme
|
||||
*/
|
||||
private var defaultMeta: Meta? = null
|
||||
private var prototype: Meta? = null
|
||||
|
||||
final override val meta: ObservableMutableMeta = SchemeMeta(Name.EMPTY)
|
||||
|
||||
final override var descriptor: MetaDescriptor? = null
|
||||
internal set
|
||||
private set
|
||||
|
||||
internal fun wrap(
|
||||
newMeta: MutableMeta,
|
||||
preserveDefault: Boolean = false,
|
||||
/**
|
||||
* This method must be called before the scheme could be used
|
||||
*/
|
||||
internal fun initialize(
|
||||
target: MutableMeta,
|
||||
prototype: Meta,
|
||||
descriptor: MetaDescriptor?,
|
||||
) {
|
||||
if (preserveDefault) {
|
||||
defaultMeta = targetMeta.seal()
|
||||
}
|
||||
targetMeta = newMeta
|
||||
this.target = target
|
||||
this.prototype = prototype
|
||||
this.descriptor = descriptor
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,11 +57,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
return descriptor?.validate(meta) ?: true
|
||||
}
|
||||
|
||||
override fun get(name: Name): MutableMeta? = meta.get(name)
|
||||
override fun get(name: Name): MutableMeta? = meta[name]
|
||||
|
||||
override fun set(name: Name, node: Meta?) {
|
||||
if (validate(name, meta)) {
|
||||
meta.set(name, node)
|
||||
meta[name] = node
|
||||
} else {
|
||||
error("Validation failed for node $node at $name")
|
||||
}
|
||||
@ -68,14 +78,16 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
|
||||
private val listeners: MutableList<MetaListener> = mutableListOf()
|
||||
|
||||
override fun toString(): String = meta.toString()
|
||||
|
||||
private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta {
|
||||
override var value: Value?
|
||||
get() = targetMeta[pathName]?.value
|
||||
?: defaultMeta?.get(pathName)?.value
|
||||
get() = target[pathName]?.value
|
||||
?: prototype?.get(pathName)?.value
|
||||
?: descriptor?.get(pathName)?.defaultValue
|
||||
set(value) {
|
||||
val oldValue = targetMeta[pathName]?.value
|
||||
targetMeta[pathName] = value
|
||||
val oldValue = target[pathName]?.value
|
||||
target!![pathName] = value
|
||||
if (oldValue != value) {
|
||||
invalidate(Name.EMPTY)
|
||||
}
|
||||
@ -83,8 +95,8 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
|
||||
override val items: Map<NameToken, ObservableMutableMeta>
|
||||
get() {
|
||||
val targetKeys = targetMeta[pathName]?.items?.keys ?: emptySet()
|
||||
val defaultKeys = defaultMeta?.get(pathName)?.items?.keys ?: emptySet()
|
||||
val targetKeys = target[pathName]?.items?.keys ?: emptySet()
|
||||
val defaultKeys = prototype?.get(pathName)?.items?.keys ?: emptySet()
|
||||
return (targetKeys + defaultKeys).associateWith { SchemeMeta(pathName + it) }
|
||||
}
|
||||
|
||||
@ -111,7 +123,7 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
override fun hashCode(): Int = Meta.hashCode(this)
|
||||
|
||||
override fun set(name: Name, node: Meta?) {
|
||||
targetMeta.set(name, node)
|
||||
target!![name] = node
|
||||
invalidate(name)
|
||||
}
|
||||
|
||||
@ -119,7 +131,6 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
|
||||
@DFExperimental
|
||||
override fun attach(name: Name, node: ObservableMutableMeta) {
|
||||
//TODO implement zero-copy attachment
|
||||
set(name, node)
|
||||
node.onChange(this) { changeName ->
|
||||
set(name + changeName, this[changeName])
|
||||
@ -131,10 +142,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
|
||||
|
||||
/**
|
||||
* Relocate scheme target onto given [MutableMeta]. Old provider does not get updates anymore.
|
||||
* Current state of the scheme used as a default.
|
||||
* The Current state of the scheme that os used as a default.
|
||||
*/
|
||||
@DFExperimental
|
||||
public fun <T : Scheme> T.retarget(provider: MutableMeta): T = apply {
|
||||
wrap(provider, true)
|
||||
initialize(provider, meta.seal(), descriptor)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,19 +167,18 @@ public open class SchemeSpec<out T : Scheme>(
|
||||
private val builder: () -> T,
|
||||
) : Specification<T> {
|
||||
|
||||
override val descriptor: MetaDescriptor? get() = null
|
||||
|
||||
override fun read(source: Meta): T = builder().also {
|
||||
it.wrap(MutableMeta().withDefault(source))
|
||||
it.initialize(MutableMeta(), source, descriptor)
|
||||
}
|
||||
|
||||
override fun write(target: MutableMeta): T = empty().also {
|
||||
it.wrap(target)
|
||||
it.initialize(target, Meta.EMPTY, descriptor)
|
||||
}
|
||||
|
||||
//TODO Generate descriptor from Scheme class
|
||||
override val descriptor: MetaDescriptor? get() = null
|
||||
|
||||
override fun empty(): T = builder().also {
|
||||
it.descriptor = descriptor
|
||||
it.initialize(MutableMeta(), Meta.EMPTY, descriptor)
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_BY_INLINE")
|
||||
|
@ -44,38 +44,27 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
|
||||
attributes.apply(block)
|
||||
}
|
||||
|
||||
public fun item(name: Name, block: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptorBuilder {
|
||||
return when (name.length) {
|
||||
0 -> apply(block)
|
||||
internal fun node(
|
||||
name: Name,
|
||||
descriptorBuilder: MetaDescriptorBuilder,
|
||||
): Unit {
|
||||
when (name.length) {
|
||||
0 -> error("Can't set descriptor to root")
|
||||
1 -> {
|
||||
val target = MetaDescriptorBuilder().apply(block)
|
||||
children[name.first().body] = target
|
||||
target
|
||||
children[name.first().body] = descriptorBuilder
|
||||
}
|
||||
|
||||
else -> {
|
||||
children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), block)
|
||||
}
|
||||
else -> children.getOrPut(name.first().body) {
|
||||
MetaDescriptorBuilder()
|
||||
}.node(name.cutFirst(), descriptorBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
public fun node(
|
||||
internal fun node(
|
||||
name: Name,
|
||||
descriptor: MetaDescriptor,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptorBuilder = when (name.length) {
|
||||
0 -> error("Can't set descriptor to root")
|
||||
1 -> {
|
||||
val item = descriptor.toBuilder().apply {
|
||||
valueRestriction = ValueRestriction.ABSENT
|
||||
}.apply(block)
|
||||
children[name.first().body] = item
|
||||
item
|
||||
}
|
||||
|
||||
else -> children.getOrPut(name.first().body) {
|
||||
MetaDescriptorBuilder()
|
||||
}.node(name.cutFirst(), descriptor, block)
|
||||
descriptorBuilder: MetaDescriptor,
|
||||
): Unit {
|
||||
node(name, descriptorBuilder.toBuilder())
|
||||
}
|
||||
|
||||
public var allowedValues: List<Value>
|
||||
@ -89,6 +78,17 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
|
||||
allowedValues = values.map { Value.of(it) }
|
||||
}
|
||||
|
||||
public fun from(descriptor: MetaDescriptor) {
|
||||
description = descriptor.description
|
||||
children.putAll(descriptor.children.mapValues { it.value.toBuilder() })
|
||||
multiple = descriptor.multiple
|
||||
valueRestriction = descriptor.valueRestriction
|
||||
valueTypes = descriptor.valueTypes
|
||||
indexKey = descriptor.indexKey
|
||||
default = descriptor.defaultValue
|
||||
attributes.update(descriptor.attributes)
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun build(): MetaDescriptor = MetaDescriptor(
|
||||
description = description,
|
||||
@ -102,40 +102,27 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
|
||||
)
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder =
|
||||
item(Name.parse(name), block)
|
||||
//public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder =
|
||||
// item(Name.parse(name), block)
|
||||
|
||||
public inline fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor =
|
||||
MetaDescriptorBuilder().apply(block).build()
|
||||
|
||||
/**
|
||||
* Create and configure child value descriptor
|
||||
*/
|
||||
public fun MetaDescriptorBuilder.value(
|
||||
name: Name,
|
||||
type: ValueType,
|
||||
vararg additionalTypes: ValueType,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptorBuilder = item(name) {
|
||||
valueType(type, *additionalTypes)
|
||||
block()
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.value(
|
||||
name: String,
|
||||
type: ValueType,
|
||||
vararg additionalTypes: ValueType,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptorBuilder = value(Name.parse(name), type, additionalTypes = additionalTypes, block)
|
||||
|
||||
/**
|
||||
* Create and configure child value descriptor
|
||||
* Create and configure child node descriptor
|
||||
*/
|
||||
public fun MetaDescriptorBuilder.node(
|
||||
name: Name, block: MetaDescriptorBuilder.() -> Unit,
|
||||
): MetaDescriptorBuilder = item(name) {
|
||||
valueRestriction = ValueRestriction.ABSENT
|
||||
block()
|
||||
name: Name,
|
||||
block: MetaDescriptorBuilder.() -> Unit,
|
||||
) {
|
||||
node(
|
||||
name,
|
||||
MetaDescriptorBuilder().apply(block)
|
||||
)
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.node(name: String, descriptor: MetaDescriptor) {
|
||||
node(Name.parse(name), descriptor)
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder.() -> Unit) {
|
||||
@ -144,30 +131,16 @@ public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder
|
||||
|
||||
public fun MetaDescriptorBuilder.node(
|
||||
key: String,
|
||||
described: Described,
|
||||
base: Described,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
) {
|
||||
described.descriptor?.let {
|
||||
node(Name.parse(key), it, block)
|
||||
}
|
||||
node(Name.parse(key), base.descriptor?.toBuilder()?.apply(block) ?: MetaDescriptorBuilder())
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.required() {
|
||||
valueRestriction = ValueRestriction.REQUIRED
|
||||
}
|
||||
|
||||
public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
|
||||
key: Name,
|
||||
default: E?,
|
||||
crossinline modifier: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptorBuilder = value(key, ValueType.STRING) {
|
||||
default?.let {
|
||||
this.default = default.asValue()
|
||||
}
|
||||
allowedValues = enumValues<E>().map { it.asValue() }
|
||||
modifier()
|
||||
}
|
||||
|
||||
private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
|
||||
description = this@toBuilder.description
|
||||
children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
|
||||
@ -179,6 +152,40 @@ private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBu
|
||||
attributes = this@toBuilder.attributes.toMutableMeta()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create and configure child value descriptor
|
||||
*/
|
||||
public fun MetaDescriptorBuilder.value(
|
||||
name: Name,
|
||||
type: ValueType,
|
||||
vararg additionalTypes: ValueType,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): Unit = node(name) {
|
||||
valueType(type, *additionalTypes)
|
||||
block()
|
||||
}
|
||||
|
||||
public fun MetaDescriptorBuilder.value(
|
||||
name: String,
|
||||
type: ValueType,
|
||||
vararg additionalTypes: ValueType,
|
||||
block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): Unit = value(Name.parse(name), type, additionalTypes = additionalTypes, block)
|
||||
|
||||
|
||||
public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
|
||||
key: Name,
|
||||
default: E?,
|
||||
crossinline modifier: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): Unit = value(key, ValueType.STRING) {
|
||||
default?.let {
|
||||
this.default = default.asValue()
|
||||
}
|
||||
allowedValues = enumValues<E>().map { it.asValue() }
|
||||
modifier()
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a deep copy of this descriptor applying given transformation [block]
|
||||
*/
|
||||
|
@ -9,7 +9,7 @@ import kotlin.reflect.typeOf
|
||||
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
|
||||
property: KProperty1<S, T>,
|
||||
noinline block: MetaDescriptorBuilder.() -> Unit = {},
|
||||
): MetaDescriptorBuilder = when (typeOf<T>()) {
|
||||
): Unit = when (typeOf<T>()) {
|
||||
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
|
||||
value(property.name, ValueType.NUMBER) {
|
||||
block()
|
||||
@ -34,7 +34,7 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
|
||||
multiple = true
|
||||
block()
|
||||
}
|
||||
else -> item(property.name, block)
|
||||
else -> node(property.name, block)
|
||||
}
|
||||
|
||||
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
|
||||
|
@ -2,7 +2,7 @@ package space.kscience.dataforge.meta
|
||||
|
||||
import kotlinx.serialization.json.*
|
||||
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
|
||||
import space.kscience.dataforge.meta.descriptors.item
|
||||
import space.kscience.dataforge.meta.descriptors.node
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@ -32,7 +32,7 @@ class JsonMetaTest {
|
||||
}
|
||||
|
||||
val descriptor = MetaDescriptor {
|
||||
item("nodeArray") {
|
||||
node("nodeArray") {
|
||||
indexKey = "index"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user