Compare commits

...

3 Commits

Author SHA1 Message Date
79759c5256 Replace MetaProvider::getMeta by get 2023-11-22 17:06:23 +03:00
2eb965e563 Type -> DfId
Add descriptor to MetaConverter
2023-11-18 22:48:10 +03:00
1b29e377ca Type -> DfId
Add descriptor to MetaConverter
2023-11-18 22:43:53 +03:00
29 changed files with 205 additions and 150 deletions

View File

@ -3,6 +3,7 @@
## Unreleased ## Unreleased
### Added ### Added
- Obligatory `type: KType` and `descriptor` property for `MetaConverters`
- Added separate `Meta`, `SealedMeta` and `ObservableMutableMeta` builders. - Added separate `Meta`, `SealedMeta` and `ObservableMutableMeta` builders.
### Changed ### Changed
@ -11,6 +12,7 @@
- Migrated from ktor-io to kotlinx-io. - Migrated from ktor-io to kotlinx-io.
- `MutableMeta` builder now returns a simplified version of meta that does not hold listeners. - `MutableMeta` builder now returns a simplified version of meta that does not hold listeners.
- More concise names for read/write methods in IO. - More concise names for read/write methods in IO.
- Remove unnecessary confusion with `get`/`getMeta` by removing `getMeta` from the interface.
### Deprecated ### Deprecated
- `String.parseValue` is replaced with `Value.parse` - `String.parseValue` is replaced with `Value.parse`

View File

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

View File

@ -3,8 +3,8 @@ package space.kscience.dataforge.context
import space.kscience.dataforge.context.Plugin.Companion.TARGET import space.kscience.dataforge.context.Plugin.Companion.TARGET
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
@ -18,7 +18,7 @@ import space.kscience.dataforge.provider.Provider
* *
* create - configure - attach - detach - destroy * create - configure - attach - detach - destroy
*/ */
@Type(TARGET) @DfId(TARGET)
public interface Plugin : Named, ContextAware, Provider, MetaRepr { public interface Plugin : Named, ContextAware, Provider, MetaRepr {
/** /**

View File

@ -1,9 +1,9 @@
package space.kscience.dataforge.context package space.kscience.dataforge.context
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
@Type(PluginFactory.TYPE) @DfId(PluginFactory.TYPE)
public interface PluginFactory<T : Plugin> : Factory<T> { public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag public val tag: PluginTag

View File

@ -1,7 +1,8 @@
package space.kscience.dataforge.properties package space.kscience.dataforge.properties
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.transformations.MetaConverter import space.kscience.dataforge.meta.transformations.MetaConverter
import space.kscience.dataforge.meta.transformations.nullableMetaToObject import space.kscience.dataforge.meta.transformations.nullableMetaToObject
import space.kscience.dataforge.meta.transformations.nullableObjectToMeta import space.kscience.dataforge.meta.transformations.nullableObjectToMeta
@ -24,7 +25,7 @@ public class MetaProperty<T : Any>(
override fun onChange(owner: Any?, callback: (T?) -> Unit) { override fun onChange(owner: Any?, callback: (T?) -> Unit) {
meta.onChange(owner) { name -> meta.onChange(owner) { name ->
if (name.startsWith(this@MetaProperty.name)) callback(converter.nullableMetaToObject(get(name))) if (name.startsWith(this@MetaProperty.name)) callback(converter.nullableMetaToObject(this[name]))
} }
} }

View File

@ -4,29 +4,29 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.PluginBuilder import space.kscience.dataforge.context.PluginBuilder
import space.kscience.dataforge.context.gather import space.kscience.dataforge.context.gather
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
@DFExperimental @DFExperimental
public val KClass<*>.dfType: String public val KClass<*>.dfId: String
get() = findAnnotation<Type>()?.id ?: simpleName ?: "" get() = findAnnotation<DfId>()?.id ?: simpleName ?: ""
/** /**
* Provide an object with given name inferring target from its type using [Type] annotation * Provide an object with given name inferring target from its type using [DfId] annotation
*/ */
@DFExperimental @DFExperimental
public inline fun <reified T : Any> Provider.provideByType(name: String): T? { public inline fun <reified T : Any> Provider.provideByType(name: String): T? {
val target = T::class.dfType val target = T::class.dfId
return provide(target, name) return provide(target, name)
} }
@DFExperimental @DFExperimental
public inline fun <reified T : Any> Provider.top(): Map<Name, T> { public inline fun <reified T : Any> Provider.top(): Map<Name, T> {
val target = T::class.dfType val target = T::class.dfId
return top(target) return top(target)
} }
@ -35,15 +35,15 @@ public inline fun <reified T : Any> Provider.top(): Map<Name, T> {
*/ */
@DFExperimental @DFExperimental
public inline fun <reified T : Any> Context.gather(inherit: Boolean = true): Map<Name, T> = public inline fun <reified T : Any> Context.gather(inherit: Boolean = true): Map<Name, T> =
gather<T>(T::class.dfType, inherit) gather<T>(T::class.dfId, inherit)
@DFExperimental @DFExperimental
public inline fun <reified T : Any> PluginBuilder.provides(items: Map<Name, T>) { public inline fun <reified T : Any> PluginBuilder.provides(items: Map<Name, T>) {
provides(T::class.dfType, items) provides(T::class.dfId, items)
} }
@DFExperimental @DFExperimental
public inline fun <reified T : Any> PluginBuilder.provides(vararg items: Named) { public inline fun <reified T : Any> PluginBuilder.provides(vararg items: Named) {
provides(T::class.dfType, *items) provides(T::class.dfId, *items)
} }

View File

@ -5,7 +5,7 @@ import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType import kotlin.reflect.KType
@ -14,7 +14,7 @@ import kotlin.reflect.typeOf
/** /**
* A data element characterized by its meta * A data element characterized by its meta
*/ */
@Type(Data.TYPE) @DfId(Data.TYPE)
public interface Data<out T> : Goal<T>, MetaRepr { public interface Data<out T> : Goal<T>, MetaRepr {
/** /**
* Type marker for the data. The type is known before the calculation takes place so it could be checked. * Type marker for the data. The type is known before the calculation takes place so it could be checked.

View File

@ -6,7 +6,6 @@ import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.mapNotNull
import space.kscience.dataforge.data.Data.Companion.TYPE_OF_NOTHING import space.kscience.dataforge.data.Data.Companion.TYPE_OF_NOTHING
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.endsWith import space.kscience.dataforge.names.endsWith

View File

@ -2,7 +2,7 @@ package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
@ -31,7 +31,7 @@ public val <T : Any> DataTreeItem<T>.type: KType
/** /**
* A tree-like [DataSet] grouped into the node. All data inside the node must inherit its type * A tree-like [DataSet] grouped into the node. All data inside the node must inherit its type
*/ */
@Type(DataTree.TYPE) @DfId(DataTree.TYPE)
public interface DataTree<out T : Any> : DataSet<T> { public interface DataTree<out T : Any> : DataSet<T> {
/** /**

View File

@ -4,7 +4,7 @@ import kotlinx.io.Source
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.io.EnvelopeFormatFactory.Companion.ENVELOPE_FORMAT_TYPE import space.kscience.dataforge.io.EnvelopeFormatFactory.Companion.ENVELOPE_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import kotlin.reflect.KType import kotlin.reflect.KType
@ -17,7 +17,7 @@ public interface EnvelopeFormat : IOFormat<Envelope> {
public fun EnvelopeFormat.read(input: Source): Envelope = readFrom(input) public fun EnvelopeFormat.read(input: Source): Envelope = readFrom(input)
@Type(ENVELOPE_FORMAT_TYPE) @DfId(ENVELOPE_FORMAT_TYPE)
public interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat { public interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
override val type: KType get() = typeOf<Envelope>() override val type: KType get() = typeOf<Envelope>()

View File

@ -7,8 +7,8 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE import space.kscience.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.misc.Type
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import kotlin.reflect.KType import kotlin.reflect.KType
@ -72,7 +72,7 @@ public fun <T : Any> Sink.writeWith(format: IOWriter<T>, obj: T): Unit =
format.writeTo(this, obj) format.writeTo(this, obj)
@Type(IO_FORMAT_TYPE) @DfId(IO_FORMAT_TYPE)
public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named { public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named {
/** /**
* Explicit type for dynamic type checks * Explicit type for dynamic type checks

View File

@ -9,7 +9,7 @@ import space.kscience.dataforge.context.Global
import space.kscience.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE import space.kscience.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
@ -38,7 +38,7 @@ public interface MetaFormat : IOFormat<Meta> {
public fun readMeta(source: Source, descriptor: MetaDescriptor? = null): Meta public fun readMeta(source: Source, descriptor: MetaDescriptor? = null): Meta
} }
@Type(META_FORMAT_TYPE) @DfId(META_FORMAT_TYPE)
public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat { public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
public val shortName: String public val shortName: String

View File

@ -1,7 +1,6 @@
package space.kscience.dataforge.io package space.kscience.dataforge.io
import space.kscience.dataforge.context.ContextBuilder import space.kscience.dataforge.context.ContextBuilder
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.set import space.kscience.dataforge.meta.set
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import java.nio.file.Path import java.nio.file.Path

View File

@ -17,8 +17,8 @@ public class Laminate internal constructor(public val layers: List<Meta>) : Type
} }
} }
override fun getMeta(name: Name): Laminate? { override fun get(name: Name): Laminate? {
val childLayers = layers.mapNotNull { it.getMeta(name) } val childLayers = layers.mapNotNull { it.get(name) }
return if (childLayers.isEmpty()) null else Laminate(childLayers) return if (childLayers.isEmpty()) null else Laminate(childLayers)
} }

View File

@ -2,7 +2,7 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.unsafeCast import space.kscience.dataforge.misc.unsafeCast
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
@ -21,9 +21,9 @@ public interface MetaRepr {
* A container for meta nodes * A container for meta nodes
*/ */
public fun interface MetaProvider : ValueProvider { public fun interface MetaProvider : ValueProvider {
public fun getMeta(name: Name): Meta? public operator fun get(name: Name): Meta?
override fun getValue(name: Name): Value? = getMeta(name)?.value override fun getValue(name: Name): Value? = get(name)?.value
} }
/** /**
@ -31,13 +31,13 @@ public fun interface MetaProvider : ValueProvider {
* TODO add documentation * TODO add documentation
* Same name siblings are supported via elements with the same [Name] but different indices. * Same name siblings are supported via elements with the same [Name] but different indices.
*/ */
@Type(Meta.TYPE) @DfId(Meta.TYPE)
@Serializable(MetaSerializer::class) @Serializable(MetaSerializer::class)
public interface Meta : MetaRepr, MetaProvider { 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? { override fun get(name: Name): Meta? {
tailrec fun Meta.find(name: Name): Meta? = if (name.isEmpty()) { tailrec fun Meta.find(name: Name): Meta? = if (name.isEmpty()) {
this this
} else { } else {
@ -108,21 +108,13 @@ 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 operator fun Meta?.get(name: Name): Meta? = this?.getMeta(name) public operator fun Meta?.get(name: Name): Meta? = this?.get(name)
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun Meta.get(name: Name): Meta? = getMeta(name)
/** /**
* 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?.get(key.parseAsName(true)) public operator fun Meta?.get(key: String): Meta? = this?.get(key.parseAsName(true))
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun Meta.get(key: String): Meta? = get(key.parseAsName(true))
/** /**
* Get all items matching given name. The index of the last element, if present is used as a [Regex], * Get all items matching given name. The index of the last element, if present is used as a [Regex],
* against which indexes of elements are matched. * against which indexes of elements are matched.
@ -159,7 +151,7 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta {
override val items: Map<NameToken, M> override val items: Map<NameToken, M>
override fun getMeta(name: Name): M? { override fun get(name: Name): M? {
tailrec fun M.find(name: Name): M? = if (name.isEmpty()) { tailrec fun M.find(name: Name): M? = if (name.isEmpty()) {
this this
} else { } else {
@ -182,28 +174,17 @@ public inline val <M : TypedMeta<M>> TypedMeta<M>.self: M get() = unsafeCast()
public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token) public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token)
/** /**
* Perform recursive item search using given [name]. Each [NameToken] is treated as a name in [TypedMeta.items] of a parent node. * Retrieves a meta node with the given name from the nullable [TypedMeta] object.
* *
* If [name] is empty return current [Meta] * @param name The name of the meta node to retrieve.
* @return The meta node with the given name, or null if it doesn't exist.
*/ */
public tailrec operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(name: Name): M? = when { public operator fun <M : TypedMeta<M>> M?.get(name: Name): M? = this?.get(name)
this == null -> null
name.isEmpty() -> self
else -> get(name.firstOrNull()!!)?.get(name.cutFirst())
}
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(name: Name): M? = get(name)
/** /**
* 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.parseAsName(true)] public operator fun <M : TypedMeta<M>> M?.get(key: String): M? = this?.get(key.parseAsName(true))
@Deprecated("Use nullable receiver", level = DeprecationLevel.HIDDEN)
@JvmName("getNonNullable")
public operator fun <M : TypedMeta<M>> TypedMeta<M>.get(key: String): M? = get(key)
/** /**

View File

@ -8,28 +8,28 @@ import kotlin.properties.ReadOnlyProperty
/* Meta delegates */ /* Meta delegates */
public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = ReadOnlyProperty { _, property -> public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = ReadOnlyProperty { _, property ->
getMeta(key ?: property.name.asName()) get(key ?: property.name.asName())
} }
public fun <T> MetaProvider.node( public fun <T> MetaProvider.node(
key: Name? = null, key: Name? = null,
converter: MetaConverter<T> converter: MetaConverter<T>
): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property -> ): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property ->
getMeta(key ?: property.name.asName())?.let { converter.metaToObject(it) } get(key ?: property.name.asName())?.let { converter.metaToObject(it) }
} }
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
public fun MetaProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = ReadOnlyProperty { _, property -> public fun MetaProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = ReadOnlyProperty { _, property ->
getMeta(key ?: property.name.asName())?.value get(key ?: property.name.asName())?.value
} }
public fun <R> MetaProvider.value( public fun <R> MetaProvider.value(
key: Name? = null, key: Name? = null,
reader: (Value?) -> R reader: (Value?) -> R
): ReadOnlyProperty<Any?, R> = ReadOnlyProperty { _, property -> ): ReadOnlyProperty<Any?, R> = ReadOnlyProperty { _, property ->
reader(getMeta(key ?: property.name.asName())?.value) reader(get(key ?: property.name.asName())?.value)
} }
//TODO add caching for sealed nodes //TODO add caching for sealed nodes

View File

@ -17,8 +17,8 @@ public annotation class MetaBuilderMarker
* A generic interface that gives access to getting and setting meta notes and values * A generic interface that gives access to getting and setting meta notes and values
*/ */
public interface MutableMetaProvider : MetaProvider, MutableValueProvider { public interface MutableMetaProvider : MetaProvider, MutableValueProvider {
override fun getMeta(name: Name): MutableMeta? override fun get(name: Name): MutableMeta?
public fun setMeta(name: Name, node: Meta?) public operator fun set(name: Name, node: Meta?)
override fun setValue(name: Name, value: Value?) override fun setValue(name: Name, value: Value?)
} }
@ -37,7 +37,7 @@ public interface MutableMeta : Meta, MutableMetaProvider {
*/ */
override var value: Value? override var value: Value?
override fun getMeta(name: Name): MutableMeta? { override fun get(name: Name): MutableMeta? {
tailrec fun MutableMeta.find(name: Name): MutableMeta? = if (name.isEmpty()) { tailrec fun MutableMeta.find(name: Name): MutableMeta? = if (name.isEmpty()) {
this this
} else { } else {
@ -83,11 +83,11 @@ public interface MutableMeta : Meta, MutableMetaProvider {
} }
public infix fun Name.put(meta: Meta) { public infix fun Name.put(meta: Meta) {
setMeta(this, meta) set(this, meta)
} }
public infix fun Name.put(repr: MetaRepr) { public infix fun Name.put(repr: MetaRepr) {
setMeta(this, repr.toMeta()) set(this, repr.toMeta())
} }
public infix fun Name.put(builder: MutableMeta.() -> Unit) { public infix fun Name.put(builder: MutableMeta.() -> Unit) {
@ -95,7 +95,7 @@ public interface MutableMeta : Meta, MutableMetaProvider {
} }
public infix fun String.put(meta: Meta) { public infix fun String.put(meta: Meta) {
setMeta(Name.parse(this), meta) set(Name.parse(this), meta)
} }
public infix fun String.put(value: Value?) { public infix fun String.put(value: Value?) {
@ -123,7 +123,7 @@ public interface MutableMeta : Meta, MutableMetaProvider {
} }
public infix fun String.put(repr: MetaRepr) { public infix fun String.put(repr: MetaRepr) {
setMeta(Name.parse(this), repr.toMeta()) set(Name.parse(this), repr.toMeta())
} }
public infix fun String.putIndexed(iterable: Iterable<Meta>) { public infix fun String.putIndexed(iterable: Iterable<Meta>) {
@ -135,11 +135,6 @@ public interface MutableMeta : Meta, MutableMetaProvider {
} }
} }
/**
* Set or replace node at given [name]
*/
public operator fun MutableMetaProvider.set(name: Name, meta: Meta): Unit = setMeta(name, meta)
/** /**
* Set or replace value at given [name] * Set or replace value at given [name]
*/ */
@ -154,24 +149,24 @@ public interface MutableTypedMeta<M : MutableTypedMeta<M>> : TypedMeta<M>, Mutab
*/ */
@DFExperimental @DFExperimental
public fun attach(name: Name, node: M) public fun attach(name: Name, node: M)
override fun getMeta(name: Name): M? override fun get(name: Name): M?
override fun getOrCreate(name: Name): M override fun getOrCreate(name: Name): M
} }
public fun <M : MutableTypedMeta<M>> M.getOrCreate(key: String): M = getOrCreate(Name.parse(key)) public fun <M : MutableTypedMeta<M>> M.getOrCreate(key: String): M = getOrCreate(Name.parse(key))
public fun MutableMetaProvider.remove(name: Name) { public fun MutableMetaProvider.remove(name: Name) {
setMeta(name, null) set(name, null)
} }
public fun MutableMetaProvider.remove(key: String) { public fun MutableMetaProvider.remove(key: String) {
setMeta(Name.parse(key), null) set(Name.parse(key), null)
} }
// node setters // node setters
public operator fun MutableMetaProvider.set(Key: NameToken, value: Meta): Unit = setMeta(Key.asName(), value) public operator fun MutableMetaProvider.set(Key: NameToken, value: Meta): Unit = set(Key.asName(), value)
public operator fun MutableMetaProvider.set(key: String, value: Meta): Unit = setMeta(Name.parse(key), value) public operator fun MutableMetaProvider.set(key: String, value: Meta): Unit = set(Name.parse(key), value)
//public fun MutableMeta.set(key: String, index: String, value: Value?): Unit = //public fun MutableMeta.set(key: String, index: String, value: Value?): Unit =
@ -319,7 +314,7 @@ private class MutableMetaImpl(
) )
@ThreadSafe @ThreadSafe
override fun setMeta(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
val oldItem: ObservableMutableMeta? = get(name) val oldItem: ObservableMutableMeta? = get(name)
if (oldItem != node) { if (oldItem != node) {
when (name.length) { when (name.length) {
@ -346,7 +341,7 @@ private class MutableMetaImpl(
newNode.adoptBy(this, token) newNode.adoptBy(this, token)
children[token] = newNode children[token] = newNode
} }
items[token]?.setMeta(name.cutFirst(), node) items[token]?.set(name.cutFirst(), node)
} }
} }
invalidate(name) invalidate(name)
@ -405,7 +400,7 @@ private class MutableMetaWithDefault(
override val items: Map<NameToken, MutableMeta> override val items: Map<NameToken, MutableMeta>
get() { get() {
val sourceKeys: Collection<NameToken> = source[rootName]?.items?.keys ?: emptyList() val sourceKeys: Collection<NameToken> = source[rootName]?.items?.keys ?: emptyList()
val defaultKeys: Collection<NameToken> = default.getMeta(rootName)?.items?.keys ?: emptyList() val defaultKeys: Collection<NameToken> = default[rootName]?.items?.keys ?: emptyList()
//merging keys for primary and default node //merging keys for primary and default node
return (sourceKeys + defaultKeys).associateWith { return (sourceKeys + defaultKeys).associateWith {
MutableMetaWithDefault(source, default, rootName + it) MutableMetaWithDefault(source, default, rootName + it)
@ -413,12 +408,12 @@ private class MutableMetaWithDefault(
} }
override var value: Value? override var value: Value?
get() = source[rootName]?.value ?: default.getMeta(rootName)?.value get() = source[rootName]?.value ?: default.get(rootName)?.value
set(value) { set(value) {
source[rootName] = value source[rootName] = value
} }
override fun getMeta(name: Name): MutableMeta = MutableMetaWithDefault(source, default, rootName + name) override fun get(name: Name): MutableMeta = MutableMetaWithDefault(source, default, rootName + 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)

View File

@ -11,31 +11,31 @@ import kotlin.reflect.KProperty
public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> =
object : ReadWriteProperty<Any?, Meta?> { object : ReadWriteProperty<Any?, Meta?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? {
return getMeta(key ?: property.name.asName()) return get(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()
setMeta(name, value) set(name, value)
} }
} }
public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConverter<T>): ReadWriteProperty<Any?, T?> = public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConverter<T>): ReadWriteProperty<Any?, T?> =
object : ReadWriteProperty<Any?, T?> { object : ReadWriteProperty<Any?, T?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T? { override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return getMeta(key ?: property.name.asName())?.let { converter.metaToObject(it) } return get(key ?: property.name.asName())?.let { converter.metaToObject(it) }
} }
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
val name = key ?: property.name.asName() val name = key ?: property.name.asName()
setMeta(name, value?.let { converter.objectToMeta(it) }) set(name, value?.let { converter.objectToMeta(it) })
} }
} }
public fun MutableMetaProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> = public fun MutableMetaProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
object : ReadWriteProperty<Any?, Value?> { object : ReadWriteProperty<Any?, Value?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
getMeta(key ?: property.name.asName())?.value get(key ?: property.name.asName())?.value
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
setValue(key ?: property.name.asName(), value) setValue(key ?: property.name.asName(), value)
@ -48,7 +48,7 @@ public fun <T> MutableMetaProvider.value(
reader: (Value?) -> T reader: (Value?) -> T
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> { ): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T = override fun getValue(thisRef: Any?, property: KProperty<*>): T =
reader(getMeta(key ?: property.name.asName())?.value) reader(get(key ?: property.name.asName())?.value)
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
setValue(key ?: property.name.asName(), writer(value)) setValue(key ?: property.name.asName(), writer(value))

View File

@ -36,7 +36,7 @@ public interface ObservableMeta : Meta {
public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> { public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> {
override fun getOrCreate(name: Name): ObservableMutableMeta override fun getOrCreate(name: Name): ObservableMutableMeta
override fun getMeta(name: Name): ObservableMutableMeta? { override fun get(name: Name): ObservableMutableMeta? {
tailrec fun ObservableMutableMeta.find(name: Name): ObservableMutableMeta? = if (name.isEmpty()) { tailrec fun ObservableMutableMeta.find(name: Name): ObservableMutableMeta? = if (name.isEmpty()) {
this this
} else { } else {

View File

@ -17,8 +17,8 @@ private class ObservableMetaWrapper(
ObservableMetaWrapper(root, absoluteName + it, listeners) ObservableMetaWrapper(root, absoluteName + it, listeners)
} }
override fun getMeta(name: Name): ObservableMutableMeta? = override fun get(name: Name): ObservableMutableMeta? =
root.getMeta(name)?.let { ObservableMetaWrapper(root, this.absoluteName + name, listeners) } root.get(name)?.let { ObservableMetaWrapper(root, this.absoluteName + name, listeners) }
@ThreadSafe @ThreadSafe
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) { override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
@ -49,11 +49,11 @@ private class ObservableMetaWrapper(
override fun getOrCreate(name: Name): ObservableMutableMeta = override fun getOrCreate(name: Name): ObservableMutableMeta =
ObservableMetaWrapper(root, this.absoluteName + name, listeners) ObservableMetaWrapper(root, this.absoluteName + name, listeners)
override fun setMeta(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
val oldMeta = get(name) val oldMeta = get(name)
//don't forget to remove listener //don't forget to remove listener
oldMeta?.removeListener(this) oldMeta?.removeListener(this)
root.setMeta(absoluteName + name, node) root.set(absoluteName + name, node)
if (oldMeta != node) { if (oldMeta != node) {
invalidate(name) invalidate(name)
} }
@ -69,7 +69,7 @@ private class ObservableMetaWrapper(
override fun attach(name: Name, node: ObservableMutableMeta) { override fun attach(name: Name, node: ObservableMutableMeta) {
set(name, node) set(name, node)
node.onChange(this) { changeName -> node.onChange(this) { changeName ->
setMeta(name + changeName, this[changeName]) set(name + changeName, this[changeName])
} }
} }
} }

View File

@ -47,11 +47,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
return descriptor?.validate(meta) ?: true return descriptor?.validate(meta) ?: true
} }
override fun getMeta(name: Name): MutableMeta? = meta.getMeta(name) override fun get(name: Name): MutableMeta? = meta.get(name)
override fun setMeta(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
if (validate(name, meta)) { if (validate(name, meta)) {
meta.setMeta(name, node) meta.set(name, node)
} else { } else {
error("Validation failed for node $node at $name") error("Validation failed for node $node at $name")
} }
@ -110,8 +110,8 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
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)
override fun setMeta(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
targetMeta.setMeta(name, node) targetMeta.set(name, node)
invalidate(name) invalidate(name)
} }
@ -120,9 +120,9 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
@DFExperimental @DFExperimental
override fun attach(name: Name, node: ObservableMutableMeta) { override fun attach(name: Name, node: ObservableMutableMeta) {
//TODO implement zero-copy attachment //TODO implement zero-copy attachment
setMeta(name, node) set(name, node)
node.onChange(this) { changeName -> node.onChange(this) { changeName ->
setMeta(name + changeName, this[changeName]) set(name + changeName, this[changeName])
} }
} }

View File

@ -62,7 +62,7 @@ internal class MetaBuilder(
val existing = get(name) as? MetaBuilder val existing = get(name) as? MetaBuilder
return if (existing == null) { return if (existing == null) {
val newItem = MetaBuilder() val newItem = MetaBuilder()
setMeta(name, newItem) set(name, newItem)
newItem newItem
} else { } else {
existing existing
@ -75,7 +75,7 @@ internal class MetaBuilder(
) )
override fun setMeta(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
when (name.length) { when (name.length) {
0 -> error("Can't set a meta with empty name") 0 -> error("Can't set a meta with empty name")
1 -> { 1 -> {
@ -89,7 +89,7 @@ internal class MetaBuilder(
} }
else -> { else -> {
getOrCreate(name.first().asName()).setMeta(name.cutFirst(), node) getOrCreate(name.first().asName()).set(name.cutFirst(), node)
} }
} }
} }

View File

@ -7,7 +7,7 @@ import space.kscience.dataforge.names.*
/** /**
* Restrictions on value in the node * Restrictions on value in the node
*/ */
public enum class ValueRequirement { public enum class ValueRestriction {
/** /**
* No restrictions * No restrictions
*/ */
@ -26,26 +26,25 @@ public enum class ValueRequirement {
/** /**
* The descriptor for a meta * The descriptor for a meta
* @param info description text * @param description description text
* @param children child descriptors for this node * @param children child descriptors for this node
* @param multiple True if same name siblings with this name are allowed * @param multiple True if same name siblings with this name are allowed
* @param valueRequirement The requirements for node content * @param valueRestriction The requirements for node content
* @param valueTypes list of allowed types for [Meta.value], null if all values are allowed. * @param valueTypes list of allowed types for [Meta.value], null if all values are allowed.
* Empty list means that no value should be present in this node. * Empty list means that no value should be present in this node.
* @param indexKey An index field by which this node is identified in case of same name siblings construct * @param indexKey An index field by which this node is identified in case of same name siblings construct
* @param defaultValue the default [Meta.value] for the node * @param defaultValue the default [Meta.value] for the node
* @param attributes additional attributes of this descriptor. For example validation and widget parameters * @param attributes additional attributes of this descriptor. For example, validation and widget parameters
*/ */
@Serializable @Serializable
public data class MetaDescriptor( public data class MetaDescriptor(
public val info: String? = null, public val description: String? = null,
public val children: Map<String, MetaDescriptor> = emptyMap(), public val children: Map<String, MetaDescriptor> = emptyMap(),
public val multiple: Boolean = false, public val multiple: Boolean = false,
public val valueRequirement: ValueRequirement = ValueRequirement.NONE, public val valueRestriction: ValueRestriction = ValueRestriction.NONE,
public val valueTypes: List<ValueType>? = null, public val valueTypes: List<ValueType>? = null,
public val indexKey: String = Meta.INDEX_KEY, public val indexKey: String = Meta.INDEX_KEY,
public val defaultValue: Value? = null, public val defaultValue: Value? = null,
public val readOnly: Boolean = false,
public val attributes: Meta = Meta.EMPTY, public val attributes: Meta = Meta.EMPTY,
) { ) {
/** /**
@ -63,11 +62,12 @@ public data class MetaDescriptor(
} }
public companion object { public companion object {
public val EMPTY: MetaDescriptor = MetaDescriptor("Generic meta tree")
internal const val ALLOWED_VALUES_KEY = "allowedValues" internal const val ALLOWED_VALUES_KEY = "allowedValues"
} }
} }
public val MetaDescriptor.required: Boolean get() = valueRequirement == ValueRequirement.REQUIRED || children.values.any { required } public val MetaDescriptor.required: Boolean get() = valueRestriction == ValueRestriction.REQUIRED || children.values.any { required }
public val MetaDescriptor.allowedValues: List<Value>? get() = attributes[MetaDescriptor.ALLOWED_VALUES_KEY]?.value?.list public val MetaDescriptor.allowedValues: List<Value>? get() = attributes[MetaDescriptor.ALLOWED_VALUES_KEY]?.value?.list
@ -80,9 +80,9 @@ public operator fun MetaDescriptor.get(name: Name): MetaDescriptor? = when (name
public operator fun MetaDescriptor.get(name: String): MetaDescriptor? = get(name.parseAsName(true)) public operator fun MetaDescriptor.get(name: String): MetaDescriptor? = get(name.parseAsName(true))
public fun MetaDescriptor.validate(value: Value?): Boolean = if (value == null) { public fun MetaDescriptor.validate(value: Value?): Boolean = if (value == null) {
valueRequirement != ValueRequirement.REQUIRED valueRestriction != ValueRestriction.REQUIRED
} else { } else {
if (valueRequirement == ValueRequirement.ABSENT) false if (valueRestriction == ValueRestriction.ABSENT) false
else { else {
(valueTypes == null || value.type in valueTypes) && (allowedValues?.let { value in it } ?: true) (valueTypes == null || value.type in valueTypes) && (allowedValues?.let { value in it } ?: true)
} }

View File

@ -8,20 +8,26 @@ import space.kscience.dataforge.names.first
import space.kscience.dataforge.names.length import space.kscience.dataforge.names.length
import kotlin.collections.set import kotlin.collections.set
public class MetaDescriptorBuilder @PublishedApi internal constructor() { public class MetaDescriptorBuilder @PublishedApi internal constructor() {
public var info: String? = null public var info: String? = null
public var children: MutableMap<String, MetaDescriptorBuilder> = linkedMapOf() public var children: MutableMap<String, MetaDescriptorBuilder> = linkedMapOf()
public var multiple: Boolean = false public var multiple: Boolean = false
public var valueRequirement: ValueRequirement = ValueRequirement.NONE public var valueRestriction: ValueRestriction = ValueRestriction.NONE
public var readOnly: Boolean = false
public var type: List<ValueType>? = null public var valueTypes: List<ValueType>? = null
public fun type(primaryType: ValueType, vararg otherTypes: ValueType) { public fun valueType(primaryType: ValueType, vararg otherTypes: ValueType) {
type = listOf(primaryType, *otherTypes) valueTypes = listOf(primaryType, *otherTypes)
} }
/**
* A key for indexing values. Should be changed in case of the name clash.
*/
public var indexKey: String = Meta.INDEX_KEY public var indexKey: String = Meta.INDEX_KEY
/**
* The default value
*/
public var default: Value? = null public var default: Value? = null
public fun default(value: Any?) { public fun default(value: Any?) {
@ -42,6 +48,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
children[name.first().body] = target children[name.first().body] = target
target target
} }
else -> { else -> {
children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), block) children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), block)
} }
@ -51,16 +58,17 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
public fun node( public fun node(
name: Name, name: Name,
descriptor: MetaDescriptor, descriptor: MetaDescriptor,
block: MetaDescriptorBuilder.() -> Unit = {} block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = when (name.length) { ): MetaDescriptorBuilder = when (name.length) {
0 -> error("Can't set descriptor to root") 0 -> error("Can't set descriptor to root")
1 -> { 1 -> {
val item = descriptor.toBuilder().apply { val item = descriptor.toBuilder().apply {
valueRequirement = ValueRequirement.ABSENT valueRestriction = ValueRestriction.ABSENT
}.apply(block) }.apply(block)
children[name.first().body] = item children[name.first().body] = item
item item
} }
else -> children.getOrPut(name.first().body) { else -> children.getOrPut(name.first().body) {
MetaDescriptorBuilder() MetaDescriptorBuilder()
}.node(name.cutFirst(), descriptor, block) }.node(name.cutFirst(), descriptor, block)
@ -79,14 +87,13 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
@PublishedApi @PublishedApi
internal fun build(): MetaDescriptor = MetaDescriptor( internal fun build(): MetaDescriptor = MetaDescriptor(
info = info, description = info,
children = children.mapValues { it.value.build() }, children = children.mapValues { it.value.build() },
multiple = multiple, multiple = multiple,
valueRequirement = valueRequirement, valueRestriction = valueRestriction,
valueTypes = type, valueTypes = valueTypes,
indexKey = indexKey, indexKey = indexKey,
defaultValue = default, defaultValue = default,
readOnly = readOnly,
attributes = attributes attributes = attributes
) )
} }
@ -104,9 +111,9 @@ public fun MetaDescriptorBuilder.value(
name: Name, name: Name,
type: ValueType, type: ValueType,
vararg additionalTypes: ValueType, vararg additionalTypes: ValueType,
block: MetaDescriptorBuilder.() -> Unit = {} block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = item(name) { ): MetaDescriptorBuilder = item(name) {
type(type, *additionalTypes) valueType(type, *additionalTypes)
block() block()
} }
@ -114,16 +121,16 @@ public fun MetaDescriptorBuilder.value(
name: String, name: String,
type: ValueType, type: ValueType,
vararg additionalTypes: ValueType, vararg additionalTypes: ValueType,
block: MetaDescriptorBuilder.() -> Unit = {} block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = value(Name.parse(name), type, additionalTypes = additionalTypes, block) ): MetaDescriptorBuilder = value(Name.parse(name), type, additionalTypes = additionalTypes, block)
/** /**
* Create and configure child value descriptor * Create and configure child value descriptor
*/ */
public fun MetaDescriptorBuilder.node( public fun MetaDescriptorBuilder.node(
name: Name, block: MetaDescriptorBuilder.() -> Unit name: Name, block: MetaDescriptorBuilder.() -> Unit,
): MetaDescriptorBuilder = item(name) { ): MetaDescriptorBuilder = item(name) {
valueRequirement = ValueRequirement.ABSENT valueRestriction = ValueRestriction.ABSENT
block() block()
} }
@ -142,7 +149,7 @@ public fun MetaDescriptorBuilder.node(
} }
public fun MetaDescriptorBuilder.required() { public fun MetaDescriptorBuilder.required() {
valueRequirement = ValueRequirement.REQUIRED valueRestriction = ValueRestriction.REQUIRED
} }
public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum( public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
@ -158,11 +165,11 @@ public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
} }
private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply { private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
info = this@toBuilder.info info = this@toBuilder.description
children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() } children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
multiple = this@toBuilder.multiple multiple = this@toBuilder.multiple
valueRequirement = this@toBuilder.valueRequirement valueRestriction = this@toBuilder.valueRestriction
type = this@toBuilder.valueTypes valueTypes = this@toBuilder.valueTypes
indexKey = this@toBuilder.indexKey indexKey = this@toBuilder.indexKey
default = defaultValue default = defaultValue
attributes = this@toBuilder.attributes.toMutableMeta() attributes = this@toBuilder.attributes.toMutableMeta()

View File

@ -1,12 +1,25 @@
package space.kscience.dataforge.meta.transformations package space.kscience.dataforge.meta.transformations
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/** /**
* A converter of generic object to and from [Meta] * A converter of generic object to and from [Meta]
*/ */
public interface MetaConverter<T> { public interface MetaConverter<T> {
/**
* Runtime type of [T]
*/
public val type: KType
/**
* A descriptor for resulting meta
*/
public val descriptor: MetaDescriptor get() = MetaDescriptor.EMPTY
/** /**
* Attempt conversion of [meta] to an object or return null if conversion failed * Attempt conversion of [meta] to an object or return null if conversion failed
*/ */
@ -20,51 +33,105 @@ public interface MetaConverter<T> {
public companion object { public companion object {
public val meta: MetaConverter<Meta> = object : MetaConverter<Meta> { public val meta: MetaConverter<Meta> = object : MetaConverter<Meta> {
override val type: KType = typeOf<Meta>()
override fun metaToObjectOrNull(meta: Meta): Meta = meta override fun metaToObjectOrNull(meta: Meta): Meta = meta
override fun objectToMeta(obj: Meta): Meta = obj override fun objectToMeta(obj: Meta): Meta = obj
} }
public val value: MetaConverter<Value> = object : MetaConverter<Value> { public val value: MetaConverter<Value> = object : MetaConverter<Value> {
override val type: KType = typeOf<Value>()
override fun metaToObjectOrNull(meta: Meta): Value? = meta.value override fun metaToObjectOrNull(meta: Meta): Value? = meta.value
override fun objectToMeta(obj: Value): Meta = Meta(obj) override fun objectToMeta(obj: Value): Meta = Meta(obj)
} }
public val string: MetaConverter<String> = object : MetaConverter<String> { public val string: MetaConverter<String> = object : MetaConverter<String> {
override val type: KType = typeOf<String>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.STRING)
}
override fun metaToObjectOrNull(meta: Meta): String? = meta.string override fun metaToObjectOrNull(meta: Meta): String? = meta.string
override fun objectToMeta(obj: String): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: String): Meta = Meta(obj.asValue())
} }
public val boolean: MetaConverter<Boolean> = object : MetaConverter<Boolean> { public val boolean: MetaConverter<Boolean> = object : MetaConverter<Boolean> {
override val type: KType = typeOf<Boolean>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.BOOLEAN)
}
override fun metaToObjectOrNull(meta: Meta): Boolean? = meta.boolean override fun metaToObjectOrNull(meta: Meta): Boolean? = meta.boolean
override fun objectToMeta(obj: Boolean): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Boolean): Meta = Meta(obj.asValue())
} }
public val number: MetaConverter<Number> = object : MetaConverter<Number> { public val number: MetaConverter<Number> = object : MetaConverter<Number> {
override val type: KType = typeOf<Number>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun metaToObjectOrNull(meta: Meta): Number? = meta.number override fun metaToObjectOrNull(meta: Meta): Number? = meta.number
override fun objectToMeta(obj: Number): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Number): Meta = Meta(obj.asValue())
} }
public val double: MetaConverter<Double> = object : MetaConverter<Double> { public val double: MetaConverter<Double> = object : MetaConverter<Double> {
override val type: KType = typeOf<Double>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun metaToObjectOrNull(meta: Meta): Double? = meta.double override fun metaToObjectOrNull(meta: Meta): Double? = meta.double
override fun objectToMeta(obj: Double): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Double): Meta = Meta(obj.asValue())
} }
public val float: MetaConverter<Float> = object : MetaConverter<Float> { public val float: MetaConverter<Float> = object : MetaConverter<Float> {
override val type: KType = typeOf<Float>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun metaToObjectOrNull(meta: Meta): Float? = meta.float override fun metaToObjectOrNull(meta: Meta): Float? = meta.float
override fun objectToMeta(obj: Float): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Float): Meta = Meta(obj.asValue())
} }
public val int: MetaConverter<Int> = object : MetaConverter<Int> { public val int: MetaConverter<Int> = object : MetaConverter<Int> {
override val type: KType = typeOf<Int>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun metaToObjectOrNull(meta: Meta): Int? = meta.int override fun metaToObjectOrNull(meta: Meta): Int? = meta.int
override fun objectToMeta(obj: Int): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Int): Meta = Meta(obj.asValue())
} }
public val long: MetaConverter<Long> = object : MetaConverter<Long> { public val long: MetaConverter<Long> = object : MetaConverter<Long> {
override val type: KType = typeOf<Long>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun metaToObjectOrNull(meta: Meta): Long? = meta.long override fun metaToObjectOrNull(meta: Meta): Long? = meta.long
override fun objectToMeta(obj: Long): Meta = Meta(obj.asValue()) override fun objectToMeta(obj: Long): Meta = Meta(obj.asValue())
} }
public inline fun <reified E : Enum<E>> enum(): MetaConverter<E> = object : MetaConverter<E> { public inline fun <reified E : Enum<E>> enum(): MetaConverter<E> = object : MetaConverter<E> {
override val type: KType = typeOf<E>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.STRING)
allowedValues(enumValues<E>())
}
@Suppress("USELESS_CAST") @Suppress("USELESS_CAST")
override fun metaToObjectOrNull(meta: Meta): E = meta.enum<E>() as? E ?: error("The Item is not a Enum") override fun metaToObjectOrNull(meta: Meta): E = meta.enum<E>() as? E ?: error("The Item is not a Enum")
@ -76,6 +143,12 @@ public interface MetaConverter<T> {
reader: (Value) -> T, reader: (Value) -> T,
): MetaConverter<List<T>> = ): MetaConverter<List<T>> =
object : MetaConverter<List<T>> { object : MetaConverter<List<T>> {
override val type: KType = typeOf<List<T>>()
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.LIST)
}
override fun metaToObjectOrNull(meta: Meta): List<T>? = meta.value?.list?.map(reader) override fun metaToObjectOrNull(meta: Meta): List<T>? = meta.value?.list?.map(reader)
override fun objectToMeta(obj: List<T>): Meta = Meta(obj.map(writer).asValue()) override fun objectToMeta(obj: List<T>): Meta = Meta(obj.map(writer).asValue())

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.setMeta(name, item) if (selector(name)) target.set(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 ->
setMeta(name, Meta) set(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 ->
setMeta(to, operation(item)) set(to, operation(item))
} }
) )
} }

View File

@ -2,9 +2,7 @@ package space.kscience.dataforge.misc
/** /**
* A text label for internal DataForge type classification. Alternative for mime container type. * A text label for internal DataForge type classification. Alternative for mime container type.
*
* The DataForge type notation presumes that type `A.B.C` is the subtype of `A.B`
*/ */
@MustBeDocumented @MustBeDocumented
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
public annotation class Type(val id: String) public annotation class DfId(val id: String)

View File

@ -9,7 +9,7 @@ import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.Specification import space.kscience.dataforge.meta.Specification
import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.Described
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.Type import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.workspace.Task.Companion.TYPE import space.kscience.dataforge.workspace.Task.Companion.TYPE
import kotlin.reflect.KType import kotlin.reflect.KType
@ -19,7 +19,7 @@ import kotlin.reflect.typeOf
* A configurable task that could be executed on a workspace. The [TaskResult] represents a lazy result of the task. * A configurable task that could be executed on a workspace. The [TaskResult] represents a lazy result of the task.
* In general no computations should be made until the result is called. * In general no computations should be made until the result is called.
*/ */
@Type(TYPE) @DfId(TYPE)
public interface Task<out T : Any> : Described { public interface Task<out T : Any> : Described {
/** /**

View File

@ -6,7 +6,7 @@ import space.kscience.dataforge.data.DataSet
import space.kscience.dataforge.data.asSequence import space.kscience.dataforge.data.asSequence
import space.kscience.dataforge.meta.Meta 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.DfId
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
@ -18,7 +18,7 @@ public interface DataSelector<T: Any>{
/** /**
* An environment for pull-mode computation * An environment for pull-mode computation
*/ */
@Type(Workspace.TYPE) @DfId(Workspace.TYPE)
public interface Workspace : ContextAware, Provider { public interface Workspace : ContextAware, Provider {
/** /**
* The whole data node for current workspace * The whole data node for current workspace