dataforge-meta cleanup

This commit is contained in:
Alexander Nozik 2020-09-07 22:43:39 +03:00
parent 87af89b47d
commit 52a3c8bc6f
20 changed files with 206 additions and 270 deletions

View File

@ -2,7 +2,6 @@ package hep.dataforge.context
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaRepr import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.buildMeta
import hep.dataforge.names.Name import hep.dataforge.names.Name
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.provider.Provider import hep.dataforge.provider.Provider

View File

@ -2,7 +2,6 @@ package hep.dataforge.context
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaRepr import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.buildMeta
/** /**
* The tag which contains information about name, group and version of some * The tag which contains information about name, group and version of some
@ -10,7 +9,7 @@ import hep.dataforge.meta.buildMeta
* *
* @author Alexander Nozik * @author Alexander Nozik
*/ */
data class PluginTag( public data class PluginTag(
val name: String, val name: String,
val group: String = "", val group: String = "",
val version: String = "" val version: String = ""
@ -22,7 +21,7 @@ data class PluginTag(
* @param otherTag * @param otherTag
* @return * @return
*/ */
fun matches(otherTag: PluginTag): Boolean { public fun matches(otherTag: PluginTag): Boolean {
return matchesName(otherTag) && matchesGroup(otherTag) return matchesName(otherTag) && matchesGroup(otherTag)
} }
@ -42,9 +41,9 @@ data class PluginTag(
"version" put version "version" put version
} }
companion object { public companion object {
const val DATAFORGE_GROUP = "hep.dataforge" public const val DATAFORGE_GROUP: String = "hep.dataforge"
/** /**
* Build new PluginTag from standard string representation * Build new PluginTag from standard string representation
@ -52,7 +51,7 @@ data class PluginTag(
* @param tag * @param tag
* @return * @return
*/ */
fun fromString(tag: String): PluginTag { public fun fromString(tag: String): PluginTag {
val sepIndex = tag.indexOf(":") val sepIndex = tag.indexOf(":")
return if (sepIndex >= 0) { return if (sepIndex >= 0) {
PluginTag(group = tag.substring(0, sepIndex), name = tag.substring(sepIndex + 1)) PluginTag(group = tag.substring(0, sepIndex), name = tag.substring(sepIndex + 1))

View File

@ -3,7 +3,6 @@ package hep.dataforge.data
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.isSuperclassOf
/** /**
* Block the thread and get data content * Block the thread and get data content
@ -14,7 +13,7 @@ public fun <T : Any> Data<T>.get(): T = runBlocking { await() }
* Check that node is compatible with given type meaning that each element could be cast to the type * Check that node is compatible with given type meaning that each element could be cast to the type
*/ */
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean = internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
this.type.isSubclassOf(type) type.isSubclassOf(this.type)
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean = internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
this.type.isSubclassOf(type) this.type.isSubclassOf(type)

View File

@ -12,6 +12,7 @@ import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
/** /**
@ -96,8 +97,12 @@ public interface MetaRepr {
public fun toMeta(): Meta public fun toMeta(): Meta
} }
public interface ItemProvider{ public fun interface ItemProvider {
public fun getItem(name: Name): MetaItem<*>? public fun getItem(name: Name): MetaItem<*>?
public companion object {
public val EMPTY: ItemProvider = ItemProvider { null }
}
} }
/** /**
@ -107,6 +112,7 @@ public interface ItemProvider{
* *
* * Same name siblings are supported via elements with the same [Name] but different queries * * Same name siblings are supported via elements with the same [Name] but different queries
*/ */
@Serializable(MetaSerializer::class)
public interface Meta : MetaRepr, ItemProvider { public interface Meta : MetaRepr, ItemProvider {
/** /**
* Top level items of meta tree * Top level items of meta tree
@ -226,7 +232,10 @@ public abstract class MetaBase : Meta {
override fun hashCode(): Int = items.hashCode() override fun hashCode(): Int = items.hashCode()
override fun toString(): String = JSON_PRETTY.encodeToString(MetaSerializer, this) override fun toString(): String = Json {
prettyPrint = true
useArrayPolymorphism = true
}.encodeToString(MetaSerializer, this)
} }
/** /**
@ -240,7 +249,7 @@ public abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase(
* If the argument is possibly mutable node, it is copied on creation * If the argument is possibly mutable node, it is copied on creation
*/ */
public class SealedMeta internal constructor( public class SealedMeta internal constructor(
override val items: Map<NameToken, MetaItem<SealedMeta>> override val items: Map<NameToken, MetaItem<SealedMeta>>,
) : AbstractMetaNode<SealedMeta>() ) : AbstractMetaNode<SealedMeta>()
/** /**

View File

@ -11,113 +11,109 @@ import kotlin.jvm.JvmName
* DSL builder for meta. Is not intended to store mutable state * DSL builder for meta. Is not intended to store mutable state
*/ */
@DFBuilder @DFBuilder
class MetaBuilder : AbstractMutableMeta<MetaBuilder>() { public class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
override fun wrapNode(meta: Meta): MetaBuilder = if (meta is MetaBuilder) meta else meta.builder() override fun wrapNode(meta: Meta): MetaBuilder = if (meta is MetaBuilder) meta else meta.builder()
override fun empty(): MetaBuilder = MetaBuilder() override fun empty(): MetaBuilder = MetaBuilder()
infix fun String.put(item: MetaItem<*>?) { public infix fun String.put(item: MetaItem<*>?) {
set(this, item) set(this, item)
} }
infix fun String.put(value: Value?) { public infix fun String.put(value: Value?) {
set(this, value) set(this, value)
} }
infix fun String.put(string: String?) { public infix fun String.put(string: String?) {
set(this, string?.asValue()) set(this, string?.asValue())
} }
infix fun String.put(number: Number?) { public infix fun String.put(number: Number?) {
set(this, number?.asValue()) set(this, number?.asValue())
} }
infix fun String.put(boolean: Boolean?) { public infix fun String.put(boolean: Boolean?) {
set(this, boolean?.asValue()) set(this, boolean?.asValue())
} }
infix fun String.put(enum: Enum<*>) { public infix fun String.put(enum: Enum<*>) {
set(this, EnumValue(enum)) set(this, EnumValue(enum))
} }
@JvmName("putValues") @JvmName("putValues")
infix fun String.put(iterable: Iterable<Value>) { public infix fun String.put(iterable: Iterable<Value>) {
set(this, iterable.asValue()) set(this, iterable.asValue())
} }
@JvmName("putNumbers") @JvmName("putNumbers")
infix fun String.put(iterable: Iterable<Number>) { public infix fun String.put(iterable: Iterable<Number>) {
set(this, iterable.map { it.asValue() }.asValue()) set(this, iterable.map { it.asValue() }.asValue())
} }
@JvmName("putStrings") @JvmName("putStrings")
infix fun String.put(iterable: Iterable<String>) { public infix fun String.put(iterable: Iterable<String>) {
set(this, iterable.map { it.asValue() }.asValue()) set(this, iterable.map { it.asValue() }.asValue())
} }
infix fun String.put(array: DoubleArray) { public infix fun String.put(array: DoubleArray) {
set(this, array.asValue()) set(this, array.asValue())
} }
infix fun String.putValue(any: Any?) { public infix fun String.put(meta: Meta?) {
set(this, Value.of(any))
}
infix fun String.put(meta: Meta?) {
this@MetaBuilder[this] = meta this@MetaBuilder[this] = meta
} }
infix fun String.put(repr: MetaRepr?) { public infix fun String.put(repr: MetaRepr?) {
set(this, repr?.toMeta()) set(this, repr?.toMeta())
} }
@JvmName("putMetas") @JvmName("putMetas")
infix fun String.put(value: Iterable<Meta>) { public infix fun String.put(value: Iterable<Meta>) {
this@MetaBuilder[this] = value.toList() this@MetaBuilder[this] = value.toList()
} }
infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) { public infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) {
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder) this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
} }
infix fun Name.put(value: Value?) { public infix fun Name.put(value: Value?) {
set(this, value) set(this, value)
} }
infix fun Name.put(string: String?) { public infix fun Name.put(string: String?) {
set(this, string?.asValue()) set(this, string?.asValue())
} }
infix fun Name.put(number: Number?) { public infix fun Name.put(number: Number?) {
set(this, number?.asValue()) set(this, number?.asValue())
} }
infix fun Name.put(boolean: Boolean?) { public infix fun Name.put(boolean: Boolean?) {
set(this, boolean?.asValue()) set(this, boolean?.asValue())
} }
infix fun Name.put(enum: Enum<*>) { public infix fun Name.put(enum: Enum<*>) {
set(this, EnumValue(enum)) set(this, EnumValue(enum))
} }
@JvmName("putValues") @JvmName("putValues")
infix fun Name.put(iterable: Iterable<Value>) { public infix fun Name.put(iterable: Iterable<Value>) {
set(this, iterable.asValue()) set(this, iterable.asValue())
} }
infix fun Name.put(meta: Meta?) { public infix fun Name.put(meta: Meta?) {
this@MetaBuilder[this] = meta this@MetaBuilder[this] = meta
} }
infix fun Name.put(repr: MetaRepr?) { public infix fun Name.put(repr: MetaRepr?) {
set(this, repr?.toMeta()) set(this, repr?.toMeta())
} }
@JvmName("putMetas") @JvmName("putMetas")
infix fun Name.put(value: Iterable<Meta>) { public infix fun Name.put(value: Iterable<Meta>) {
this@MetaBuilder[this] = value.toList() this@MetaBuilder[this] = value.toList()
} }
infix fun Name.put(metaBuilder: MetaBuilder.() -> Unit) { public infix fun Name.put(metaBuilder: MetaBuilder.() -> Unit) {
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder) this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
} }
} }
@ -125,7 +121,7 @@ class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
/** /**
* For safety, builder always copies the initial meta even if it is builder itself * For safety, builder always copies the initial meta even if it is builder itself
*/ */
fun Meta.builder(): MetaBuilder { public fun Meta.builder(): MetaBuilder {
return MetaBuilder().also { builder -> return MetaBuilder().also { builder ->
items.mapValues { entry -> items.mapValues { entry ->
val item = entry.value val item = entry.value
@ -140,16 +136,10 @@ fun Meta.builder(): MetaBuilder {
/** /**
* Create a deep copy of this meta and apply builder to it * Create a deep copy of this meta and apply builder to it
*/ */
fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder) public fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
/**
* Build a [MetaBuilder] using given transformation
*/
@Deprecated("To be replaced with fake constructor", ReplaceWith("Meta"))
fun buildMeta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
/** /**
* Build a [MetaBuilder] using given transformation * Build a [MetaBuilder] using given transformation
*/ */
@Suppress("FunctionName") @Suppress("FunctionName")
fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder) public fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)

View File

@ -1,6 +1,7 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.MapSerializer
@ -11,12 +12,13 @@ import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
/** /**
* Serialized for meta * Serialized for meta
*/ */
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Meta::class) @Serializer(Meta::class)
object MetaSerializer : KSerializer<Meta> { public object MetaSerializer : KSerializer<Meta> {
private val mapSerializer = MapSerializer( private val mapSerializer = MapSerializer(
NameToken.serializer(), NameToken.serializer(),
MetaItem.serializer(MetaSerializer) MetaItem.serializer(MetaSerializer)

View File

@ -15,7 +15,6 @@ import kotlin.reflect.KProperty
public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem<*>?> public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem<*>?>
public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = object : MutableItemDelegate { public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = object : MutableItemDelegate {
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? { override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
return getItem(key ?: property.name.asName()) return getItem(key ?: property.name.asName())
} }
@ -24,7 +23,6 @@ public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = ob
val name = key ?: property.name.asName() val name = key ?: property.name.asName()
setItem(name, value) setItem(name, value)
} }
//MutableItemDelegate(this, key)
} }
/* Mutable converters */ /* Mutable converters */
@ -111,7 +109,10 @@ public fun MutableItemProvider.boolean(key: Name? = null, default: () -> Boolean
public fun MutableItemProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> = public fun MutableItemProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> =
item(key).convert(MetaConverter.number, default) item(key).convert(MetaConverter.number, default)
public inline fun <reified E : Enum<E>> MutableItemProvider.enum(default: E, key: Name? = null): ReadWriteProperty<Any?, E> = public inline fun <reified E : Enum<E>> MutableItemProvider.enum(
default: E,
key: Name? = null,
): ReadWriteProperty<Any?, E> =
item(key).convert(MetaConverter.enum()) { default } item(key).convert(MetaConverter.enum()) { default }
public inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null): ReadWriteProperty<Any?, M?> = public inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null): ReadWriteProperty<Any?, M?> =
@ -155,14 +156,14 @@ public fun MutableItemProvider.float(default: Float, key: Name? = null): ReadWri
public fun MutableItemProvider.stringList( public fun MutableItemProvider.stringList(
vararg default: String, vararg default: String,
key: Name? = null key: Name? = null,
): ReadWriteProperty<Any?, List<String>> = item(key).convert( ): ReadWriteProperty<Any?, List<String>> = item(key).convert(
reader = { it?.stringList ?: listOf(*default) }, reader = { it?.stringList ?: listOf(*default) },
writer = { it.map { str -> str.asValue() }.asValue().asMetaItem() } writer = { it.map { str -> str.asValue() }.asValue().asMetaItem() }
) )
public fun MutableItemProvider.stringList( public fun MutableItemProvider.stringList(
key: Name? = null key: Name? = null,
): ReadWriteProperty<Any?, List<String>?> = item(key).convert( ): ReadWriteProperty<Any?, List<String>?> = item(key).convert(
reader = { it?.stringList }, reader = { it?.stringList },
writer = { it?.map { str -> str.asValue() }?.asValue()?.asMetaItem() } writer = { it?.map { str -> str.asValue() }?.asValue()?.asMetaItem() }
@ -170,7 +171,7 @@ public fun MutableItemProvider.stringList(
public fun MutableItemProvider.numberList( public fun MutableItemProvider.numberList(
vararg default: Number, vararg default: Number,
key: Name? = null key: Name? = null,
): ReadWriteProperty<Any?, List<Number>> = item(key).convert( ): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) }, reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) },
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() } writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
@ -181,7 +182,7 @@ public fun MutableItemProvider.numberList(
public fun MutableItemProvider.doubleArray( public fun MutableItemProvider.doubleArray(
vararg default: Double, vararg default: Double,
key: Name? = null key: Name? = null,
): ReadWriteProperty<Any?, DoubleArray> = item(key).convert( ): ReadWriteProperty<Any?, DoubleArray> = item(key).convert(
reader = { it?.value?.doubleArray ?: doubleArrayOf(*default) }, reader = { it?.value?.doubleArray ?: doubleArrayOf(*default) },
writer = { DoubleArrayValue(it).asMetaItem() } writer = { DoubleArrayValue(it).asMetaItem() }
@ -190,5 +191,5 @@ public fun MutableItemProvider.doubleArray(
public fun <T> MutableItemProvider.listValue( public fun <T> MutableItemProvider.listValue(
key: Name? = null, key: Name? = null,
writer: (T) -> Value = { Value.of(it) }, writer: (T) -> Value = { Value.of(it) },
reader: (Value) -> T reader: (Value) -> T,
): ReadWriteProperty<Any?, List<T>?> = item(key).convert(MetaConverter.valueList(writer, reader)) ): ReadWriteProperty<Any?, List<T>?> = item(key).convert(MetaConverter.valueList(writer, reader))

View File

@ -3,11 +3,11 @@ package hep.dataforge.meta
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.values.Value import hep.dataforge.values.Value
interface MutableItemProvider : ItemProvider { public interface MutableItemProvider : ItemProvider {
fun setItem(name: Name, item: MetaItem<*>?) public fun setItem(name: Name, item: MetaItem<*>?)
} }
interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider { public interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider {
override val items: Map<NameToken, MetaItem<M>> override val items: Map<NameToken, MetaItem<M>>
// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) // fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
// fun removeListener(owner: Any? = null) // fun removeListener(owner: Any? = null)
@ -18,7 +18,7 @@ interface MutableMeta<out M : MutableMeta<M>> : MetaNode<M>, MutableItemProvider
* *
* Changes in Meta are not thread safe. * Changes in Meta are not thread safe.
*/ */
abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> { public abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(), MutableMeta<M> {
protected val _items: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap() protected val _items: MutableMap<NameToken, MetaItem<M>> = LinkedHashMap()
override val items: Map<NameToken, MetaItem<M>> override val items: Map<NameToken, MetaItem<M>>
@ -74,28 +74,28 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun MutableMeta<*>.remove(name: Name) = setItem(name, null) public inline fun MutableMeta<*>.remove(name: Name): Unit = setItem(name, null)
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun MutableMeta<*>.remove(name: String) = remove(name.toName()) public inline fun MutableMeta<*>.remove(name: String): Unit = remove(name.toName())
operator fun MutableMeta<*>.set(name: Name, item: MetaItem<*>?) = setItem(name, item) public operator fun MutableMeta<*>.set(name: Name, item: MetaItem<*>?): Unit = setItem(name, item)
fun MutableMeta<*>.setValue(name: Name, value: Value) = setItem(name, MetaItem.ValueItem(value)) public fun MutableMeta<*>.setValue(name: Name, value: Value): Unit = setItem(name, MetaItem.ValueItem(value))
fun MutableMeta<*>.setValue(name: String, value: Value) = set(name.toName(), value) public fun MutableMeta<*>.setValue(name: String, value: Value): Unit = set(name.toName(), value)
fun MutableMeta<*>.setItem(name: String, item: MetaItem<*>?) = setItem(name.toName(), item) public fun MutableMeta<*>.setItem(name: String, item: MetaItem<*>?): Unit = setItem(name.toName(), item)
fun MutableMeta<*>.setNode(name: Name, node: Meta) = public fun MutableMeta<*>.setNode(name: Name, node: Meta): Unit =
setItem(name, MetaItem.NodeItem(node)) setItem(name, MetaItem.NodeItem(node))
fun MutableMeta<*>.setNode(name: String, node: Meta) = setNode(name.toName(), node) public fun MutableMeta<*>.setNode(name: String, node: Meta): Unit = setNode(name.toName(), node)
/** /**
* Universal unsafe set method * Universal unsafe set method
*/ */
operator fun MutableMeta<*>.set(name: Name, value: Any?) { public operator fun MutableMeta<*>.set(name: Name, value: Any?) {
when (value) { when (value) {
null -> remove(name) null -> remove(name)
is MetaItem<*> -> setItem(name, value) is MetaItem<*> -> setItem(name, value)
@ -105,11 +105,14 @@ operator fun MutableMeta<*>.set(name: Name, value: Any?) {
} }
} }
operator fun MutableMeta<*>.set(name: NameToken, value: Any?) = set(name.asName(), value) public operator fun MutableMeta<*>.set(name: NameToken, value: Any?): Unit =
set(name.asName(), value)
operator fun MutableMeta<*>.set(key: String, value: Any?) = set(key.toName(), value) public operator fun MutableMeta<*>.set(key: String, value: Any?): Unit =
set(key.toName(), value)
operator fun MutableMeta<*>.set(key: String, index: String, value: Any?) = set(key.toName().withIndex(index), value) public operator fun MutableMeta<*>.set(key: String, index: String, value: Any?): Unit =
set(key.toName().withIndex(index), value)
/** /**
* Update existing mutable node with another node. The rules are following: * Update existing mutable node with another node. The rules are following:
@ -117,7 +120,7 @@ operator fun MutableMeta<*>.set(key: String, index: String, value: Any?) = set(k
* * node updates node and replaces anything but node * * node updates node and replaces anything but node
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise * * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
*/ */
fun <M : MutableMeta<M>> M.update(meta: Meta) { public fun <M : MutableMeta<M>> M.update(meta: Meta) {
meta.items.forEach { entry -> meta.items.forEach { entry ->
when (val value = entry.value) { when (val value = entry.value) {
is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value) is MetaItem.ValueItem -> setValue(entry.key.asName(), value.value)
@ -129,7 +132,7 @@ fun <M : MutableMeta<M>> M.update(meta: Meta) {
/* Same name siblings generation */ /* Same name siblings generation */
fun MutableMeta<*>.setIndexedItems( public fun MutableMeta<*>.setIndexedItems(
name: Name, name: Name,
items: Iterable<MetaItem<*>>, items: Iterable<MetaItem<*>>,
indexFactory: (MetaItem<*>, index: Int) -> String = { _, index -> index.toString() } indexFactory: (MetaItem<*>, index: Int) -> String = { _, index -> index.toString() }
@ -143,7 +146,7 @@ fun MutableMeta<*>.setIndexedItems(
} }
} }
fun MutableMeta<*>.setIndexed( public fun MutableMeta<*>.setIndexed(
name: Name, name: Name,
metas: Iterable<Meta>, metas: Iterable<Meta>,
indexFactory: (Meta, index: Int) -> String = { _, index -> index.toString() } indexFactory: (Meta, index: Int) -> String = { _, index -> index.toString() }
@ -151,13 +154,13 @@ fun MutableMeta<*>.setIndexed(
setIndexedItems(name, metas.map { MetaItem.NodeItem(it) }) { item, index -> indexFactory(item.node!!, index) } setIndexedItems(name, metas.map { MetaItem.NodeItem(it) }) { item, index -> indexFactory(item.node!!, index) }
} }
operator fun MutableMeta<*>.set(name: Name, metas: Iterable<Meta>): Unit = setIndexed(name, metas) public operator fun MutableMeta<*>.set(name: Name, metas: Iterable<Meta>): Unit = setIndexed(name, metas)
operator fun MutableMeta<*>.set(name: String, metas: Iterable<Meta>): Unit = setIndexed(name.toName(), metas) public operator fun MutableMeta<*>.set(name: String, metas: Iterable<Meta>): Unit = setIndexed(name.toName(), metas)
/** /**
* Append the node with a same-name-sibling, automatically generating numerical index * Append the node with a same-name-sibling, automatically generating numerical index
*/ */
fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) { public fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
require(!name.isEmpty()) { "Name could not be empty for append operation" } require(!name.isEmpty()) { "Name could not be empty for append operation" }
val newIndex = name.lastOrNull()!!.index val newIndex = name.lastOrNull()!!.index
if (newIndex != null) { if (newIndex != null) {
@ -168,13 +171,13 @@ fun <M : MutableMeta<M>> M.append(name: Name, value: Any?) {
} }
} }
fun <M : MutableMeta<M>> M.append(name: String, value: Any?) = append(name.toName(), value) public fun <M : MutableMeta<M>> M.append(name: String, value: Any?): Unit = append(name.toName(), value)
/** /**
* Apply existing node with given [builder] or create a new element with it. * Apply existing node with given [builder] or create a new element with it.
*/ */
@DFExperimental @DFExperimental
fun <M : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) { public fun <M : AbstractMutableMeta<M>> M.edit(name: Name, builder: M.() -> Unit) {
val item = when (val existingItem = get(name)) { val item = when (val existingItem = get(name)) {
null -> empty().also { set(name, it) } null -> empty().also { set(name, it) }
is MetaItem.NodeItem<M> -> existingItem.node is MetaItem.NodeItem<M> -> existingItem.node

View File

@ -8,23 +8,21 @@ import hep.dataforge.names.plus
/** /**
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification]. * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification].
*/ */
open class Scheme() : Configurable, Described, MetaRepr { public open class Scheme(
constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() { config: Config,
this.config = config defaultProvider: ItemProvider,
this.defaultProvider = defaultProvider ) : Configurable, Described, MetaRepr {
}
//constructor(config: Config, default: Meta) : this(config, { default[it] }) override var config: Config = config
constructor(config: Config) : this(config, { null })
final override var config: Config = Config()
internal set internal set
var defaultProvider: (Name) -> MetaItem<*>? = { null } public var defaultProvider: ItemProvider = defaultProvider
internal set internal set
public constructor() : this(Config(), ItemProvider { null })
override fun getDefaultItem(name: Name): MetaItem<*>? { override fun getDefaultItem(name: Name): MetaItem<*>? {
return defaultProvider(name) ?: descriptor?.get(name)?.defaultItem() return defaultProvider.getItem(name) ?: descriptor?.get(name)?.defaultItem()
} }
/** /**
@ -32,7 +30,7 @@ open class Scheme() : Configurable, Described, MetaRepr {
* values if default value is unavailable. * values if default value is unavailable.
* Values from [defaultProvider] completely replace * Values from [defaultProvider] completely replace
*/ */
open val defaultLayer: Meta get() = DefaultLayer(Name.EMPTY) public open val defaultLayer: Meta get() = DefaultLayer(Name.EMPTY)
override fun toMeta(): Laminate = Laminate(config, defaultLayer) override fun toMeta(): Laminate = Laminate(config, defaultLayer)
@ -50,38 +48,45 @@ open class Scheme() : Configurable, Described, MetaRepr {
} }
} }
inline operator fun <T : Scheme> T.invoke(block: T.() -> Unit) = apply(block) /**
* A shortcut to edit a [Scheme] object in-place
*/
public inline operator fun <T : Scheme> T.invoke(block: T.() -> Unit): T = apply(block)
/** /**
* A specification for simplified generation of wrappers * A specification for simplified generation of wrappers
*/ */
open class SchemeSpec<T : Scheme>(val builder: () -> T) : public open class SchemeSpec<T : Scheme>(
Specification<T> { private val builder: (config: Config, defaultProvider: ItemProvider) -> T,
override fun empty(): T = builder() ) : Specification<T> {
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T { public constructor(emptyBuilder: () -> T) : this({ config: Config, defaultProvider: ItemProvider ->
return empty().apply { emptyBuilder().apply {
this.config = config this.config = config
this.defaultProvider = defaultProvider this.defaultProvider = defaultProvider
} }
} })
override fun empty(): T = builder(Config(), ItemProvider.EMPTY)
override fun wrap(config: Config, defaultProvider: ItemProvider): T = builder(config, defaultProvider)
@Suppress("OVERRIDE_BY_INLINE") @Suppress("OVERRIDE_BY_INLINE")
final override inline operator fun invoke(action: T.() -> Unit) = empty().apply(action) final override inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
} }
/** /**
* A scheme that uses [Meta] as a default layer * A scheme that uses [Meta] as a default layer
*/ */
open class MetaScheme( public open class MetaScheme(
val meta: Meta, private val meta: Meta,
override val descriptor: NodeDescriptor? = null, override val descriptor: NodeDescriptor? = null,
config: Config = Config() config: Config = Config(),
) : Scheme(config, meta::get) { ) : Scheme(config, meta::get) {
override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node) override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
} }
fun Meta.asScheme() = public fun Meta.asScheme(): MetaScheme = MetaScheme(this)
MetaScheme(this)
fun <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit) = spec.wrap(this).apply(block) public fun <T : Configurable> Meta.toScheme(spec: Specification<T>, block: T.() -> Unit): T =
spec.wrap(this).apply(block)

View File

@ -1,6 +1,5 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.Name
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
/** /**
@ -8,32 +7,32 @@ import kotlin.jvm.JvmName
* By convention [Scheme] companion should inherit this class * By convention [Scheme] companion should inherit this class
* *
*/ */
interface Specification<T : Configurable> { public interface Specification<T : Configurable> {
fun empty() = wrap() public fun empty(): T = wrap()
/** /**
* Wrap generic configuration producing instance of desired type * Wrap generic configuration producing instance of desired type
*/ */
fun wrap(config: Config = Config(), defaultProvider: (Name) -> MetaItem<*>? = { null }): T public fun wrap(config: Config = Config(), defaultProvider: ItemProvider = ItemProvider{ null }): T
operator fun invoke(action: T.() -> Unit): T = empty().apply(action) public operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
} }
/** /**
* Update given configuration using given type as a builder * Update given configuration using given type as a builder
*/ */
fun <T : Configurable> Specification<T>.update(config: Config, action: T.() -> Unit): T = wrap(config).apply(action) public fun <T : Configurable> Specification<T>.update(config: Config, action: T.() -> Unit): T = wrap(config).apply(action)
/** /**
* Wrap a configuration using static meta as default * Wrap a configuration using static meta as default
*/ */
fun <T : Configurable> Specification<T>.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T = public fun <T : Configurable> Specification<T>.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T =
wrap(config) { default[it] } wrap(config, default)
/** /**
* Wrap a configuration using static meta as default * Wrap a configuration using static meta as default
*/ */
fun <T : Configurable> Specification<T>.wrap(source: Meta): T { public fun <T : Configurable> Specification<T>.wrap(source: Meta): T {
val default = source.seal() val default = source.seal()
return wrap(source.asConfig(), default) return wrap(source.asConfig(), default)
} }
@ -42,26 +41,26 @@ fun <T : Configurable> Specification<T>.wrap(source: Meta): T {
/** /**
* Apply specified configuration to configurable * Apply specified configuration to configurable
*/ */
fun <T : Configurable, C : Configurable, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit) = public fun <T : Configurable, C : Configurable, S : Specification<C>> T.configure(spec: S, action: C.() -> Unit): T =
apply { spec.update(config, action) } apply { spec.update(config, action) }
/** /**
* Update configuration using given specification * Update configuration using given specification
*/ */
fun <C : Configurable, S : Specification<C>> Configurable.update(spec: S, action: C.() -> Unit) = public fun <C : Configurable, S : Specification<C>> Configurable.update(spec: S, action: C.() -> Unit): Configurable =
apply { spec.update(config, action) } apply { spec.update(config, action) }
/** /**
* Create a style based on given specification * Create a style based on given specification
*/ */
fun <C : Configurable, S : Specification<C>> S.createStyle(action: C.() -> Unit): Meta = public fun <C : Configurable, S : Specification<C>> S.createStyle(action: C.() -> Unit): Meta =
Config().also { update(it, action) } Config().also { update(it, action) }
fun <T : Configurable> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let { public fun <T : Configurable> MetaItem<*>.spec(spec: Specification<T>): T? = node?.let {
spec.wrap( spec.wrap(
Config(), it Config(), it
) )
} }
@JvmName("configSpec") @JvmName("configSpec")
fun <T : Configurable> MetaItem<Config>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(it) } public fun <T : Configurable> MetaItem<Config>.spec(spec: Specification<T>): T? = node?.let { spec.wrap(it) }

View File

@ -4,8 +4,8 @@ package hep.dataforge.meta
* General marker for dataforge builders * General marker for dataforge builders
*/ */
@DslMarker @DslMarker
annotation class DFBuilder public annotation class DFBuilder
@RequiresOptIn(level = RequiresOptIn.Level.WARNING) @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
annotation class DFExperimental public annotation class DFExperimental

View File

@ -6,7 +6,7 @@ import hep.dataforge.names.*
* Get all items matching given name. The index of the last element, if present is used as a [Regex], * Get all items matching given name. The index of the last element, if present is used as a [Regex],
* against which indexes of elements are matched. * against which indexes of elements are matched.
*/ */
fun Meta.getIndexed(name: Name): Map<String?, MetaItem<*>> { public fun Meta.getIndexed(name: Name): Map<String?, MetaItem<*>> {
val root = when (name.length) { val root = when (name.length) {
0 -> error("Can't use empty name for 'getIndexed'") 0 -> error("Can't use empty name for 'getIndexed'")
1 -> this 1 -> this
@ -18,19 +18,19 @@ fun Meta.getIndexed(name: Name): Map<String?, MetaItem<*>> {
root.items.filter { it.key.body == body }.mapKeys { it.key.index } root.items.filter { it.key.body == body }.mapKeys { it.key.index }
} else { } else {
val regex = index.toRegex() val regex = index.toRegex()
root.items root.items.filter { it.key.body == body && (regex.matches(it.key.index ?: "")) }
.filter { it.key.body == body && (regex.matches(it.key.index ?: "")) }
.mapKeys { it.key.index } .mapKeys { it.key.index }
} }
} }
fun Meta.getIndexed(name: String): Map<String?, MetaItem<*>> = this@getIndexed.getIndexed(name.toName()) public fun Meta.getIndexed(name: String): Map<String?, MetaItem<*>> = this@getIndexed.getIndexed(name.toName())
/** /**
* Get all items matching given name. * Get all items matching given name.
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> = public fun <M : MetaNode<M>> M.getIndexed(name: Name): Map<String, MetaItem<M>> =
(this as Meta).getIndexed(name) as Map<String, MetaItem<M>> (this as Meta).getIndexed(name) as Map<String, MetaItem<M>>
fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> = getIndexed(name.toName()) public fun <M : MetaNode<M>> M.getIndexed(name: String): Map<String, MetaItem<M>> =
getIndexed(name.toName())

View File

@ -8,7 +8,7 @@ import hep.dataforge.values.Value
/** /**
* Convert meta to map of maps * Convert meta to map of maps
*/ */
fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> { public fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
return items.entries.associate { (token, item) -> return items.entries.associate { (token, item) ->
token.toString() to when (item) { token.toString() to when (item) {
is MetaItem.NodeItem -> item.node.toMap() is MetaItem.NodeItem -> item.node.toMap()
@ -22,7 +22,7 @@ fun Meta.toMap(descriptor: NodeDescriptor? = null): Map<String, Any?> {
* All other values will be converted to values. * All other values will be converted to values.
*/ */
@DFExperimental @DFExperimental
fun Map<String, Any?>.toMeta(descriptor: NodeDescriptor? = null): Meta = Meta { public fun Map<String, Any?>.toMeta(descriptor: NodeDescriptor? = null): Meta = Meta {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun toItem(value: Any?): MetaItem<*> = when (value) { fun toItem(value: Any?): MetaItem<*> = when (value) {
is MetaItem<*> -> value is MetaItem<*> -> value

View File

@ -1,76 +0,0 @@
package hep.dataforge.meta
import kotlinx.serialization.InternalSerializationApi
import kotlinx.serialization.builtins.DoubleArraySerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.Json
fun ClassSerialDescriptorBuilder.boolean(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, Boolean.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.string(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, String.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.int(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, Int.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.double(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, Double.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.float(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, Float.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.long(name: String, isOptional: Boolean = false, vararg annotations: Annotation) =
element(name, Long.serializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
fun ClassSerialDescriptorBuilder.doubleArray(
name: String,
isOptional: Boolean = false,
vararg annotations: Annotation,
) =
element(name, DoubleArraySerializer().descriptor, isOptional = isOptional, annotations = annotations.toList())
@OptIn(InternalSerializationApi::class)
inline fun <reified E : Enum<E>> ClassSerialDescriptorBuilder.enum(
name: String,
isOptional: Boolean = false,
vararg annotations: Annotation,
) {
val enumDescriptor = buildSerialDescriptor(serialName, SerialKind.ENUM) {
enumValues<E>().forEach {
val fqn = "$serialName.${it.name}"
val enumMemberDescriptor = buildSerialDescriptor(fqn, StructureKind.OBJECT)
element(it.name, enumMemberDescriptor)
}
}
element(name, enumDescriptor, isOptional = isOptional, annotations = annotations.toList())
}
@DFExperimental
inline fun <R> Decoder.decodeStructure(
desc: SerialDescriptor,
crossinline block: CompositeDecoder.() -> R,
): R {
val decoder = beginStructure(desc)
val res = decoder.block()
decoder.endStructure(desc)
return res
}
@DFExperimental
inline fun Encoder.encodeStructure(
desc: SerialDescriptor,
block: CompositeEncoder.() -> Unit,
) {
val encoder = beginStructure(desc)
encoder.block()
encoder.endStructure(desc)
}
val JSON_PRETTY = Json { prettyPrint = true; useArrayPolymorphism = true }
val JSON_PLAIN = Json { prettyPrint = false; useArrayPolymorphism = true }

View File

@ -10,7 +10,7 @@ import kotlinx.serialization.Serializable
* *
*/ */
@Serializable @Serializable
enum class ValueType { public enum class ValueType {
NUMBER, STRING, BOOLEAN, NULL NUMBER, STRING, BOOLEAN, NULL
} }
@ -19,44 +19,44 @@ enum class ValueType {
* *
* Value can represent a list of value objects. * Value can represent a list of value objects.
*/ */
interface Value { @Serializable(ValueSerializer::class)
public interface Value {
/** /**
* Get raw value of this value * Get raw value of this value
*/ */
val value: Any? public val value: Any?
/** /**
* The type of the value * The type of the value
*/ */
val type: ValueType public val type: ValueType
/** /**
* get this value represented as Number * get this value represented as Number
*/ */
val number: Number public val number: Number
/** /**
* get this value represented as String * get this value represented as String
*/ */
val string: String public val string: String
/** /**
* get this value represented as List * get this value represented as List
*/ */
val list: List<Value> public val list: List<Value> get() = if (this == Null) emptyList() else listOf(this)
get() = if (this == Null) emptyList() else listOf(this)
override fun equals(other: Any?): Boolean override fun equals(other: Any?): Boolean
override fun hashCode(): Int override fun hashCode(): Int
companion object { public companion object {
const val TYPE = "value" public const val TYPE: String = "value"
/** /**
* Convert object to value * Convert object to value
*/ */
fun of(value: Any?): Value { public fun of(value: Any?): Value {
return when (value) { return when (value) {
null -> Null null -> Null
is Value -> value is Value -> value
@ -89,7 +89,7 @@ interface Value {
/** /**
* A singleton null value * A singleton null value
*/ */
object Null : Value { public object Null : Value {
override val value: Any? get() = null override val value: Any? get() = null
override val type: ValueType get() = ValueType.NULL override val type: ValueType get() = ValueType.NULL
override val number: Number get() = Double.NaN override val number: Number get() = Double.NaN
@ -104,7 +104,7 @@ object Null : Value {
/** /**
* Singleton true value * Singleton true value
*/ */
object True : Value { public object True : Value {
override val value: Any? get() = true override val value: Any? get() = true
override val type: ValueType get() = ValueType.BOOLEAN override val type: ValueType get() = ValueType.BOOLEAN
override val number: Number get() = 1.0 override val number: Number get() = 1.0
@ -119,7 +119,7 @@ object True : Value {
/** /**
* Singleton false value * Singleton false value
*/ */
object False : Value { public object False : Value {
override val value: Any? get() = false override val value: Any? get() = false
override val type: ValueType get() = ValueType.BOOLEAN override val type: ValueType get() = ValueType.BOOLEAN
override val number: Number get() = -1.0 override val number: Number get() = -1.0
@ -131,7 +131,7 @@ object False : Value {
override fun hashCode(): Int = -1 override fun hashCode(): Int = -1
} }
class NumberValue(override val number: Number) : Value { public class NumberValue(override val number: Number) : Value {
override val value: Any? get() = number override val value: Any? get() = number
override val type: ValueType get() = ValueType.NUMBER override val type: ValueType get() = ValueType.NUMBER
override val string: String get() = number.toString() override val string: String get() = number.toString()
@ -154,7 +154,7 @@ class NumberValue(override val number: Number) : Value {
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
} }
class StringValue(override val string: String) : Value { public class StringValue(override val string: String) : Value {
override val value: Any? get() = string override val value: Any? get() = string
override val type: ValueType get() = ValueType.STRING override val type: ValueType get() = ValueType.STRING
override val number: Number get() = string.toDouble() override val number: Number get() = string.toDouble()
@ -168,7 +168,7 @@ class StringValue(override val string: String) : Value {
override fun toString(): String = "\"${value.toString()}\"" override fun toString(): String = "\"${value.toString()}\""
} }
class EnumValue<E : Enum<*>>(override val value: E) : Value { public class EnumValue<E : Enum<*>>(override val value: E) : Value {
override val type: ValueType get() = ValueType.STRING override val type: ValueType get() = ValueType.STRING
override val number: Number get() = value.ordinal override val number: Number get() = value.ordinal
override val string: String get() = value.name override val string: String get() = value.name
@ -182,7 +182,7 @@ class EnumValue<E : Enum<*>>(override val value: E) : Value {
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
} }
class ListValue(override val list: List<Value>) : Value { public class ListValue(override val list: List<Value>) : Value {
init { init {
require(list.isNotEmpty()) { "Can't create list value from empty list" } require(list.isNotEmpty()) { "Can't create list value from empty list" }
} }
@ -210,34 +210,34 @@ class ListValue(override val list: List<Value>) : Value {
} }
fun Number.asValue(): Value = NumberValue(this) public fun Number.asValue(): Value = NumberValue(this)
fun Boolean.asValue(): Value = if (this) True else False public fun Boolean.asValue(): Value = if (this) True else False
fun String.asValue(): Value = StringValue(this) public fun String.asValue(): Value = StringValue(this)
fun Iterable<Value>.asValue(): Value { public fun Iterable<Value>.asValue(): Value {
val list = toList() val list = toList()
return if (list.isEmpty()) Null else ListValue(this.toList()) return if (list.isEmpty()) Null else ListValue(this.toList())
} }
fun IntArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun IntArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
fun LongArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun LongArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
fun ShortArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun ShortArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
fun ByteArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) public fun ByteArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
fun <E : Enum<E>> E.asValue(): Value = EnumValue(this) public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this)
/** /**
* Create Value from String using closest match conversion * Create Value from String using closest match conversion
*/ */
fun String.parseValue(): Value { public fun String.parseValue(): Value {
//Trying to get integer //Trying to get integer
if (isEmpty() || this == Null.string) { if (isEmpty() || this == Null.string) {

View File

@ -1,25 +1,25 @@
package hep.dataforge.values package hep.dataforge.values
import hep.dataforge.meta.boolean import kotlinx.serialization.ExperimentalSerializationApi
import hep.dataforge.meta.enum
import hep.dataforge.meta.string
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Value::class) @Serializer(Value::class)
object ValueSerializer : KSerializer<Value> { public object ValueSerializer : KSerializer<Value> {
private val listSerializer by lazy { ListSerializer(ValueSerializer) } private val listSerializer by lazy { ListSerializer(ValueSerializer) }
override val descriptor: SerialDescriptor = override val descriptor: SerialDescriptor =
buildClassSerialDescriptor("hep.dataforge.values.Value") { buildClassSerialDescriptor("hep.dataforge.values.Value") {
boolean("isList") element<Boolean>("isList")
enum<ValueType>("valueType") element<ValueType>("valueType")
string("value") element<String>("value")
} }
private fun Decoder.decodeValue(): Value { private fun Decoder.decodeValue(): Value {

View File

@ -4,7 +4,7 @@ package hep.dataforge.values
/** /**
* A value built from string which content and type are parsed on-demand * A value built from string which content and type are parsed on-demand
*/ */
class LazyParsedValue(override val string: String) : Value { public class LazyParsedValue(override val string: String) : Value {
private val parsedValue by lazy { string.parseValue() } private val parsedValue by lazy { string.parseValue() }
override val value: Any? get() = parsedValue.value override val value: Any? get() = parsedValue.value
@ -18,12 +18,12 @@ class LazyParsedValue(override val string: String) : Value {
override fun hashCode(): Int = string.hashCode() override fun hashCode(): Int = string.hashCode()
} }
fun String.lazyParseValue(): LazyParsedValue = LazyParsedValue(this) public fun String.lazyParseValue(): LazyParsedValue = LazyParsedValue(this)
/** /**
* A performance optimized version of list value for doubles * A performance optimized version of list value for doubles
*/ */
class DoubleArrayValue(override val value: DoubleArray) : Value { public class DoubleArrayValue(override val value: DoubleArray) : Value {
override val type: ValueType get() = ValueType.NUMBER override val type: ValueType get() = ValueType.NUMBER
override val number: Double get() = value.first() override val number: Double get() = value.first()
override val string: String get() = value.first().toString() override val string: String get() = value.first().toString()
@ -46,4 +46,4 @@ class DoubleArrayValue(override val value: DoubleArray) : Value {
override fun toString(): String = list.joinToString (prefix = "[", postfix = "]") override fun toString(): String = list.joinToString (prefix = "[", postfix = "]")
} }
fun DoubleArray.asValue(): Value = if(isEmpty()) Null else DoubleArrayValue(this) public fun DoubleArray.asValue(): Value = if(isEmpty()) Null else DoubleArrayValue(this)

View File

@ -1,32 +1,33 @@
package hep.dataforge.values package hep.dataforge.values
import hep.dataforge.meta.Meta import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
/** /**
* Check if value is null * Check if value is null
*/ */
fun Value.isNull(): Boolean = this == Null public fun Value.isNull(): Boolean = this == Null
/** /**
* Check if value is list * Check if value is list
*/ */
fun Value.isList(): Boolean = this.list.size > 1 public fun Value.isList(): Boolean = this.list.size > 1
val Value.boolean public val Value.boolean
get() = this == True get() = this == True
|| this.list.firstOrNull() == True || this.list.firstOrNull() == True
|| (type == ValueType.STRING && string.toBoolean()) || (type == ValueType.STRING && string.toBoolean())
val Value.int get() = number.toInt() public val Value.int: Int get() = number.toInt()
val Value.double get() = number.toDouble() public val Value.double: Double get() = number.toDouble()
val Value.float get() = number.toFloat() public val Value.float: Float get() = number.toFloat()
val Value.short get() = number.toShort() public val Value.short: Short get() = number.toShort()
val Value.long get() = number.toLong() public val Value.long: Long get() = number.toLong()
val Value.stringList: List<String> get() = list.map { it.string } public val Value.stringList: List<String> get() = list.map { it.string }
val Value.doubleArray: DoubleArray public val Value.doubleArray: DoubleArray
get() = if (this is DoubleArrayValue) { get() = if (this is DoubleArrayValue) {
value value
} else { } else {
@ -34,4 +35,4 @@ val Value.doubleArray: DoubleArray
} }
fun Value.toMeta() = Meta { Meta.VALUE_KEY put this } public fun Value.toMeta(): MetaBuilder = Meta { Meta.VALUE_KEY put this }

View File

@ -1,18 +1,17 @@
package hep.dataforge.meta package hep.dataforge.meta
import hep.dataforge.names.Name
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
class SpecificationTest { class SpecificationTest {
class TestStyled(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : class TestStyled(config: Config, defaultProvider: ItemProvider) :
Scheme(config, defaultProvider) { Scheme(config, defaultProvider) {
var list by numberList(1, 2, 3) var list by numberList(1, 2, 3)
companion object : Specification<TestStyled> { companion object : Specification<TestStyled> {
override fun wrap( override fun wrap(
config: Config, config: Config,
defaultProvider: (Name) -> MetaItem<*>? defaultProvider: ItemProvider
): TestStyled = TestStyled(config, defaultProvider) ): TestStyled = TestStyled(config, defaultProvider)
} }
} }

View File

@ -0,0 +1,6 @@
package hep.dataforge.meta
import kotlinx.serialization.json.Json
public val JSON_PRETTY: Json = Json { prettyPrint = true; useArrayPolymorphism = true }
public val JSON_PLAIN: Json = Json { prettyPrint = false; useArrayPolymorphism = true }