dataforge-meta cleanup
This commit is contained in:
parent
87af89b47d
commit
52a3c8bc6f
@ -2,7 +2,6 @@ package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
|
@ -2,7 +2,6 @@ package hep.dataforge.context
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaRepr
|
||||
import hep.dataforge.meta.buildMeta
|
||||
|
||||
/**
|
||||
* The tag which contains information about name, group and version of some
|
||||
@ -10,7 +9,7 @@ import hep.dataforge.meta.buildMeta
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
data class PluginTag(
|
||||
public data class PluginTag(
|
||||
val name: String,
|
||||
val group: String = "",
|
||||
val version: String = ""
|
||||
@ -22,7 +21,7 @@ data class PluginTag(
|
||||
* @param otherTag
|
||||
* @return
|
||||
*/
|
||||
fun matches(otherTag: PluginTag): Boolean {
|
||||
public fun matches(otherTag: PluginTag): Boolean {
|
||||
return matchesName(otherTag) && matchesGroup(otherTag)
|
||||
}
|
||||
|
||||
@ -42,9 +41,9 @@ data class PluginTag(
|
||||
"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
|
||||
@ -52,7 +51,7 @@ data class PluginTag(
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
fun fromString(tag: String): PluginTag {
|
||||
public fun fromString(tag: String): PluginTag {
|
||||
val sepIndex = tag.indexOf(":")
|
||||
return if (sepIndex >= 0) {
|
||||
PluginTag(group = tag.substring(0, sepIndex), name = tag.substring(sepIndex + 1))
|
||||
|
@ -3,7 +3,6 @@ package hep.dataforge.data
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.isSuperclassOf
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 =
|
||||
this.type.isSubclassOf(type)
|
||||
|
@ -12,6 +12,7 @@ import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
|
||||
/**
|
||||
@ -86,7 +87,7 @@ public sealed class MetaItem<out M : Meta> {
|
||||
}
|
||||
|
||||
public fun Value.asMetaItem(): ValueItem = ValueItem(this)
|
||||
public fun <M:Meta> M.asMetaItem(): NodeItem<M> = NodeItem(this)
|
||||
public fun <M : Meta> M.asMetaItem(): NodeItem<M> = NodeItem(this)
|
||||
|
||||
/**
|
||||
* The object that could be represented as [Meta]. Meta provided by [toMeta] method should fully represent object state.
|
||||
@ -96,8 +97,12 @@ public interface MetaRepr {
|
||||
public fun toMeta(): Meta
|
||||
}
|
||||
|
||||
public interface ItemProvider{
|
||||
public fun interface ItemProvider {
|
||||
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
|
||||
*/
|
||||
@Serializable(MetaSerializer::class)
|
||||
public interface Meta : MetaRepr, ItemProvider {
|
||||
/**
|
||||
* Top level items of meta tree
|
||||
@ -140,7 +146,7 @@ public interface Meta : MetaRepr, ItemProvider {
|
||||
*/
|
||||
public const val VALUE_KEY: String = "@value"
|
||||
|
||||
public val EMPTY: Meta = object: MetaBase() {
|
||||
public val EMPTY: Meta = object : MetaBase() {
|
||||
override val items: Map<NameToken, MetaItem<*>> = emptyMap()
|
||||
}
|
||||
}
|
||||
@ -202,7 +208,7 @@ public interface MetaNode<out M : MetaNode<M>> : Meta {
|
||||
/**
|
||||
* The same as [Meta.get], but with specific node type
|
||||
*/
|
||||
public operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) {
|
||||
public operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if (this == null) {
|
||||
null
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
|
||||
@ -226,7 +232,10 @@ public abstract class MetaBase : Meta {
|
||||
|
||||
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
|
||||
*/
|
||||
public class SealedMeta internal constructor(
|
||||
override val items: Map<NameToken, MetaItem<SealedMeta>>
|
||||
override val items: Map<NameToken, MetaItem<SealedMeta>>,
|
||||
) : AbstractMetaNode<SealedMeta>()
|
||||
|
||||
/**
|
||||
|
@ -11,113 +11,109 @@ import kotlin.jvm.JvmName
|
||||
* DSL builder for meta. Is not intended to store mutable state
|
||||
*/
|
||||
@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 empty(): MetaBuilder = MetaBuilder()
|
||||
|
||||
infix fun String.put(item: MetaItem<*>?) {
|
||||
public infix fun String.put(item: MetaItem<*>?) {
|
||||
set(this, item)
|
||||
}
|
||||
|
||||
infix fun String.put(value: Value?) {
|
||||
public infix fun String.put(value: Value?) {
|
||||
set(this, value)
|
||||
}
|
||||
|
||||
infix fun String.put(string: String?) {
|
||||
public infix fun String.put(string: String?) {
|
||||
set(this, string?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(number: Number?) {
|
||||
public infix fun String.put(number: Number?) {
|
||||
set(this, number?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(boolean: Boolean?) {
|
||||
public infix fun String.put(boolean: Boolean?) {
|
||||
set(this, boolean?.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(enum: Enum<*>) {
|
||||
public infix fun String.put(enum: Enum<*>) {
|
||||
set(this, EnumValue(enum))
|
||||
}
|
||||
|
||||
@JvmName("putValues")
|
||||
infix fun String.put(iterable: Iterable<Value>) {
|
||||
public infix fun String.put(iterable: Iterable<Value>) {
|
||||
set(this, iterable.asValue())
|
||||
}
|
||||
|
||||
@JvmName("putNumbers")
|
||||
infix fun String.put(iterable: Iterable<Number>) {
|
||||
public infix fun String.put(iterable: Iterable<Number>) {
|
||||
set(this, iterable.map { it.asValue() }.asValue())
|
||||
}
|
||||
|
||||
@JvmName("putStrings")
|
||||
infix fun String.put(iterable: Iterable<String>) {
|
||||
public infix fun String.put(iterable: Iterable<String>) {
|
||||
set(this, iterable.map { it.asValue() }.asValue())
|
||||
}
|
||||
|
||||
infix fun String.put(array: DoubleArray) {
|
||||
public infix fun String.put(array: DoubleArray) {
|
||||
set(this, array.asValue())
|
||||
}
|
||||
|
||||
infix fun String.putValue(any: Any?) {
|
||||
set(this, Value.of(any))
|
||||
}
|
||||
|
||||
infix fun String.put(meta: Meta?) {
|
||||
public infix fun String.put(meta: Meta?) {
|
||||
this@MetaBuilder[this] = meta
|
||||
}
|
||||
|
||||
infix fun String.put(repr: MetaRepr?) {
|
||||
public infix fun String.put(repr: MetaRepr?) {
|
||||
set(this, repr?.toMeta())
|
||||
}
|
||||
|
||||
@JvmName("putMetas")
|
||||
infix fun String.put(value: Iterable<Meta>) {
|
||||
public infix fun String.put(value: Iterable<Meta>) {
|
||||
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)
|
||||
}
|
||||
|
||||
infix fun Name.put(value: Value?) {
|
||||
public infix fun Name.put(value: Value?) {
|
||||
set(this, value)
|
||||
}
|
||||
|
||||
infix fun Name.put(string: String?) {
|
||||
public infix fun Name.put(string: String?) {
|
||||
set(this, string?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(number: Number?) {
|
||||
public infix fun Name.put(number: Number?) {
|
||||
set(this, number?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(boolean: Boolean?) {
|
||||
public infix fun Name.put(boolean: Boolean?) {
|
||||
set(this, boolean?.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(enum: Enum<*>) {
|
||||
public infix fun Name.put(enum: Enum<*>) {
|
||||
set(this, EnumValue(enum))
|
||||
}
|
||||
|
||||
@JvmName("putValues")
|
||||
infix fun Name.put(iterable: Iterable<Value>) {
|
||||
public infix fun Name.put(iterable: Iterable<Value>) {
|
||||
set(this, iterable.asValue())
|
||||
}
|
||||
|
||||
infix fun Name.put(meta: Meta?) {
|
||||
public infix fun Name.put(meta: Meta?) {
|
||||
this@MetaBuilder[this] = meta
|
||||
}
|
||||
|
||||
infix fun Name.put(repr: MetaRepr?) {
|
||||
public infix fun Name.put(repr: MetaRepr?) {
|
||||
set(this, repr?.toMeta())
|
||||
}
|
||||
|
||||
@JvmName("putMetas")
|
||||
infix fun Name.put(value: Iterable<Meta>) {
|
||||
public infix fun Name.put(value: Iterable<Meta>) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -125,7 +121,7 @@ class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
|
||||
/**
|
||||
* 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 ->
|
||||
items.mapValues { entry ->
|
||||
val item = entry.value
|
||||
@ -140,16 +136,10 @@ fun Meta.builder(): MetaBuilder {
|
||||
/**
|
||||
* Create a deep copy of this meta and apply builder to it
|
||||
*/
|
||||
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)
|
||||
public fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
|
||||
|
||||
/**
|
||||
* Build a [MetaBuilder] using given transformation
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
||||
public fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
|
@ -1,6 +1,7 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.NameToken
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.builtins.MapSerializer
|
||||
@ -11,12 +12,13 @@ import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonEncoder
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
|
||||
|
||||
/**
|
||||
* Serialized for meta
|
||||
*/
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Serializer(Meta::class)
|
||||
object MetaSerializer : KSerializer<Meta> {
|
||||
public object MetaSerializer : KSerializer<Meta> {
|
||||
|
||||
private val mapSerializer = MapSerializer(
|
||||
NameToken.serializer(),
|
||||
MetaItem.serializer(MetaSerializer)
|
||||
|
@ -14,8 +14,7 @@ import kotlin.reflect.KProperty
|
||||
|
||||
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<*>? {
|
||||
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()
|
||||
setItem(name, value)
|
||||
}
|
||||
//MutableItemDelegate(this, key)
|
||||
}
|
||||
|
||||
/* 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> =
|
||||
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 }
|
||||
|
||||
public inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null): ReadWriteProperty<Any?, M?> =
|
||||
@ -155,22 +156,22 @@ public fun MutableItemProvider.float(default: Float, key: Name? = null): ReadWri
|
||||
|
||||
public fun MutableItemProvider.stringList(
|
||||
vararg default: String,
|
||||
key: Name? = null
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<String>> = item(key).convert(
|
||||
reader = { it?.stringList ?: listOf(*default) },
|
||||
writer = { it.map { str -> str.asValue() }.asValue().asMetaItem() }
|
||||
)
|
||||
|
||||
public fun MutableItemProvider.stringList(
|
||||
key: Name? = null
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<String>?> = item(key).convert(
|
||||
reader = { it?.stringList },
|
||||
reader = { it?.stringList },
|
||||
writer = { it?.map { str -> str.asValue() }?.asValue()?.asMetaItem() }
|
||||
)
|
||||
|
||||
public fun MutableItemProvider.numberList(
|
||||
vararg default: Number,
|
||||
key: Name? = null
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
|
||||
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) },
|
||||
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
|
||||
@ -181,8 +182,8 @@ public fun MutableItemProvider.numberList(
|
||||
|
||||
public fun MutableItemProvider.doubleArray(
|
||||
vararg default: Double,
|
||||
key: Name? = null
|
||||
): ReadWriteProperty<Any?, DoubleArray> =item(key).convert(
|
||||
key: Name? = null,
|
||||
): ReadWriteProperty<Any?, DoubleArray> = item(key).convert(
|
||||
reader = { it?.value?.doubleArray ?: doubleArrayOf(*default) },
|
||||
writer = { DoubleArrayValue(it).asMetaItem() }
|
||||
)
|
||||
@ -190,5 +191,5 @@ public fun MutableItemProvider.doubleArray(
|
||||
public fun <T> MutableItemProvider.listValue(
|
||||
key: Name? = null,
|
||||
writer: (T) -> Value = { Value.of(it) },
|
||||
reader: (Value) -> T
|
||||
reader: (Value) -> T,
|
||||
): ReadWriteProperty<Any?, List<T>?> = item(key).convert(MetaConverter.valueList(writer, reader))
|
||||
|
@ -3,11 +3,11 @@ package hep.dataforge.meta
|
||||
import hep.dataforge.names.*
|
||||
import hep.dataforge.values.Value
|
||||
|
||||
interface MutableItemProvider : ItemProvider {
|
||||
fun setItem(name: Name, item: MetaItem<*>?)
|
||||
public interface MutableItemProvider : ItemProvider {
|
||||
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>>
|
||||
// fun onChange(owner: Any? = null, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit)
|
||||
// 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.
|
||||
*/
|
||||
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()
|
||||
|
||||
override val items: Map<NameToken, MetaItem<M>>
|
||||
@ -74,28 +74,28 @@ abstract class AbstractMutableMeta<M : MutableMeta<M>> : AbstractMetaNode<M>(),
|
||||
|
||||
|
||||
@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")
|
||||
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))
|
||||
|
||||
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
|
||||
*/
|
||||
operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
||||
public operator fun MutableMeta<*>.set(name: Name, value: Any?) {
|
||||
when (value) {
|
||||
null -> remove(name)
|
||||
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:
|
||||
@ -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 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 ->
|
||||
when (val value = entry.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 */
|
||||
|
||||
fun MutableMeta<*>.setIndexedItems(
|
||||
public fun MutableMeta<*>.setIndexedItems(
|
||||
name: Name,
|
||||
items: Iterable<MetaItem<*>>,
|
||||
indexFactory: (MetaItem<*>, index: Int) -> String = { _, index -> index.toString() }
|
||||
@ -143,7 +146,7 @@ fun MutableMeta<*>.setIndexedItems(
|
||||
}
|
||||
}
|
||||
|
||||
fun MutableMeta<*>.setIndexed(
|
||||
public fun MutableMeta<*>.setIndexed(
|
||||
name: Name,
|
||||
metas: Iterable<Meta>,
|
||||
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) }
|
||||
}
|
||||
|
||||
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: Name, metas: Iterable<Meta>): Unit = setIndexed(name, 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
|
||||
*/
|
||||
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" }
|
||||
val newIndex = name.lastOrNull()!!.index
|
||||
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.
|
||||
*/
|
||||
@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)) {
|
||||
null -> empty().also { set(name, it) }
|
||||
is MetaItem.NodeItem<M> -> existingItem.node
|
||||
|
@ -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].
|
||||
*/
|
||||
open class Scheme() : Configurable, Described, MetaRepr {
|
||||
constructor(config: Config, defaultProvider: (Name) -> MetaItem<*>?) : this() {
|
||||
this.config = config
|
||||
this.defaultProvider = defaultProvider
|
||||
}
|
||||
public open class Scheme(
|
||||
config: Config,
|
||||
defaultProvider: ItemProvider,
|
||||
) : Configurable, Described, MetaRepr {
|
||||
|
||||
//constructor(config: Config, default: Meta) : this(config, { default[it] })
|
||||
constructor(config: Config) : this(config, { null })
|
||||
|
||||
final override var config: Config = Config()
|
||||
override var config: Config = config
|
||||
internal set
|
||||
|
||||
var defaultProvider: (Name) -> MetaItem<*>? = { null }
|
||||
public var defaultProvider: ItemProvider = defaultProvider
|
||||
internal set
|
||||
|
||||
public constructor() : this(Config(), ItemProvider { null })
|
||||
|
||||
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 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)
|
||||
|
||||
@ -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
|
||||
*/
|
||||
open class SchemeSpec<T : Scheme>(val builder: () -> T) :
|
||||
Specification<T> {
|
||||
override fun empty(): T = builder()
|
||||
public open class SchemeSpec<T : Scheme>(
|
||||
private val builder: (config: Config, defaultProvider: ItemProvider) -> T,
|
||||
) : Specification<T> {
|
||||
|
||||
override fun wrap(config: Config, defaultProvider: (Name) -> MetaItem<*>?): T {
|
||||
return empty().apply {
|
||||
public constructor(emptyBuilder: () -> T) : this({ config: Config, defaultProvider: ItemProvider ->
|
||||
emptyBuilder().apply {
|
||||
this.config = config
|
||||
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")
|
||||
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
|
||||
*/
|
||||
open class MetaScheme(
|
||||
val meta: Meta,
|
||||
public open class MetaScheme(
|
||||
private val meta: Meta,
|
||||
override val descriptor: NodeDescriptor? = null,
|
||||
config: Config = Config()
|
||||
config: Config = Config(),
|
||||
) : Scheme(config, meta::get) {
|
||||
override val defaultLayer: Meta get() = Laminate(meta, descriptor?.defaultItem().node)
|
||||
}
|
||||
|
||||
fun Meta.asScheme() =
|
||||
MetaScheme(this)
|
||||
public fun Meta.asScheme(): MetaScheme = 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)
|
@ -1,6 +1,5 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
@ -8,32 +7,32 @@ import kotlin.jvm.JvmName
|
||||
* By convention [Scheme] companion should inherit this class
|
||||
*
|
||||
*/
|
||||
interface Specification<T : Configurable> {
|
||||
fun empty() = wrap()
|
||||
public interface Specification<T : Configurable> {
|
||||
public fun empty(): T = wrap()
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
fun <T : Configurable> Specification<T>.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T =
|
||||
wrap(config) { default[it] }
|
||||
public fun <T : Configurable> Specification<T>.wrap(config: Config = Config(), default: Meta = Meta.EMPTY): T =
|
||||
wrap(config, 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()
|
||||
return wrap(source.asConfig(), default)
|
||||
}
|
||||
@ -42,26 +41,26 @@ fun <T : Configurable> Specification<T>.wrap(source: Meta): T {
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
/**
|
||||
* 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) }
|
||||
|
||||
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(
|
||||
Config(), it
|
||||
)
|
||||
}
|
||||
|
||||
@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) }
|
||||
|
@ -4,8 +4,8 @@ package hep.dataforge.meta
|
||||
* General marker for dataforge builders
|
||||
*/
|
||||
@DslMarker
|
||||
annotation class DFBuilder
|
||||
public annotation class DFBuilder
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.WARNING)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class DFExperimental
|
||||
public annotation class DFExperimental
|
@ -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],
|
||||
* 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) {
|
||||
0 -> error("Can't use empty name for 'getIndexed'")
|
||||
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 }
|
||||
} else {
|
||||
val regex = index.toRegex()
|
||||
root.items
|
||||
.filter { it.key.body == body && (regex.matches(it.key.index ?: "")) }
|
||||
root.items.filter { it.key.body == body && (regex.matches(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.
|
||||
*/
|
||||
@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>>
|
||||
|
||||
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())
|
@ -8,7 +8,7 @@ import hep.dataforge.values.Value
|
||||
/**
|
||||
* 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) ->
|
||||
token.toString() to when (item) {
|
||||
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.
|
||||
*/
|
||||
@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")
|
||||
fun toItem(value: Any?): MetaItem<*> = when (value) {
|
||||
is MetaItem<*> -> value
|
||||
|
@ -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 }
|
@ -10,7 +10,7 @@ import kotlinx.serialization.Serializable
|
||||
*
|
||||
*/
|
||||
@Serializable
|
||||
enum class ValueType {
|
||||
public enum class ValueType {
|
||||
NUMBER, STRING, BOOLEAN, NULL
|
||||
}
|
||||
|
||||
@ -19,44 +19,44 @@ enum class ValueType {
|
||||
*
|
||||
* Value can represent a list of value objects.
|
||||
*/
|
||||
interface Value {
|
||||
@Serializable(ValueSerializer::class)
|
||||
public interface Value {
|
||||
/**
|
||||
* Get raw value of this value
|
||||
*/
|
||||
val value: Any?
|
||||
public val value: Any?
|
||||
|
||||
/**
|
||||
* The type of the value
|
||||
*/
|
||||
val type: ValueType
|
||||
public val type: ValueType
|
||||
|
||||
/**
|
||||
* get this value represented as Number
|
||||
*/
|
||||
val number: Number
|
||||
public val number: Number
|
||||
|
||||
/**
|
||||
* get this value represented as String
|
||||
*/
|
||||
val string: String
|
||||
public val string: String
|
||||
|
||||
/**
|
||||
* get this value represented as List
|
||||
*/
|
||||
val list: List<Value>
|
||||
get() = if (this == Null) emptyList() else listOf(this)
|
||||
public val list: List<Value> get() = if (this == Null) emptyList() else listOf(this)
|
||||
|
||||
override fun equals(other: Any?): Boolean
|
||||
|
||||
override fun hashCode(): Int
|
||||
|
||||
companion object {
|
||||
const val TYPE = "value"
|
||||
public companion object {
|
||||
public const val TYPE: String = "value"
|
||||
|
||||
/**
|
||||
* Convert object to value
|
||||
*/
|
||||
fun of(value: Any?): Value {
|
||||
public fun of(value: Any?): Value {
|
||||
return when (value) {
|
||||
null -> Null
|
||||
is Value -> value
|
||||
@ -89,7 +89,7 @@ interface Value {
|
||||
/**
|
||||
* A singleton null value
|
||||
*/
|
||||
object Null : Value {
|
||||
public object Null : Value {
|
||||
override val value: Any? get() = null
|
||||
override val type: ValueType get() = ValueType.NULL
|
||||
override val number: Number get() = Double.NaN
|
||||
@ -104,7 +104,7 @@ object Null : Value {
|
||||
/**
|
||||
* Singleton true value
|
||||
*/
|
||||
object True : Value {
|
||||
public object True : Value {
|
||||
override val value: Any? get() = true
|
||||
override val type: ValueType get() = ValueType.BOOLEAN
|
||||
override val number: Number get() = 1.0
|
||||
@ -119,7 +119,7 @@ object True : Value {
|
||||
/**
|
||||
* Singleton false value
|
||||
*/
|
||||
object False : Value {
|
||||
public object False : Value {
|
||||
override val value: Any? get() = false
|
||||
override val type: ValueType get() = ValueType.BOOLEAN
|
||||
override val number: Number get() = -1.0
|
||||
@ -131,7 +131,7 @@ object False : Value {
|
||||
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 type: ValueType get() = ValueType.NUMBER
|
||||
override val string: String get() = number.toString()
|
||||
@ -154,7 +154,7 @@ class NumberValue(override val number: Number) : Value {
|
||||
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 type: ValueType get() = ValueType.STRING
|
||||
override val number: Number get() = string.toDouble()
|
||||
@ -168,7 +168,7 @@ class StringValue(override val string: String) : Value {
|
||||
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 number: Number get() = value.ordinal
|
||||
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()
|
||||
}
|
||||
|
||||
class ListValue(override val list: List<Value>) : Value {
|
||||
public class ListValue(override val list: List<Value>) : Value {
|
||||
init {
|
||||
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()
|
||||
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
|
||||
*/
|
||||
fun String.parseValue(): Value {
|
||||
public fun String.parseValue(): Value {
|
||||
|
||||
//Trying to get integer
|
||||
if (isEmpty() || this == Null.string) {
|
||||
|
@ -1,25 +1,25 @@
|
||||
package hep.dataforge.values
|
||||
|
||||
import hep.dataforge.meta.boolean
|
||||
import hep.dataforge.meta.enum
|
||||
import hep.dataforge.meta.string
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.builtins.ListSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||
import kotlinx.serialization.descriptors.element
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Serializer(Value::class)
|
||||
object ValueSerializer : KSerializer<Value> {
|
||||
public object ValueSerializer : KSerializer<Value> {
|
||||
private val listSerializer by lazy { ListSerializer(ValueSerializer) }
|
||||
|
||||
override val descriptor: SerialDescriptor =
|
||||
buildClassSerialDescriptor("hep.dataforge.values.Value") {
|
||||
boolean("isList")
|
||||
enum<ValueType>("valueType")
|
||||
string("value")
|
||||
element<Boolean>("isList")
|
||||
element<ValueType>("valueType")
|
||||
element<String>("value")
|
||||
}
|
||||
|
||||
private fun Decoder.decodeValue(): Value {
|
||||
|
@ -4,7 +4,7 @@ package hep.dataforge.values
|
||||
/**
|
||||
* 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() }
|
||||
|
||||
override val value: Any? get() = parsedValue.value
|
||||
@ -18,12 +18,12 @@ class LazyParsedValue(override val string: String) : Value {
|
||||
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
|
||||
*/
|
||||
class DoubleArrayValue(override val value: DoubleArray) : Value {
|
||||
public class DoubleArrayValue(override val value: DoubleArray) : Value {
|
||||
override val type: ValueType get() = ValueType.NUMBER
|
||||
override val number: Double get() = value.first()
|
||||
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 = "]")
|
||||
}
|
||||
|
||||
fun DoubleArray.asValue(): Value = if(isEmpty()) Null else DoubleArrayValue(this)
|
||||
public fun DoubleArray.asValue(): Value = if(isEmpty()) Null else DoubleArrayValue(this)
|
||||
|
@ -1,32 +1,33 @@
|
||||
package hep.dataforge.values
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
|
||||
/**
|
||||
* Check if value is null
|
||||
*/
|
||||
fun Value.isNull(): Boolean = this == Null
|
||||
public fun Value.isNull(): Boolean = this == Null
|
||||
|
||||
/**
|
||||
* 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
|
||||
|| this.list.firstOrNull() == True
|
||||
|| (type == ValueType.STRING && string.toBoolean())
|
||||
|
||||
|
||||
val Value.int get() = number.toInt()
|
||||
val Value.double get() = number.toDouble()
|
||||
val Value.float get() = number.toFloat()
|
||||
val Value.short get() = number.toShort()
|
||||
val Value.long get() = number.toLong()
|
||||
public val Value.int: Int get() = number.toInt()
|
||||
public val Value.double: Double get() = number.toDouble()
|
||||
public val Value.float: Float get() = number.toFloat()
|
||||
public val Value.short: Short get() = number.toShort()
|
||||
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) {
|
||||
value
|
||||
} 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 }
|
@ -1,18 +1,17 @@
|
||||
package hep.dataforge.meta
|
||||
|
||||
import hep.dataforge.names.Name
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class SpecificationTest {
|
||||
class TestStyled(config: Config, defaultProvider: (Name) -> MetaItem<*>?) :
|
||||
class TestStyled(config: Config, defaultProvider: ItemProvider) :
|
||||
Scheme(config, defaultProvider) {
|
||||
var list by numberList(1, 2, 3)
|
||||
|
||||
companion object : Specification<TestStyled> {
|
||||
override fun wrap(
|
||||
config: Config,
|
||||
defaultProvider: (Name) -> MetaItem<*>?
|
||||
defaultProvider: ItemProvider
|
||||
): TestStyled = TestStyled(config, defaultProvider)
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
Loading…
Reference in New Issue
Block a user