Name revolution

This commit is contained in:
Alexander Nozik 2021-07-31 15:02:11 +03:00
parent 4a76063093
commit 8763d63e28
42 changed files with 298 additions and 296 deletions

View File

@ -11,6 +11,7 @@
- Build tools 0.10.0 - Build tools 0.10.0
- Relaxed type restriction on `MetaConverter`. Now nullables are available. - Relaxed type restriction on `MetaConverter`. Now nullables are available.
- **Huge API-breaking refactoring of Meta**. Meta now can hava both value and children. - **Huge API-breaking refactoring of Meta**. Meta now can hava both value and children.
- **API breaking** `String.toName()` is replaced by `Name.parse()`
### Deprecated ### Deprecated
- Direct use of `Config` - Direct use of `Config`

View File

@ -4,7 +4,7 @@ plugins {
allprojects { allprojects {
group = "space.kscience" group = "space.kscience"
version = "0.5.0-dev-3" version = "0.5.0-dev-4"
} }
subprojects { subprojects {

View File

@ -7,8 +7,9 @@ import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.toName
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.set import kotlin.collections.set
@ -30,7 +31,7 @@ public class ContextBuilder internal constructor(
} }
public fun name(string: String) { public fun name(string: String) {
this.name = string.toName() this.name = Name.parse(string)
} }
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
@ -63,7 +64,7 @@ public class ContextBuilder internal constructor(
} }
public fun build(): Context { public fun build(): Context {
val contextName = name ?: "@auto[${hashCode().toUInt().toString(16)}]".toName() val contextName = name ?: NameToken("@auto",hashCode().toUInt().toString(16)).asName()
val plugins = HashMap<PluginTag, Plugin>() val plugins = HashMap<PluginTag, Plugin>()
fun addPlugin(factory: PluginFactory<*>, meta: Meta) { fun addPlugin(factory: PluginFactory<*>, meta: Meta) {

View File

@ -6,7 +6,6 @@ import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
/** /**
@ -31,7 +30,7 @@ public interface Plugin : Named, ContextAware, Provider, MetaRepr {
/** /**
* The name of this plugin ignoring version and group * The name of this plugin ignoring version and group
*/ */
override val name: Name get() = tag.name.toName() override val name: Name get() = Name.parse(tag.name)
/** /**
* Plugin dependencies which are required to attach this plugin. Plugin * Plugin dependencies which are required to attach this plugin. Plugin

View File

@ -1,14 +1,14 @@
package space.kscience.dataforge.properties package space.kscience.dataforge.properties
import space.kscience.dataforge.meta.ObservableMeta import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.names.toName
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
@DFExperimental @DFExperimental
public fun <P : ObservableMeta, T : Any> P.property(property: KMutableProperty1<P, T?>): Property<T?> = public fun <S : Scheme, T : Any> S.property(property: KMutableProperty1<S, T?>): Property<T?> =
object : Property<T?> { object : Property<T?> {
override var value: T? override var value: T?
get() = property.get(this@property) get() = property.get(this@property)
@ -17,15 +17,15 @@ public fun <P : ObservableMeta, T : Any> P.property(property: KMutableProperty1<
} }
override fun onChange(owner: Any?, callback: (T?) -> Unit) { override fun onChange(owner: Any?, callback: (T?) -> Unit) {
this@property.onChange(this) { name -> this@property.meta.onChange(this) { name ->
if (name.startsWith(property.name.toName())) { if (name.startsWith(Name.parse(property.name))) {
callback(property.get(this@property)) callback(property.get(this@property))
} }
} }
} }
override fun removeChangeListener(owner: Any?) { override fun removeChangeListener(owner: Any?) {
this@property.removeListener(this@property) this@property.meta.removeListener(this@property)
} }
} }

View File

@ -16,7 +16,6 @@
package space.kscience.dataforge.provider package space.kscience.dataforge.provider
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
/** /**
@ -63,7 +62,7 @@ public data class PathToken(val name: Name, val target: String? = null) {
public const val TARGET_SEPARATOR: String = "::" public const val TARGET_SEPARATOR: String = "::"
public fun parse(token: String): PathToken { public fun parse(token: String): PathToken {
val target = token.substringBefore(TARGET_SEPARATOR, "") val target = token.substringBefore(TARGET_SEPARATOR, "")
val name = token.substringAfter(TARGET_SEPARATOR).toName() val name = Name.parse(token.substringAfter(TARGET_SEPARATOR))
if (target.contains("[")) TODO("target separators in queries are not supported") if (target.contains("[")) TODO("target separators in queries are not supported")
return PathToken(name, target) return PathToken(name, target)
} }

View File

@ -2,7 +2,6 @@ package space.kscience.dataforge.context
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.appendLeft import space.kscience.dataforge.names.appendLeft
import space.kscience.dataforge.names.toName
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -12,17 +11,16 @@ class ContextTest {
override val tag get() = PluginTag("test") override val tag get() = PluginTag("test")
override fun content(target: String): Map<Name, Any> { override fun content(target: String): Map<Name, Any> {
return when(target){ return when (target) {
"test" -> listOf("a", "b", "c.d").associate { it.toName() to it.toName() } "test" -> listOf("a", "b", "c.d").associate { Name.parse(it) to Name.parse(it) }
else -> emptyMap() else -> emptyMap()
} }
} }
} }
@Test @Test
fun testPluginManager() { fun testPluginManager() {
val context = Global.buildContext{ val context = Global.buildContext {
name("test") name("test")
plugin(DummyPlugin()) plugin(DummyPlugin())
} }

View File

@ -14,7 +14,7 @@ internal class TestScheme : Scheme() {
} }
@DFExperimental @DFExperimental
class ItemPropertiesTest { class MetaPropertiesTest {
@Test @Test
fun testBinding() { fun testBinding() {
val scheme = TestScheme.empty() val scheme = TestScheme.empty()

View File

@ -11,7 +11,6 @@ import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -95,7 +94,7 @@ internal class ReduceAction<T : Any, R : Any>(
val groupMeta = group.meta val groupMeta = group.meta
val env = ActionEnv(groupName.toName(), groupMeta, meta) val env = ActionEnv(Name.parse(groupName), groupMeta, meta)
@OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData( @OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData(
outputType, outputType,
meta = groupMeta meta = groupMeta

View File

@ -12,7 +12,6 @@ import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.collections.set import kotlin.collections.set
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -36,7 +35,7 @@ public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val me
* @param rule the rule to transform fragment name and meta using * @param rule the rule to transform fragment name and meta using
*/ */
public fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) { public fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) {
fragments[name.toName()] = rule fragments[Name.parse(name)] = rule
} }
} }

View File

@ -115,4 +115,4 @@ public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit( public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
name: String, name: String,
noinline block: suspend ActiveDataTree<T>.() -> Unit, noinline block: suspend ActiveDataTree<T>.() -> Unit,
): Unit = emit(name.toName(), ActiveDataTree(typeOf<T>(), block)) ): Unit = emit(Name.parse(name), ActiveDataTree(typeOf<T>(), block))

View File

@ -8,7 +8,6 @@ import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.toName
import kotlin.reflect.KType import kotlin.reflect.KType
public interface DataSetBuilder<in T : Any> { public interface DataSetBuilder<in T : Any> {
@ -39,17 +38,17 @@ public interface DataSetBuilder<in T : Any> {
/** /**
* Append data to node * Append data to node
*/ */
public suspend infix fun String.put(data: Data<T>): Unit = emit(toName(), data) public suspend infix fun String.put(data: Data<T>): Unit = emit(Name.parse(this), data)
/** /**
* Append node * Append node
*/ */
public suspend infix fun String.put(dataSet: DataSet<T>): Unit = emit(toName(), dataSet) public suspend infix fun String.put(dataSet: DataSet<T>): Unit = emit(Name.parse(this), dataSet)
/** /**
* Build and append node * Build and append node
*/ */
public suspend infix fun String.put(block: suspend DataSetBuilder<T>.() -> Unit): Unit = emit(toName(), block) public suspend infix fun String.put(block: suspend DataSetBuilder<T>.() -> Unit): Unit = emit(Name.parse(this), block)
} }
private class SubSetBuilder<in T : Any>( private class SubSetBuilder<in T : Any>(
@ -77,15 +76,15 @@ public suspend fun <T : Any> DataSetBuilder<T>.emit(name: Name, block: suspend D
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, data: Data<T>) { public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, data: Data<T>) {
emit(name.toName(), data) emit(Name.parse(name), data)
} }
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, set: DataSet<T>) { public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, set: DataSet<T>) {
this.emit(name.toName(), set) this.emit(Name.parse(name), set)
} }
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, block: suspend DataSetBuilder<T>.() -> Unit): Unit = public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, block: suspend DataSetBuilder<T>.() -> Unit): Unit =
this@emit.emit(name.toName(), block) this@emit.emit(Name.parse(name), block)
public suspend fun <T : Any> DataSetBuilder<T>.emit(data: NamedData<T>) { public suspend fun <T : Any> DataSetBuilder<T>.emit(data: NamedData<T>) {
emit(data.name, data.data) emit(data.name, data.data)
@ -115,17 +114,25 @@ public suspend inline fun <reified T : Any> DataSetBuilder<T>.produce(
/** /**
* Emit a static data with the fixed value * Emit a static data with the fixed value
*/ */
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(name: String, data: T, meta: Meta = Meta.EMPTY): Unit = public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(
name: String,
data: T,
meta: Meta = Meta.EMPTY
): Unit =
emit(name, Data.static(data, meta)) emit(name, Data.static(data, meta))
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(name: Name, data: T, meta: Meta = Meta.EMPTY): Unit = public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(
name: Name,
data: T,
meta: Meta = Meta.EMPTY
): Unit =
emit(name, Data.static(data, meta)) emit(name, Data.static(data, meta))
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static( public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(
name: String, name: String,
data: T, data: T,
mutableMeta: MutableMeta.() -> Unit, mutableMeta: MutableMeta.() -> Unit,
): Unit = emit(name.toName(), Data.static(data, Meta(mutableMeta))) ): Unit = emit(Name.parse(name), Data.static(data, Meta(mutableMeta)))
/** /**
* Update data with given node data and meta with node meta. * Update data with given node data and meta with node meta.

View File

@ -57,7 +57,7 @@ public interface DataTree<out T : Any> : DataSet<T> {
} }
} }
public suspend fun <T: Any> DataSet<T>.getData(name: String): Data<T>? = getData(name.toName()) public suspend fun <T: Any> DataSet<T>.getData(name: String): Data<T>? = getData(Name.parse(name))
/** /**
* Get a [DataTreeItem] with given [name] or null if the item does not exist * Get a [DataTreeItem] with given [name] or null if the item does not exist

View File

@ -5,7 +5,10 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.removeHeadOrNull
import kotlin.reflect.KType import kotlin.reflect.KType
@ -64,7 +67,7 @@ public fun <T : Any> DataSet<T>.branch(branchName: Name): DataSet<T> = if (branc
override val updates: Flow<Name> get() = this@branch.updates.mapNotNull { it.removeHeadOrNull(branchName) } override val updates: Flow<Name> get() = this@branch.updates.mapNotNull { it.removeHeadOrNull(branchName) }
} }
public fun <T : Any> DataSet<T>.branch(branchName: String): DataSet<T> = this@branch.branch(branchName.toName()) public fun <T : Any> DataSet<T>.branch(branchName: String): DataSet<T> = this@branch.branch(Name.parse(branchName))
@DFExperimental @DFExperimental
public suspend fun <T : Any> DataSet<T>.rootData(): Data<T>? = getData(Name.EMPTY) public suspend fun <T : Any> DataSet<T>.rootData(): Data<T>? = getData(Name.EMPTY)

View File

@ -6,7 +6,6 @@ import kotlinx.coroutines.flow.map
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.matches import space.kscience.dataforge.names.matches
import space.kscience.dataforge.names.toName
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -61,4 +60,4 @@ public suspend fun <R : Any> DataSet<*>.selectOne(type: KType, name: Name): Name
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: Name): NamedData<R>? = selectOne(typeOf<R>(), name) public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: Name): NamedData<R>? = selectOne(typeOf<R>(), name)
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: String): NamedData<R>? = public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: String): NamedData<R>? =
selectOne(typeOf<R>(), name.toName()) selectOne(typeOf<R>(), Name.parse(name))

View File

@ -3,7 +3,7 @@ package space.kscience.dataforge.data
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collect
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.toName import space.kscience.dataforge.names.asName
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -72,7 +72,7 @@ internal class DataTreeBuilderTest {
} }
} }
val rootNode = ActiveDataTree<Int> { val rootNode = ActiveDataTree<Int> {
setAndObserve("sub".toName(), subNode) setAndObserve("sub".asName(), subNode)
} }
launch { launch {

View File

@ -10,12 +10,11 @@ import space.kscience.dataforge.io.PartDescriptor.Companion.SEPARATOR_KEY
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.toName
private class PartDescriptor : Scheme() { private class PartDescriptor : Scheme() {
var offset by int(0) var offset by int(0)
var size by int(0) var size by int(0)
var partMeta by item("meta".toName()) var partMeta by item("meta".asName())
companion object : SchemeSpec<PartDescriptor>(::PartDescriptor) { companion object : SchemeSpec<PartDescriptor>(::PartDescriptor) {
val MULTIPART_KEY = ENVELOPE_NODE_KEY + "multipart" val MULTIPART_KEY = ENVELOPE_NODE_KEY + "multipart"

View File

@ -10,7 +10,7 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.native.concurrent.ThreadLocal import kotlin.native.concurrent.ThreadLocal
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -23,7 +23,7 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
public fun <T : Any> resolveIOFormat(item: Meta, type: KClass<out T>): IOFormat<T>? { public fun <T : Any> resolveIOFormat(item: Meta, type: KClass<out T>): IOFormat<T>? {
val key = item.string ?: item[NAME_KEY]?.string ?: error("Format name not defined") val key = item.string ?: item[NAME_KEY]?.string ?: error("Format name not defined")
val name = key.toName() val name = Name.parse(key)
return ioFormatFactories.find { it.name == name }?.let { return ioFormatFactories.find { it.name == name }?.let {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
if (it.type != type) error("Format type ${it.type} is not the same as requested type $type") if (it.type != type) error("Format type ${it.type} is not the same as requested type $type")
@ -52,7 +52,7 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
public fun resolveEnvelopeFormat(item: Meta): EnvelopeFormat? { public fun resolveEnvelopeFormat(item: Meta): EnvelopeFormat? {
val name = item.string ?: item[NAME_KEY]?.string ?: error("Envelope format name not defined") val name = item.string ?: item[NAME_KEY]?.string ?: error("Envelope format name not defined")
val meta = item[META_KEY] ?: Meta.EMPTY val meta = item[META_KEY] ?: Meta.EMPTY
return resolveEnvelopeFormat(name.toName(), meta) return resolveEnvelopeFormat(Name.parse(name), meta)
} }
override fun content(target: String): Map<Name, Any> { override fun content(target: String): Map<Name, Any> {

View File

@ -10,7 +10,7 @@ import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import space.kscience.dataforge.names.toName
/** /**
* A streaming-friendly envelope format with a short binary tag. * A streaming-friendly envelope format with a short binary tag.
@ -121,7 +121,7 @@ public class TaggedEnvelopeFormat(
override fun invoke(meta: Meta, context: Context): EnvelopeFormat { override fun invoke(meta: Meta, context: Context): EnvelopeFormat {
val io = context.io val io = context.io
val metaFormatName = meta["name"].string?.toName() ?: JsonMetaFormat.name val metaFormatName = meta["name"].string?.let { Name.parse(it) } ?: JsonMetaFormat.name
//Check if appropriate factory exists //Check if appropriate factory exists
io.metaFormatFactories.find { it.name == metaFormatName } ?: error("Meta format could not be resolved") io.metaFormatFactories.find { it.name == metaFormatName } ?: error("Meta format could not be resolved")

View File

@ -7,7 +7,6 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaSerializer import space.kscience.dataforge.meta.MetaSerializer
import space.kscience.dataforge.meta.seal import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -43,7 +42,7 @@ class MetaSerializerTest {
@Test @Test
fun testNameSerialization() { fun testNameSerialization() {
val name = "a.b.c".toName() val name = Name.parse("a.b.c")
val string = JSON_PRETTY.encodeToString(Name.serializer(), name) val string = JSON_PRETTY.encodeToString(Name.serializer(), name)
val restored = JSON_PLAIN.decodeFromString(Name.serializer(), string) val restored = JSON_PLAIN.decodeFromString(Name.serializer(), string)
assertEquals(name, restored) assertEquals(name, restored)

View File

@ -16,6 +16,13 @@ public interface MetaRepr {
public fun toMeta(): Meta public fun toMeta(): Meta
} }
/**
* A container for meta nodes
*/
public fun interface MetaProvider {
public fun getMeta(name: Name): Meta?
}
/** /**
* A meta node * A meta node
* TODO add documentation * TODO add documentation
@ -23,10 +30,12 @@ public interface MetaRepr {
*/ */
@Type(Meta.TYPE) @Type(Meta.TYPE)
@Serializable(MetaSerializer::class) @Serializable(MetaSerializer::class)
public interface Meta : MetaRepr { public interface Meta : MetaRepr, MetaProvider {
public val value: Value? public val value: Value?
public val items: Map<NameToken, Meta> public val items: Map<NameToken, Meta>
override fun getMeta(name: Name): Meta? = find(name)
override fun toMeta(): Meta = this override fun toMeta(): Meta = this
override fun toString(): String override fun toString(): String
@ -66,6 +75,12 @@ public interface Meta : MetaRepr {
public fun toString(meta: Meta): String = json.encodeToString(MetaSerializer, meta) public fun toString(meta: Meta): String = json.encodeToString(MetaSerializer, meta)
public val EMPTY: Meta = SealedMeta(null, emptyMap()) public val EMPTY: Meta = SealedMeta(null, emptyMap())
private tailrec fun Meta.find(name: Name): Meta? = if (name.isEmpty()) {
this
} else {
items[name.firstOrNull()!!]?.find(name.cutFirst())
}
} }
} }
@ -82,16 +97,12 @@ public operator fun Meta.get(token: NameToken): Meta? = items[token]
* *
* If [name] is empty return current [Meta] * If [name] is empty return current [Meta]
*/ */
public tailrec operator fun Meta.get(name: Name): Meta? = if (name.isEmpty()) { public operator fun Meta.get(name: Name): Meta? = getMeta(name)
this
} else {
get(name.firstOrNull()!!)?.get(name.cutFirst())
}
/** /**
* Parse [Name] from [key] using full name notation and pass it to [Meta.get] * Parse [Name] from [key] using full name notation and pass it to [Meta.get]
*/ */
public operator fun Meta.get(key: String): Meta? = this[key.toName()] public operator fun Meta.get(key: String): Meta? = this[Name.parse(key)]
/** /**
* 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],
@ -155,7 +166,7 @@ public tailrec operator fun <M : TypedMeta<M>> TypedMeta<M>.get(name: Name): M?
/** /**
* Parse [Name] from [key] using full name notation and pass it to [TypedMeta.get] * Parse [Name] from [key] using full name notation and pass it to [TypedMeta.get]
*/ */
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(key: String): M? = this[key.toName()] public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(key: String): M? = this[Name.parse(key)]
/** /**
@ -197,7 +208,7 @@ public fun Meta.isEmpty(): Boolean = this === Meta.EMPTY || (value == null && it
public fun <M : TypedMeta<M>> TypedMeta<M>.getIndexed(name: Name): Map<String?, M> = public fun <M : TypedMeta<M>> TypedMeta<M>.getIndexed(name: Name): Map<String?, M> =
(this as Meta).getIndexed(name) as Map<String?, M> (this as Meta).getIndexed(name) as Map<String?, M>
public fun <M : TypedMeta<M>> TypedMeta<M>.getIndexed(name: String): Map<String?, Meta> = getIndexed(name.toName()) public fun <M : TypedMeta<M>> TypedMeta<M>.getIndexed(name: String): Map<String?, Meta> = getIndexed(Name.parse(name))
public val Meta?.string: String? get() = this?.value?.string public val Meta?.string: String? get() = this?.value?.string

View File

@ -10,8 +10,8 @@ import kotlin.properties.ReadOnlyProperty
public typealias MetaDelegate = ReadOnlyProperty<Any?, Meta?> public typealias MetaDelegate = ReadOnlyProperty<Any?, Meta?>
public fun Meta.item(key: Name? = null): MetaDelegate = ReadOnlyProperty { _, property -> public fun MetaProvider.item(key: Name? = null): MetaDelegate = ReadOnlyProperty { _, property ->
get(key ?: property.name.asName()) getMeta(key ?: property.name.asName())
} }
//TODO add caching for sealed nodes //TODO add caching for sealed nodes
@ -50,62 +50,62 @@ public fun <R> MetaDelegate.convert(
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
public fun Meta.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = public fun MetaProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> =
item(key).convert(MetaConverter.value) item(key).convert(MetaConverter.value)
public fun Meta.string(key: Name? = null): ReadOnlyProperty<Any?, String?> = public fun MetaProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> =
item(key).convert(MetaConverter.string) item(key).convert(MetaConverter.string)
public fun Meta.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> = public fun MetaProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> =
item(key).convert(MetaConverter.boolean) item(key).convert(MetaConverter.boolean)
public fun Meta.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> = public fun MetaProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> =
item(key).convert(MetaConverter.number) item(key).convert(MetaConverter.number)
public fun Meta.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> = public fun MetaProvider.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> =
item(key).convert(MetaConverter.double) item(key).convert(MetaConverter.double)
public fun Meta.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> = public fun MetaProvider.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> =
item(key).convert(MetaConverter.float) item(key).convert(MetaConverter.float)
public fun Meta.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> = public fun MetaProvider.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> =
item(key).convert(MetaConverter.int) item(key).convert(MetaConverter.int)
public fun Meta.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> = public fun MetaProvider.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> =
item(key).convert(MetaConverter.long) item(key).convert(MetaConverter.long)
public fun Meta.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> =
item(key).convert(MetaConverter.meta) item(key).convert(MetaConverter.meta)
public fun Meta.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> = public fun MetaProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> =
item(key).convert(MetaConverter.string) { default } item(key).convert(MetaConverter.string) { default }
public fun Meta.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> = public fun MetaProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean) { default } item(key).convert(MetaConverter.boolean) { default }
public fun Meta.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> = public fun MetaProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> =
item(key).convert(MetaConverter.number) { default } item(key).convert(MetaConverter.number) { default }
public fun Meta.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> = public fun MetaProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> =
item(key).convert(MetaConverter.double) { default } item(key).convert(MetaConverter.double) { default }
public fun Meta.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> = public fun MetaProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> =
item(key).convert(MetaConverter.float) { default } item(key).convert(MetaConverter.float) { default }
public fun Meta.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> = public fun MetaProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> =
item(key).convert(MetaConverter.int) { default } item(key).convert(MetaConverter.int) { default }
public fun Meta.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> = public fun MetaProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> =
item(key).convert(MetaConverter.long) { default } item(key).convert(MetaConverter.long) { default }
public inline fun <reified E : Enum<E>> Meta.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> = public inline fun <reified E : Enum<E>> MetaProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> =
item(key).convert(MetaConverter.enum()) { default } item(key).convert(MetaConverter.enum()) { default }
public fun Meta.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> = public fun MetaProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> =
item(key).convert(MetaConverter.string, default) item(key).convert(MetaConverter.string, default)
public fun Meta.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> = public fun MetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean, default) item(key).convert(MetaConverter.boolean, default)
public fun Meta.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> = public fun MetaProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> =
item(key).convert(MetaConverter.number, default) item(key).convert(MetaConverter.number, default)

View File

@ -16,13 +16,17 @@ import kotlin.jvm.Synchronized
@DslMarker @DslMarker
public annotation class MetaBuilder public annotation class MetaBuilder
public interface MutableMetaProvider : MetaProvider {
public fun setMeta(name: Name, node: Meta?)
}
/** /**
* Mutable variant of [Meta] * Mutable variant of [Meta]
* TODO documentation * TODO documentation
*/ */
@Serializable(MutableMetaSerializer::class) @Serializable(MutableMetaSerializer::class)
@MetaBuilder @MetaBuilder
public interface MutableMeta : Meta { public interface MutableMeta : Meta, MutableMetaProvider {
override val items: Map<NameToken, MutableMeta> override val items: Map<NameToken, MutableMeta>
@ -36,6 +40,14 @@ public interface MutableMeta : Meta {
*/ */
public operator fun set(name: Name, meta: Meta) public operator fun set(name: Name, meta: Meta)
override fun setMeta(name: Name, node: Meta?) {
if (node == null) {
remove(name)
} else {
set(name, node)
}
}
/** /**
* Remove a node at a given [name] if it is present * Remove a node at a given [name] if it is present
*/ */
@ -85,47 +97,47 @@ public interface MutableMeta : Meta {
} }
public infix fun String.put(meta: Meta) { public infix fun String.put(meta: Meta) {
toName() put meta Name.parse(this) put meta
} }
public infix fun String.put(value: Value?) { public infix fun String.put(value: Value?) {
set(toName(), value) set(Name.parse(this), value)
} }
public infix fun String.put(string: String) { public infix fun String.put(string: String) {
set(toName(), string.asValue()) set(Name.parse(this), string.asValue())
} }
public infix fun String.put(number: Number) { public infix fun String.put(number: Number) {
set(toName(), number.asValue()) set(Name.parse(this), number.asValue())
} }
public infix fun String.put(boolean: Boolean) { public infix fun String.put(boolean: Boolean) {
set(toName(), boolean.asValue()) set(Name.parse(this), boolean.asValue())
} }
public infix fun String.put(enum: Enum<*>) { public infix fun String.put(enum: Enum<*>) {
set(toName(), EnumValue(enum)) set(Name.parse(this), EnumValue(enum))
} }
public infix fun String.put(array: DoubleArray) { public infix fun String.put(array: DoubleArray) {
set(toName(), array.asValue()) set(Name.parse(this), array.asValue())
} }
public infix fun String.put(repr: MetaRepr) { public infix fun String.put(repr: MetaRepr) {
toName() put repr.toMeta() Name.parse(this) put repr.toMeta()
} }
public infix fun String.put(iterable: Iterable<Meta>) { public infix fun String.put(iterable: Iterable<Meta>) {
setIndexed(toName(), iterable) setIndexed(Name.parse(this), iterable)
} }
public infix fun String.put(builder: MutableMeta.() -> Unit) { public infix fun String.put(builder: MutableMeta.() -> Unit) {
set(toName(), MutableMeta(builder)) set(Name.parse(this), MutableMeta(builder))
} }
} }
public fun MutableMeta.getOrCreate(string: String): MutableMeta = getOrCreate(string.toName()) public fun MutableMeta.getOrCreate(key: String): MutableMeta = getOrCreate(Name.parse(key))
@Serializable(MutableMetaSerializer::class) @Serializable(MutableMetaSerializer::class)
public interface MutableTypedMeta<M : MutableTypedMeta<M>> : TypedMeta<M>, MutableMeta { public interface MutableTypedMeta<M : MutableTypedMeta<M>> : TypedMeta<M>, MutableMeta {
@ -138,47 +150,37 @@ public interface MutableTypedMeta<M : MutableTypedMeta<M>> : TypedMeta<M>, Mutab
override fun getOrCreate(name: Name): M override fun getOrCreate(name: Name): M
} }
public fun <M : MutableTypedMeta<M>> M.getOrCreate(string: String): M = getOrCreate(string.toName()) public fun <M : MutableTypedMeta<M>> M.getOrCreate(key: String): M = getOrCreate(Name.parse(key))
public fun MutableMeta.remove(name: String){ public fun MutableMeta.remove(key: String) {
remove(name.toName()) remove(Name.parse(key))
} }
// node setters // node setters
public operator fun MutableMeta.set(name: NameToken, value: Meta): Unit = set(name.asName(), value) public operator fun MutableMetaProvider.set(Key: NameToken, value: Meta): Unit = setMeta(Key.asName(), value)
public operator fun MutableMeta.set(name: Name, meta: Meta?): Unit { public operator fun MutableMetaProvider.set(key: String, value: Meta): Unit = setMeta(Name.parse(key), value)
if (meta == null) {
remove(name)
} else {
set(name, meta)
}
}
public operator fun MutableMeta.set(key: String, meta: Meta?): Unit {
set(key.toName(), meta)
}
//value setters //value setters
public operator fun MutableMeta.set(name: NameToken, value: Value?): Unit = set(name.asName(), value) public operator fun MutableMeta.set(name: NameToken, value: Value?): Unit = set(name.asName(), value)
public operator fun MutableMeta.set(key: String, value: Value?): Unit = set(key.toName(), value) public operator fun MutableMeta.set(key: String, value: Value?): Unit = set(Name.parse(key), value)
public operator fun MutableMeta.set(name: Name, value: String): Unit = set(name, value.asValue()) public operator fun MutableMeta.set(name: Name, value: String): Unit = set(name, value.asValue())
public operator fun MutableMeta.set(name: NameToken, value: String): Unit = set(name.asName(), value.asValue()) public operator fun MutableMeta.set(name: NameToken, value: String): Unit = set(name.asName(), value.asValue())
public operator fun MutableMeta.set(key: String, value: String): Unit = set(key.toName(), value.asValue()) public operator fun MutableMeta.set(key: String, value: String): Unit = set(Name.parse(key), value.asValue())
public operator fun MutableMeta.set(name: Name, value: Boolean): Unit = set(name, value.asValue()) public operator fun MutableMeta.set(name: Name, value: Boolean): Unit = set(name, value.asValue())
public operator fun MutableMeta.set(name: NameToken, value: Boolean): Unit = set(name.asName(), value.asValue()) public operator fun MutableMeta.set(name: NameToken, value: Boolean): Unit = set(name.asName(), value.asValue())
public operator fun MutableMeta.set(key: String, value: Boolean): Unit = set(key.toName(), value.asValue()) public operator fun MutableMeta.set(key: String, value: Boolean): Unit = set(Name.parse(key), value.asValue())
public operator fun MutableMeta.set(name: Name, value: Number): Unit = set(name, value.asValue()) public operator fun MutableMeta.set(name: Name, value: Number): Unit = set(name, value.asValue())
public operator fun MutableMeta.set(name: NameToken, value: Number): Unit = set(name.asName(), value.asValue()) public operator fun MutableMeta.set(name: NameToken, value: Number): Unit = set(name.asName(), value.asValue())
public operator fun MutableMeta.set(key: String, value: Number): Unit = set(key.toName(), value.asValue()) public operator fun MutableMeta.set(key: String, value: Number): Unit = set(Name.parse(key), value.asValue())
public operator fun MutableMeta.set(name: Name, value: List<Value>): Unit = set(name, value.asValue()) public operator fun MutableMeta.set(name: Name, value: List<Value>): Unit = set(name, value.asValue())
public operator fun MutableMeta.set(name: NameToken, value: List<Value>): Unit = set(name.asName(), value.asValue()) public operator fun MutableMeta.set(name: NameToken, value: List<Value>): Unit = set(name.asName(), value.asValue())
public operator fun MutableMeta.set(key: String, value: List<Value>): Unit = set(key.toName(), value.asValue()) public operator fun MutableMeta.set(key: String, value: List<Value>): Unit = set(Name.parse(key), value.asValue())
//public fun MutableMeta.set(key: String, index: String, value: Value?): Unit = //public fun MutableMeta.set(key: String, index: String, value: Value?): Unit =
// set(key.toName().withIndex(index), value) // set(key.toName().withIndex(index), value)
@ -218,8 +220,8 @@ public fun MutableMeta.setIndexed(
public operator fun MutableMeta.set(name: Name, metas: Iterable<Meta>): Unit = public operator fun MutableMeta.set(name: Name, metas: Iterable<Meta>): Unit =
setIndexed(name, metas) setIndexed(name, metas)
public operator fun MutableMeta.set(name: String, metas: Iterable<Meta>): Unit = public operator fun MutableMeta.set(key: String, metas: Iterable<Meta>): Unit =
setIndexed(name.toName(), metas) setIndexed(Name.parse(key), metas)
/** /**
@ -396,13 +398,13 @@ public fun MutableMeta.append(name: Name, meta: Meta) {
} }
@DFExperimental @DFExperimental
public fun MutableMeta.append(name: String, meta: Meta): Unit = append(name.toName(), meta) public fun MutableMeta.append(key: String, meta: Meta): Unit = append(Name.parse(key), meta)
@DFExperimental @DFExperimental
public fun MutableMeta.append(name: Name, value: Value): Unit = append(name, Meta(value)) public fun MutableMeta.append(name: Name, value: Value): Unit = append(name, Meta(value))
@DFExperimental @DFExperimental
public fun MutableMeta.append(name: String, value: Value): Unit = append(name.toName(), value) public fun MutableMeta.append(key: String, value: Value): Unit = append(Name.parse(key), 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.
@ -443,8 +445,9 @@ public inline fun Meta.copy(block: MutableMeta.() -> Unit = {}): Meta =
toMutableMeta().apply(block) toMutableMeta().apply(block)
private class MutableMetaWithDefault(val source: MutableMeta, val default: Meta, val name: Name) : private class MutableMetaWithDefault(
MutableMeta by source { val source: MutableMeta, val default: Meta, val name: Name
) : MutableMeta by source {
override val items: Map<NameToken, MutableMeta> override val items: Map<NameToken, MutableMeta>
get() = (source.items.keys + default.items.keys).associateWith { get() = (source.items.keys + default.items.keys).associateWith {
MutableMetaWithDefault(source, default, name + it) MutableMetaWithDefault(source, default, name + it)
@ -456,6 +459,8 @@ private class MutableMetaWithDefault(val source: MutableMeta, val default: Meta,
source[name] = value source[name] = value
} }
override fun getMeta(name: Name): Meta? = source.getMeta(name) ?: default.getMeta(name)
override fun toString(): String = Meta.toString(this) override fun toString(): String = Meta.toString(this)
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta) override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
override fun hashCode(): Int = Meta.hashCode(this) override fun hashCode(): Int = Meta.hashCode(this)

View File

@ -11,14 +11,14 @@ import kotlin.reflect.KProperty
public typealias MutableMetaDelegate = ReadWriteProperty<Any?, Meta?> public typealias MutableMetaDelegate = ReadWriteProperty<Any?, Meta?>
public fun MutableMeta.item(key: Name? = null): MutableMetaDelegate = object : MutableMetaDelegate { public fun MutableMetaProvider.item(key: Name? = null): MutableMetaDelegate = object : MutableMetaDelegate {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? {
return get(key ?: property.name.asName()) return getMeta(key ?: property.name.asName())
} }
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
val name = key ?: property.name.asName() val name = key ?: property.name.asName()
set(name, value) setMeta(name, value)
} }
} }
@ -74,40 +74,40 @@ public fun <R> MutableMetaDelegate.convert(
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
public fun MutableMeta.value(key: Name? = null): ReadWriteProperty<Any?, Value?> = public fun MutableMetaProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
item(key).convert(MetaConverter.value) item(key).convert(MetaConverter.value)
public fun MutableMeta.string(key: Name? = null): ReadWriteProperty<Any?, String?> = public fun MutableMetaProvider.string(key: Name? = null): ReadWriteProperty<Any?, String?> =
item(key).convert(MetaConverter.string) item(key).convert(MetaConverter.string)
public fun MutableMeta.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> = public fun MutableMetaProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
item(key).convert(MetaConverter.boolean) item(key).convert(MetaConverter.boolean)
public fun MutableMeta.number(key: Name? = null): ReadWriteProperty<Any?, Number?> = public fun MutableMetaProvider.number(key: Name? = null): ReadWriteProperty<Any?, Number?> =
item(key).convert(MetaConverter.number) item(key).convert(MetaConverter.number)
public fun MutableMeta.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> = public fun MutableMetaProvider.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> =
item(key).convert(MetaConverter.string) { default } item(key).convert(MetaConverter.string) { default }
public fun MutableMeta.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> = public fun MutableMetaProvider.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean) { default } item(key).convert(MetaConverter.boolean) { default }
public fun MutableMeta.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> = public fun MutableMetaProvider.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> =
item(key).convert(MetaConverter.number) { default } item(key).convert(MetaConverter.number) { default }
public fun MutableMeta.value(key: Name? = null, default: () -> Value): ReadWriteProperty<Any?, Value> = public fun MutableMetaProvider.value(key: Name? = null, default: () -> Value): ReadWriteProperty<Any?, Value> =
item(key).convert(MetaConverter.value, default) item(key).convert(MetaConverter.value, default)
public fun MutableMeta.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> = public fun MutableMetaProvider.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> =
item(key).convert(MetaConverter.string, default) item(key).convert(MetaConverter.string, default)
public fun MutableMeta.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> = public fun MutableMetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean, default) item(key).convert(MetaConverter.boolean, default)
public fun MutableMeta.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> = public fun MutableMetaProvider.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>> MutableMeta.enum( public inline fun <reified E : Enum<E>> MutableMetaProvider.enum(
default: E, default: E,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, E> = ): ReadWriteProperty<Any?, E> =
@ -115,37 +115,37 @@ public inline fun <reified E : Enum<E>> MutableMeta.enum(
/* Number delegates */ /* Number delegates */
public fun MutableMeta.int(key: Name? = null): ReadWriteProperty<Any?, Int?> = public fun MutableMetaProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> =
item(key).convert(MetaConverter.int) item(key).convert(MetaConverter.int)
public fun MutableMeta.double(key: Name? = null): ReadWriteProperty<Any?, Double?> = public fun MutableMetaProvider.double(key: Name? = null): ReadWriteProperty<Any?, Double?> =
item(key).convert(MetaConverter.double) item(key).convert(MetaConverter.double)
public fun MutableMeta.long(key: Name? = null): ReadWriteProperty<Any?, Long?> = public fun MutableMetaProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> =
item(key).convert(MetaConverter.long) item(key).convert(MetaConverter.long)
public fun MutableMeta.float(key: Name? = null): ReadWriteProperty<Any?, Float?> = public fun MutableMetaProvider.float(key: Name? = null): ReadWriteProperty<Any?, Float?> =
item(key).convert(MetaConverter.float) item(key).convert(MetaConverter.float)
/* Safe number delegates*/ /* Safe number delegates*/
public fun MutableMeta.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> = public fun MutableMetaProvider.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> =
item(key).convert(MetaConverter.int) { default } item(key).convert(MetaConverter.int) { default }
public fun MutableMeta.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> = public fun MutableMetaProvider.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> =
item(key).convert(MetaConverter.double) { default } item(key).convert(MetaConverter.double) { default }
public fun MutableMeta.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> = public fun MutableMetaProvider.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> =
item(key).convert(MetaConverter.long) { default } item(key).convert(MetaConverter.long) { default }
public fun MutableMeta.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> = public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> =
item(key).convert(MetaConverter.float) { default } item(key).convert(MetaConverter.float) { default }
/* Extra delegates for special cases */ /* Extra delegates for special cases */
public fun MutableMeta.stringList( public fun MutableMetaProvider.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(
@ -153,14 +153,14 @@ public fun MutableMeta.stringList(
writer = { Meta(it.map { str -> str.asValue() }.asValue()) } writer = { Meta(it.map { str -> str.asValue() }.asValue()) }
) )
public fun MutableMeta.stringList( public fun MutableMetaProvider.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()?.let { Meta(it) } } writer = { it?.map { str -> str.asValue() }?.asValue()?.let { Meta(it) } }
) )
public fun MutableMeta.numberList( public fun MutableMetaProvider.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(
@ -171,7 +171,7 @@ public fun MutableMeta.numberList(
/* A special delegate for double arrays */ /* A special delegate for double arrays */
public fun MutableMeta.doubleArray( public fun MutableMetaProvider.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(
@ -179,7 +179,7 @@ public fun MutableMeta.doubleArray(
writer = { Meta(DoubleArrayValue(it)) } writer = { Meta(DoubleArrayValue(it)) }
) )
public fun <T> MutableMeta.listValue( public fun <T> MutableMetaProvider.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,

View File

@ -1,9 +1,6 @@
package space.kscience.dataforge.meta package space.kscience.dataforge.meta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.*
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.startsWith
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import kotlin.jvm.Synchronized import kotlin.jvm.Synchronized
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
@ -57,6 +54,8 @@ private class ObservableMetaWrapper(
override val items: Map<NameToken, ObservableMetaWrapper> override val items: Map<NameToken, ObservableMetaWrapper>
get() = origin.items.mapValues { ObservableMetaWrapper(it.value) } get() = origin.items.mapValues { ObservableMetaWrapper(it.value) }
override fun getMeta(name: Name): Meta? = origin.getMeta(name)
override var value: Value? override var value: Value?
get() = origin.value get() = origin.value
set(value) { set(value) {
@ -86,7 +85,10 @@ private class ObservableMetaWrapper(
} }
override fun attach(name: Name, node: ObservableMutableMeta) { override fun attach(name: Name, node: ObservableMutableMeta) {
TODO("Not yet implemented") set(name, node)
node.onChange(this) { changeName ->
setMeta(name + changeName, node[changeName])
}
} }
} }
@ -104,14 +106,14 @@ public fun MutableMeta.asObservable(): ObservableMutableMeta =
* *
* Optional [owner] property is used for * Optional [owner] property is used for
*/ */
public fun <O : ObservableMeta, T> O.useProperty( public fun <S : Scheme, T> S.useProperty(
property: KProperty1<O, T>, property: KProperty1<S, T>,
owner: Any? = null, owner: Any? = null,
callBack: O.(T) -> Unit, callBack: S.(T) -> Unit,
) { ) {
//Pass initial value. //Pass initial value.
callBack(property.get(this)) callBack(property.get(this))
onChange(owner) { name -> meta.onChange(owner) { name ->
if (name.startsWith(property.name.asName())) { if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty)) callBack(property.get(this@useProperty))
} }

View File

@ -2,35 +2,24 @@ package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.descriptors.* import space.kscience.dataforge.meta.descriptors.*
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.values.Value
/** /**
* 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].
* Default item provider and [NodeDescriptor] are optional * Default item provider and [MetaDescriptor] are optional
*/ */
public open class Scheme( public open class Scheme : Described, MetaRepr, MutableMetaProvider {
source: MutableMeta = MutableMeta()
) : Described, MutableMeta, ObservableMeta, Meta by source {
private var source = source.asObservable() public var meta: ObservableMutableMeta = MutableMeta()
private set
final override var descriptor: MetaDescriptor? = null final override var descriptor: MetaDescriptor? = null
internal set internal set
override var value: Value?
get() = source.value
set(value) {
source.value = value
}
override val items: Map<NameToken, MutableMeta> get() = source.items
internal fun wrap( internal fun wrap(
items: MutableMeta, items: MutableMeta,
preserveDefault: Boolean = false preserveDefault: Boolean = false
) { ) {
this.source = (if (preserveDefault) items.withDefault(this.source) else items).asObservable() meta = (if (preserveDefault) items.withDefault(meta.seal()) else items).asObservable()
} }
/** /**
@ -41,35 +30,17 @@ public open class Scheme(
return descriptor?.validate(meta) ?: true return descriptor?.validate(meta) ?: true
} }
/** override fun getMeta(name: Name): Meta? = meta.getMeta(name)
* Set a configurable property
*/ override fun setMeta(name: Name, node: Meta?) {
override fun set(name: Name, meta: Meta) {
val oldItem = source[name]
if (oldItem != meta) {
if (validate(name, meta)) { if (validate(name, meta)) {
source[name] = meta meta.setMeta(name, node)
} else { } else {
error("Validation failed for property $name with value $meta") error("Validation failed for node $node at $name")
}
} }
} }
override fun toMeta(): Laminate = Laminate(source, descriptor?.defaultNode) override fun toMeta(): Laminate = Laminate(meta, descriptor?.defaultNode)
override fun remove(name: Name) {
source.remove(name)
}
override fun getOrCreate(name: Name): MutableMeta = source.getOrCreate(name)
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
source.onChange(owner ?: this, callback)
}
override fun removeListener(owner: Any?) {
source.removeListener(owner ?: this)
}
} }
/** /**

View File

@ -77,6 +77,11 @@ public fun <T : Scheme> MutableMeta.spec(
} }
} }
public fun <T : Scheme> Scheme.spec(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T> = meta.spec(spec, key)
/** /**
* A delegate that uses a [Specification] to wrap a list of child providers. * A delegate that uses a [Specification] to wrap a list of child providers.
* If children are mutable, the changes in list elements are reflected on them. * If children are mutable, the changes in list elements are reflected on them.

View File

@ -43,7 +43,7 @@ public operator fun MetaDescriptor.get(name: Name): MetaDescriptor? = when (name
else -> get(name.firstOrNull()!!.asName())?.get(name.cutFirst()) else -> get(name.firstOrNull()!!.asName())?.get(name.cutFirst())
} }
public operator fun MetaDescriptor.get(name: String): MetaDescriptor? = get(name.toName()) public operator fun MetaDescriptor.get(name: String): MetaDescriptor? = get(Name.parse(name))
/** /**
* A node constructed of default values for this descriptor and its children * A node constructed of default values for this descriptor and its children

View File

@ -4,10 +4,22 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.set import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.cutFirst
import space.kscience.dataforge.names.first
import space.kscience.dataforge.names.length
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.ValueType import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
import kotlin.collections.List
import kotlin.collections.MutableMap
import kotlin.collections.emptyList
import kotlin.collections.getOrPut
import kotlin.collections.hashMapOf
import kotlin.collections.listOf
import kotlin.collections.map
import kotlin.collections.mapValues
import kotlin.collections.set
public class MetaDescriptorBuilder { public class MetaDescriptorBuilder {
public var info: String? = null public var info: String? = null
@ -67,7 +79,7 @@ public class MetaDescriptorBuilder {
} }
public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit) { public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit) {
item(name.toName(), block) item(Name.parse(name), block)
} }
public fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor = public fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor =
@ -94,7 +106,7 @@ public fun MetaDescriptorBuilder.value(
vararg additionalTypes: ValueType, vararg additionalTypes: ValueType,
block: MetaDescriptorBuilder.() -> Unit block: MetaDescriptorBuilder.() -> Unit
) { ) {
value(name.toName(), type, additionalTypes = additionalTypes, block) value(Name.parse(name), type, additionalTypes = additionalTypes, block)
} }
/** /**
@ -108,7 +120,7 @@ public fun MetaDescriptorBuilder.node(name: Name, block: MetaDescriptorBuilder.(
} }
public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder.() -> Unit) { public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder.() -> Unit) {
node(name.toName(), block) node(Name.parse(name), block)
} }
public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum( public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(

View File

@ -3,7 +3,7 @@ package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.get import space.kscience.dataforge.meta.descriptors.get
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.toName import space.kscience.dataforge.names.Name
import space.kscience.dataforge.values.ListValue import space.kscience.dataforge.values.ListValue
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
@ -28,7 +28,7 @@ public fun Meta.toMap(descriptor: MetaDescriptor? = null): Map<String, Any?> = b
/** /**
* Convert map of maps to meta. This method will recognize [Meta], [Map]<String,Any?> and [List] of all mentioned above as value. * Convert map of maps to meta. This method will recognize [Meta], [Map]<String,Any?> and [List] of all mentioned above as value.
* All other values will be converted to values. * All other values will be converted to [Value].
*/ */
@DFExperimental @DFExperimental
public fun Map<String, Any?>.toMeta(descriptor: MetaDescriptor? = null): Meta = Meta { public fun Map<String, Any?>.toMeta(descriptor: MetaDescriptor? = null): Meta = Meta {
@ -45,7 +45,7 @@ public fun Map<String, Any?>.toMeta(descriptor: MetaDescriptor? = null): Meta =
if (items.all { it.isLeaf }) { if (items.all { it.isLeaf }) {
set(key, ListValue(items.map { it.value!! })) set(key, ListValue(items.map { it.value!! }))
} else { } else {
setIndexedItems(key.toName(), value.map { toMeta(it) }) setIndexedItems(Name.parse(key), value.map { toMeta(it) })
} }
} else { } else {
set(key, toMeta(value)) set(key, toMeta(value))

View File

@ -42,7 +42,7 @@ public data class KeepTransformationRule(val selector: (Name) -> Boolean) :
meta.nodeSequence().map { it.first }.filter(selector) meta.nodeSequence().map { it.first }.filter(selector)
override fun transformItem(name: Name, item: Meta?, target: MutableMeta) { override fun transformItem(name: Name, item: Meta?, target: MutableMeta) {
if (selector(name)) target.set(name, item) if (selector(name)) target.setMeta(name, item)
} }
} }
@ -174,7 +174,7 @@ public class MetaTransformationBuilder {
public fun keep(regex: String) { public fun keep(regex: String) {
transformations.add( transformations.add(
RegexItemTransformationRule(regex.toRegex()) { name, _, Meta -> RegexItemTransformationRule(regex.toRegex()) { name, _, Meta ->
set(name, Meta) setMeta(name, Meta)
}) })
} }
@ -184,7 +184,7 @@ public class MetaTransformationBuilder {
public fun move(from: Name, to: Name, operation: (Meta?) -> Meta? = { it }) { public fun move(from: Name, to: Name, operation: (Meta?) -> Meta? = { it }) {
transformations.add( transformations.add(
SingleItemTransformationRule(from) { _, item -> SingleItemTransformationRule(from) { _, item ->
set(to, operation(item)) setMeta(to, operation(item))
} }
) )
} }

View File

@ -47,45 +47,13 @@ public class Name(public val tokens: List<NameToken>) {
public val MATCH_ALL_TOKEN: NameToken = NameToken("**") public val MATCH_ALL_TOKEN: NameToken = NameToken("**")
public val EMPTY: Name = Name(emptyList()) public val EMPTY: Name = Name(emptyList())
}
}
public operator fun Name.get(i: Int): NameToken = tokens[i] /**
/**
* The reminder of the name after last element is cut. For empty name return itself.
*/
public fun Name.cutLast(): Name = Name(tokens.dropLast(1))
/**
* The reminder of the name after first element is cut. For empty name return itself.
*/
public fun Name.cutFirst(): Name = Name(tokens.drop(1))
public val Name.length: Int get() = tokens.size
/**
* Last token of the name or null if it is empty
*/
public fun Name.lastOrNull(): NameToken? = tokens.lastOrNull()
/**
* First token of the name or null if it is empty
*/
public fun Name.firstOrNull(): NameToken? = tokens.firstOrNull()
/**
* First token or throw exception
*/
public fun Name.first(): NameToken = tokens.first()
/**
* Convert a [String] to name parsing it and extracting name tokens and index syntax. * Convert a [String] to name parsing it and extracting name tokens and index syntax.
* This operation is rather heavy so it should be used with care in high performance code. * This operation is rather heavy so it should be used with care in high performance code.
*/ */
public fun String.toName(): Name { public fun parse(string: String): Name{
if (isBlank()) return Name.EMPTY if (string.isBlank()) return Name.EMPTY
val tokens = sequence { val tokens = sequence {
var bodyBuilder = StringBuilder() var bodyBuilder = StringBuilder()
var queryBuilder = StringBuilder() var queryBuilder = StringBuilder()
@ -93,7 +61,7 @@ public fun String.toName(): Name {
var escape: Boolean = false var escape: Boolean = false
fun queryOn() = bracketCount > 0 fun queryOn() = bracketCount > 0
for (it in this@toName) { for (it in string) {
when { when {
escape -> { escape -> {
if (queryOn()) { if (queryOn()) {
@ -133,8 +101,40 @@ public fun String.toName(): Name {
yield(NameToken(bodyBuilder.toString(), query)) yield(NameToken(bodyBuilder.toString(), query))
} }
return Name(tokens.toList()) return Name(tokens.toList())
}
}
} }
public operator fun Name.get(i: Int): NameToken = tokens[i]
/**
* The reminder of the name after last element is cut. For empty name return itself.
*/
public fun Name.cutLast(): Name = Name(tokens.dropLast(1))
/**
* The reminder of the name after first element is cut. For empty name return itself.
*/
public fun Name.cutFirst(): Name = Name(tokens.drop(1))
public val Name.length: Int get() = tokens.size
/**
* Last token of the name or null if it is empty
*/
public fun Name.lastOrNull(): NameToken? = tokens.lastOrNull()
/**
* First token of the name or null if it is empty
*/
public fun Name.firstOrNull(): NameToken? = tokens.firstOrNull()
/**
* First token or throw exception
*/
public fun Name.first(): NameToken = tokens.first()
/** /**
* Convert the [String] to a [Name] by simply wrapping it in a single name token without parsing. * Convert the [String] to a [Name] by simply wrapping it in a single name token without parsing.
* The input string could contain dots and braces, but they are just escaped, not parsed. * The input string could contain dots and braces, but they are just escaped, not parsed.
@ -145,7 +145,7 @@ public operator fun NameToken.plus(other: Name): Name = Name(listOf(this) + othe
public operator fun Name.plus(other: Name): Name = Name(this.tokens + other.tokens) public operator fun Name.plus(other: Name): Name = Name(this.tokens + other.tokens)
public operator fun Name.plus(other: String): Name = this + other.toName() public operator fun Name.plus(other: String): Name = this + Name.parse(other)
public operator fun Name.plus(other: NameToken): Name = Name(tokens + other) public operator fun Name.plus(other: NameToken): Name = Name(tokens + other)
@ -174,8 +174,8 @@ public fun Name.withIndex(index: String): Name {
* Fast [String]-based accessor for item map * Fast [String]-based accessor for item map
*/ */
public operator fun <T> Map<NameToken, T>.get(body: String, query: String? = null): T? = get(NameToken(body, query)) public operator fun <T> Map<NameToken, T>.get(body: String, query: String? = null): T? = get(NameToken(body, query))
public operator fun <T> Map<Name, T>.get(name: String): T? = get(name.toName()) public operator fun <T> Map<Name, T>.get(name: String): T? = get(Name.parse(name))
public operator fun <T> MutableMap<Name, T>.set(name: String, value: T): Unit = set(name.toName(), value) public operator fun <T> MutableMap<Name, T>.set(name: String, value: T): Unit = set(Name.parse(name), value)
/* Name comparison operations */ /* Name comparison operations */

View File

@ -12,7 +12,7 @@ public object NameSerializer : KSerializer<Name> {
PrimitiveSerialDescriptor("space.kscience.dataforge.names.Name", PrimitiveKind.STRING) PrimitiveSerialDescriptor("space.kscience.dataforge.names.Name", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): Name { override fun deserialize(decoder: Decoder): Name {
return decoder.decodeString().toName() return Name.parse(decoder.decodeString())
} }
override fun serialize(encoder: Encoder, value: Name) { override fun serialize(encoder: Encoder, value: Name) {
@ -25,7 +25,7 @@ public object NameTokenSerializer: KSerializer<NameToken> {
PrimitiveSerialDescriptor("space.kscience.dataforge.names.NameToken", PrimitiveKind.STRING) PrimitiveSerialDescriptor("space.kscience.dataforge.names.NameToken", PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder): NameToken { override fun deserialize(decoder: Decoder): NameToken {
return decoder.decodeString().toName().firstOrNull()!! return Name.parse(decoder.decodeString()).firstOrNull()!!
} }
override fun serialize( override fun serialize(

View File

@ -44,4 +44,4 @@ public fun Name.matches(pattern: Name): Boolean = when {
} }
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
public fun Name.matches(pattern: String): Boolean = matches(pattern.toName()) public fun Name.matches(pattern: String): Boolean = matches(Name.parse(pattern))

View File

@ -30,7 +30,7 @@ class MetaDelegateTest {
fun delegateTest() { fun delegateTest() {
val testObject = TestScheme.empty() val testObject = TestScheme.empty()
testObject.set("myValue","theString".asValue()) testObject.meta["myValue"] = "theString".asValue()
testObject.enumValue = TestEnum.NO testObject.enumValue = TestEnum.NO
testObject.inner = InnerScheme { innerValue = "ddd" } testObject.inner = InnerScheme { innerValue = "ddd" }

View File

@ -10,7 +10,7 @@ import kotlin.test.assertTrue
class NameMatchTest { class NameMatchTest {
@Test @Test
fun matchWildCards() { fun matchWildCards() {
val theName = "a.b.c.d".toName() val theName = Name.parse("a.b.c.d")
assertTrue { theName.matches("a.b.**") } assertTrue { theName.matches("a.b.**") }
assertTrue { theName.matches("a.*.c.**") } assertTrue { theName.matches("a.*.c.**") }
assertTrue { theName.matches("**.d") } assertTrue { theName.matches("**.d") }
@ -22,7 +22,7 @@ class NameMatchTest {
@Test @Test
fun matchPattern() { fun matchPattern() {
val theName = "a[dd+2].b[13].c.d[\"d\"]".toName() val theName = Name.parse("a[dd+2].b[13].c.d[\"d\"]")
assertTrue { theName.matches("a[.*].b[.*].c[.*].d[.*]") } assertTrue { theName.matches("a[.*].b[.*].c[.*].d[.*]") }
assertTrue { theName.matches("a[.*].b[.*].c.d[.*]") } assertTrue { theName.matches("a[.*].b[.*].c.d[.*]") }
assertFalse { theName.matches("a[.*].b[.*].*.d") } assertFalse { theName.matches("a[.*].b[.*].*.d") }

View File

@ -9,7 +9,7 @@ class NameSerializationTest {
@Test @Test
fun testNameSerialization() { fun testNameSerialization() {
val name = "aaa.bbb.ccc".toName() val name = Name.parse("aaa.bbb.ccc")
val json = Json.encodeToJsonElement(Name.serializer(), name) val json = Json.encodeToJsonElement(Name.serializer(), name)
println(json) println(json)
val reconstructed = Json.decodeFromJsonElement(Name.serializer(), json) val reconstructed = Json.decodeFromJsonElement(Name.serializer(), json)

View File

@ -8,22 +8,22 @@ import kotlin.test.assertTrue
class NameTest { class NameTest {
@Test @Test
fun simpleName() { fun simpleName() {
val name = "token1.token2.token3".toName() val name = Name.parse("token1.token2.token3")
assertEquals("token2", name[1].toString()) assertEquals("token2", name[1].toString())
} }
@Test @Test
fun equalityTest() { fun equalityTest() {
val name1 = "token1.token2[2].token3".toName() val name1 = Name.parse("token1.token2[2].token3")
val name2 = "token1".toName() + "token2[2].token3" val name2 = "token1".asName() + "token2[2].token3"
assertEquals(name1, name2) assertEquals(name1, name2)
} }
@Test @Test
fun comparisonTest(){ fun comparisonTest(){
val name1 = "token1.token2.token3".toName() val name1 = Name.parse("token1.token2.token3")
val name2 = "token1.token2".toName() val name2 = Name.parse("token1.token2")
val name3 = "token3".toName() val name3 = Name.parse("token3")
assertTrue { name1.startsWith(name2) } assertTrue { name1.startsWith(name2) }
assertTrue { name1.endsWith(name3) } assertTrue { name1.endsWith(name3) }
assertFalse { name1.startsWith(name3) } assertFalse { name1.startsWith(name3) }
@ -31,11 +31,11 @@ class NameTest {
@Test @Test
fun escapeTest(){ fun escapeTest(){
val escapedName = "token\\.one.token2".toName() val escapedName = Name.parse("token\\.one.token2")
val unescapedName = "token\\.one.token2".asName() val unescapedName = "token\\.one.token2".asName()
assertEquals(2, escapedName.length) assertEquals(2, escapedName.length)
assertEquals(1, unescapedName.length) assertEquals(1, unescapedName.length)
assertEquals(escapedName, escapedName.toString().toName()) assertEquals(escapedName, Name.parse(escapedName.toString()))
} }
} }

View File

@ -1,6 +1,5 @@
package space.kscience.dataforge.meta package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.values.Value import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue import space.kscience.dataforge.values.asValue
@ -8,7 +7,6 @@ import space.kscience.dataforge.values.isList
//TODO add Meta wrapper for dynamic //TODO add Meta wrapper for dynamic
@DFExperimental
public fun Value.toDynamic(): dynamic { public fun Value.toDynamic(): dynamic {
return if (isList()) { return if (isList()) {
list.map { it.toDynamic() }.toTypedArray().asDynamic() list.map { it.toDynamic() }.toTypedArray().asDynamic()
@ -20,7 +18,6 @@ public fun Value.toDynamic(): dynamic {
/** /**
* Represent or copy this [Meta] to dynamic object to be passed to JS libraries * Represent or copy this [Meta] to dynamic object to be passed to JS libraries
*/ */
@DFExperimental
public fun Meta.toDynamic(): dynamic { public fun Meta.toDynamic(): dynamic {
if (this is DynamicMeta) return this.obj if (this is DynamicMeta) return this.obj
if(items.isEmpty()) return value?.toDynamic() if(items.isEmpty()) return value?.toDynamic()
@ -36,7 +33,6 @@ public fun Meta.toDynamic(): dynamic {
return res return res
} }
@DFExperimental
public class DynamicMeta(internal val obj: dynamic) : TypedMeta<DynamicMeta> { public class DynamicMeta(internal val obj: dynamic) : TypedMeta<DynamicMeta> {
private fun keys(): Array<String> = js("Object").keys(obj) as Array<String> private fun keys(): Array<String> = js("Object").keys(obj) as Array<String>

View File

@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
@ -28,7 +27,7 @@ public interface Workspace : ContextAware, Provider {
override fun content(target: String): Map<Name, Any> { override fun content(target: String): Map<Name, Any> {
return when (target) { return when (target) {
"target", Meta.TYPE -> targets.mapKeys { it.key.toName() } "target", Meta.TYPE -> targets.mapKeys { Name.parse(it.key)}
Task.TYPE -> tasks Task.TYPE -> tasks
//Data.TYPE -> data.flow().toMap() //Data.TYPE -> data.flow().toMap()
else -> emptyMap() else -> emptyMap()
@ -50,10 +49,10 @@ public interface Workspace : ContextAware, Provider {
} }
public suspend fun Workspace.produce(task: String, target: String): TaskResult<*> = public suspend fun Workspace.produce(task: String, target: String): TaskResult<*> =
produce(task.toName(), targets[target] ?: error("Target with key $target not found in $this")) produce(Name.parse(task), targets[target] ?: error("Target with key $target not found in $this"))
public suspend fun Workspace.produce(task: String, meta: Meta): TaskResult<*> = public suspend fun Workspace.produce(task: String, meta: Meta): TaskResult<*> =
produce(task.toName(), meta) produce(Name.parse(task), meta)
public suspend fun Workspace.produce(task: String, block: MutableMeta.() -> Unit = {}): TaskResult<*> = public suspend fun Workspace.produce(task: String, block: MutableMeta.() -> Unit = {}): TaskResult<*> =
produce(task, Meta(block)) produce(task, Meta(block))

View File

@ -14,7 +14,6 @@ import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.toName
import kotlin.properties.PropertyDelegateProvider import kotlin.properties.PropertyDelegateProvider
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
@ -29,13 +28,13 @@ public inline fun <reified T : Any> TaskContainer.registerTask(
name: String, name: String,
noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {},
noinline builder: suspend TaskResultBuilder<T>.() -> Unit, noinline builder: suspend TaskResultBuilder<T>.() -> Unit,
): Unit = registerTask(name.toName(), Task(MetaDescriptor(descriptorBuilder), builder)) ): Unit = registerTask(Name.parse(name), Task(MetaDescriptor(descriptorBuilder), builder))
public inline fun <reified T : Any> TaskContainer.task( public inline fun <reified T : Any> TaskContainer.task(
noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {},
noinline builder: suspend TaskResultBuilder<T>.() -> Unit, noinline builder: suspend TaskResultBuilder<T>.() -> Unit,
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<T>>> = PropertyDelegateProvider { _, property -> ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<T>>> = PropertyDelegateProvider { _, property ->
val taskName = property.name.toName() val taskName = Name.parse(property.name)
val task = Task(MetaDescriptor(descriptorBuilder), builder) val task = Task(MetaDescriptor(descriptorBuilder), builder)
registerTask(taskName, task) registerTask(taskName, task)
ReadOnlyProperty { _, _ -> TaskReference(taskName, task) } ReadOnlyProperty { _, _ -> TaskReference(taskName, task) }

View File

@ -7,7 +7,6 @@ import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.context.PluginTag import space.kscience.dataforge.context.PluginTag
import space.kscience.dataforge.data.* import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.toName
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -25,7 +24,7 @@ class DataPropagationTestPlugin : WorkspacePlugin() {
val singleData by task<Int> { val singleData by task<Int> {
workspace.data.select<Int>().getData("myData[12]".toName())?.let { workspace.data.select<Int>().getData("myData[12]")?.let {
emit("result", it) emit("result", it)
} }
} }