Clean up scheme and descriptor logic

This commit is contained in:
Alexander Nozik 2023-12-31 11:57:54 +03:00
parent 6e20fc3929
commit 282b43a05a
9 changed files with 274 additions and 277 deletions

View File

@ -8,7 +8,7 @@ plugins {
allprojects { allprojects {
group = "space.kscience" group = "space.kscience"
version = "0.7.2-dev-2" version = "0.8.0-dev-1"
} }
subprojects { subprojects {

View File

@ -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 = "")

View File

@ -1,53 +1,124 @@
package space.kscience.dataforge.descriptors 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>, * Description text for meta property, node or whole object
// delegate: ConfigurableDelegate */
//): ItemDescriptor { @Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
// when { @Retention(AnnotationRetention.RUNTIME)
// V::class.isSubclassOf(Scheme::class) -> NodeDescriptor { @MustBeDocumented
// default = delegate.default.node public annotation class Description(val value: String)
// }
// V::class.isSubclassOf(Meta::class) -> NodeDescriptor { @Target(AnnotationTarget.PROPERTY)
// default = delegate.default.node @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)

View File

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

View File

@ -71,6 +71,11 @@ internal class ByteArrayBinary(
override fun view(offset: Int, binarySize: Int): ByteArrayBinary = override fun view(offset: Int, binarySize: Int): ByteArrayBinary =
ByteArrayBinary(array, start + offset, binarySize) ByteArrayBinary(array, start + offset, binarySize)
override fun toString(): String =
"ByteArrayBinary(array=$array, start=$start, size=$size)"
} }
public fun ByteArray.asBinary(): Binary = ByteArrayBinary(this) public fun ByteArray.asBinary(): Binary = ByteArrayBinary(this)

View File

@ -15,28 +15,38 @@ import space.kscience.dataforge.names.*
public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurable { 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 * 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 val meta: ObservableMutableMeta = SchemeMeta(Name.EMPTY)
final override var descriptor: MetaDescriptor? = null final override var descriptor: MetaDescriptor? = null
internal set private set
internal fun wrap( /**
newMeta: MutableMeta, * This method must be called before the scheme could be used
preserveDefault: Boolean = false, */
internal fun initialize(
target: MutableMeta,
prototype: Meta,
descriptor: MetaDescriptor?,
) { ) {
if (preserveDefault) { this.target = target
defaultMeta = targetMeta.seal() this.prototype = prototype
} this.descriptor = descriptor
targetMeta = newMeta
} }
/** /**
@ -47,11 +57,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
return descriptor?.validate(meta) ?: true 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?) { override fun set(name: Name, node: Meta?) {
if (validate(name, meta)) { if (validate(name, meta)) {
meta.set(name, node) meta[name] = node
} else { } else {
error("Validation failed for node $node at $name") 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() private val listeners: MutableList<MetaListener> = mutableListOf()
override fun toString(): String = meta.toString()
private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta { private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta {
override var value: Value? override var value: Value?
get() = targetMeta[pathName]?.value get() = target[pathName]?.value
?: defaultMeta?.get(pathName)?.value ?: prototype?.get(pathName)?.value
?: descriptor?.get(pathName)?.defaultValue ?: descriptor?.get(pathName)?.defaultValue
set(value) { set(value) {
val oldValue = targetMeta[pathName]?.value val oldValue = target[pathName]?.value
targetMeta[pathName] = value target!![pathName] = value
if (oldValue != value) { if (oldValue != value) {
invalidate(Name.EMPTY) invalidate(Name.EMPTY)
} }
@ -83,8 +95,8 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
override val items: Map<NameToken, ObservableMutableMeta> override val items: Map<NameToken, ObservableMutableMeta>
get() { get() {
val targetKeys = targetMeta[pathName]?.items?.keys ?: emptySet() val targetKeys = target[pathName]?.items?.keys ?: emptySet()
val defaultKeys = defaultMeta?.get(pathName)?.items?.keys ?: emptySet() val defaultKeys = prototype?.get(pathName)?.items?.keys ?: emptySet()
return (targetKeys + defaultKeys).associateWith { SchemeMeta(pathName + it) } 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 hashCode(): Int = Meta.hashCode(this)
override fun set(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
targetMeta.set(name, node) target!![name] = node
invalidate(name) invalidate(name)
} }
@ -119,7 +131,6 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
@DFExperimental @DFExperimental
override fun attach(name: Name, node: ObservableMutableMeta) { override fun attach(name: Name, node: ObservableMutableMeta) {
//TODO implement zero-copy attachment
set(name, node) set(name, node)
node.onChange(this) { changeName -> node.onChange(this) { changeName ->
set(name + changeName, 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. * 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 { 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, private val builder: () -> T,
) : Specification<T> { ) : Specification<T> {
override val descriptor: MetaDescriptor? get() = null
override fun read(source: Meta): T = builder().also { 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 { 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 { override fun empty(): T = builder().also {
it.descriptor = descriptor it.initialize(MutableMeta(), Meta.EMPTY, descriptor)
} }
@Suppress("OVERRIDE_BY_INLINE") @Suppress("OVERRIDE_BY_INLINE")

View File

@ -44,38 +44,27 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
attributes.apply(block) attributes.apply(block)
} }
public fun item(name: Name, block: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptorBuilder { internal fun node(
return when (name.length) {
0 -> apply(block)
1 -> {
val target = MetaDescriptorBuilder().apply(block)
children[name.first().body] = target
target
}
else -> {
children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), block)
}
}
}
public fun node(
name: Name, name: Name,
descriptor: MetaDescriptor, descriptorBuilder: MetaDescriptorBuilder,
block: MetaDescriptorBuilder.() -> Unit = {}, ): Unit {
): MetaDescriptorBuilder = when (name.length) { when (name.length) {
0 -> error("Can't set descriptor to root") 0 -> error("Can't set descriptor to root")
1 -> { 1 -> {
val item = descriptor.toBuilder().apply { children[name.first().body] = descriptorBuilder
valueRestriction = ValueRestriction.ABSENT
}.apply(block)
children[name.first().body] = item
item
} }
else -> children.getOrPut(name.first().body) { else -> children.getOrPut(name.first().body) {
MetaDescriptorBuilder() MetaDescriptorBuilder()
}.node(name.cutFirst(), descriptor, block) }.node(name.cutFirst(), descriptorBuilder)
}
}
internal fun node(
name: Name,
descriptorBuilder: MetaDescriptor,
): Unit {
node(name, descriptorBuilder.toBuilder())
} }
public var allowedValues: List<Value> public var allowedValues: List<Value>
@ -89,6 +78,17 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
allowedValues = values.map { Value.of(it) } 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 @PublishedApi
internal fun build(): MetaDescriptor = MetaDescriptor( internal fun build(): MetaDescriptor = MetaDescriptor(
description = description, description = description,
@ -102,40 +102,27 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
) )
} }
public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder = //public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder =
item(Name.parse(name), block) // item(Name.parse(name), block)
public inline fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor = public inline fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor =
MetaDescriptorBuilder().apply(block).build() MetaDescriptorBuilder().apply(block).build()
/** /**
* Create and configure child value descriptor * Create and configure child node 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
*/ */
public fun MetaDescriptorBuilder.node( public fun MetaDescriptorBuilder.node(
name: Name, block: MetaDescriptorBuilder.() -> Unit, name: Name,
): MetaDescriptorBuilder = item(name) { block: MetaDescriptorBuilder.() -> Unit,
valueRestriction = ValueRestriction.ABSENT ) {
block() 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) { 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( public fun MetaDescriptorBuilder.node(
key: String, key: String,
described: Described, base: Described,
block: MetaDescriptorBuilder.() -> Unit = {}, block: MetaDescriptorBuilder.() -> Unit = {},
) { ) {
described.descriptor?.let { node(Name.parse(key), base.descriptor?.toBuilder()?.apply(block) ?: MetaDescriptorBuilder())
node(Name.parse(key), it, block)
}
} }
public fun MetaDescriptorBuilder.required() { public fun MetaDescriptorBuilder.required() {
valueRestriction = ValueRestriction.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 { private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
description = this@toBuilder.description description = this@toBuilder.description
children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() } children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
@ -179,6 +152,40 @@ private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBu
attributes = this@toBuilder.attributes.toMutableMeta() 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] * Make a deep copy of this descriptor applying given transformation [block]
*/ */

View File

@ -9,7 +9,7 @@ import kotlin.reflect.typeOf
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value( public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
property: KProperty1<S, T>, property: KProperty1<S, T>,
noinline block: MetaDescriptorBuilder.() -> Unit = {}, noinline block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = when (typeOf<T>()) { ): Unit = when (typeOf<T>()) {
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() -> typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
value(property.name, ValueType.NUMBER) { value(property.name, ValueType.NUMBER) {
block() block()
@ -34,7 +34,7 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
multiple = true multiple = true
block() block()
} }
else -> item(property.name, block) else -> node(property.name, block)
} }
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme( public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(

View File

@ -2,7 +2,7 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor 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.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -32,7 +32,7 @@ class JsonMetaTest {
} }
val descriptor = MetaDescriptor { val descriptor = MetaDescriptor {
item("nodeArray") { node("nodeArray") {
indexKey = "index" indexKey = "index"
} }
} }