Compare commits

...

2 Commits

Author SHA1 Message Date
946ac88480 Partially fixed a bug with MutableMeta observable wrappers. 2023-12-05 15:13:50 +03:00
5461a83417 Name refactoring.
Meta.stringList accepts nullable receiver.
2023-12-04 09:55:04 +03:00
37 changed files with 193 additions and 89 deletions

View File

@ -3,6 +3,7 @@
## Unreleased ## Unreleased
### Added ### Added
- Wasm artifacts
### Changed ### Changed
@ -11,6 +12,7 @@
### Removed ### Removed
### Fixed ### Fixed
- Partially fixed a bug with `MutableMeta` observable wrappers.
### Security ### Security

View File

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

View File

@ -8,12 +8,14 @@ kscience {
jvm() jvm()
js() js()
native() native()
wasm()
useCoroutines() useCoroutines()
useSerialization() useSerialization()
dependencies { commonMain {
api(project(":dataforge-meta")) api(project(":dataforge-meta"))
api(spclibs.atomicfu)
} }
dependencies(jvmMain){ jvmMain{
api(kotlin("reflect")) api(kotlin("reflect"))
api("org.slf4j:slf4j-api:1.7.30") api("org.slf4j:slf4j-api:1.7.30")
} }

View File

@ -3,7 +3,7 @@ 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.DfType
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
@ -18,7 +18,7 @@ import space.kscience.dataforge.provider.Provider
* *
* create - configure - attach - detach - destroy * create - configure - attach - detach - destroy
*/ */
@DfId(TARGET) @DfType(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.DfId import space.kscience.dataforge.misc.DfType
@DfId(PluginFactory.TYPE) @DfType(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

@ -4,7 +4,7 @@ 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.DfType
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -13,10 +13,10 @@ import kotlin.reflect.full.findAnnotation
@DFExperimental @DFExperimental
public val KClass<*>.dfId: String public val KClass<*>.dfId: String
get() = findAnnotation<DfId>()?.id ?: simpleName ?: "" get() = findAnnotation<DfType>()?.id ?: simpleName ?: ""
/** /**
* Provide an object with given name inferring target from its type using [DfId] annotation * Provide an object with given name inferring target from its type using [DfType] 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? {

View File

@ -0,0 +1,3 @@
package space.kscience.dataforge.context
internal actual fun getGlobalLoggerFactory(): PluginFactory<out LogManager> = DefaultLogManager

View File

@ -6,9 +6,11 @@ kscience{
jvm() jvm()
js() js()
native() native()
wasm()
useCoroutines() useCoroutines()
dependencies { dependencies {
api(project(":dataforge-meta")) api(spclibs.atomicfu)
api(projects.dataforgeMeta)
api(kotlin("reflect")) api(kotlin("reflect"))
} }
} }

View File

@ -98,8 +98,7 @@ internal class MapAction<in T : Any, R : Any>(
* A one-to-one mapping action * A one-to-one mapping action
*/ */
@DFExperimental @DFExperimental
@Suppress("FunctionName") public inline fun <T : Any, reified R : Any> Action.Companion.mapping(
public inline fun <T : Any, reified R : Any> Action.Companion.map(
noinline builder: MapActionBuilder<T, R>.() -> Unit, noinline builder: MapActionBuilder<T, R>.() -> Unit,
): Action<T, R> = MapAction(typeOf<R>(), builder) ): Action<T, R> = MapAction(typeOf<R>(), builder)

View File

@ -112,6 +112,6 @@ internal class ReduceAction<T : Any, R : Any>(
* A one-to-one mapping action * A one-to-one mapping action
*/ */
@DFExperimental @DFExperimental
public inline fun <reified T : Any, reified R : Any> Action.Companion.reduce( public inline fun <reified T : Any, reified R : Any> Action.Companion.reducing(
noinline builder: ReduceGroupBuilder<T, R>.() -> Unit, noinline builder: ReduceGroupBuilder<T, R>.() -> Unit,
): Action<T, R> = ReduceAction(typeOf<R>(), builder) ): Action<T, R> = ReduceAction(typeOf<R>(), builder)

View File

@ -87,6 +87,6 @@ internal class SplitAction<T : Any, R : Any>(
* Action that splits each incoming element into a number of fragments defined in builder * Action that splits each incoming element into a number of fragments defined in builder
*/ */
@DFExperimental @DFExperimental
public inline fun <T : Any, reified R : Any> Action.Companion.split( public inline fun <T : Any, reified R : Any> Action.Companion.splitting(
noinline builder: SplitBuilder<T, R>.() -> Unit, noinline builder: SplitBuilder<T, R>.() -> Unit,
): Action<T, R> = SplitAction(typeOf<R>(), builder) ): Action<T, R> = SplitAction(typeOf<R>(), builder)

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.DfId import space.kscience.dataforge.misc.DfType
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
*/ */
@DfId(Data.TYPE) @DfType(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

@ -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.DfId import space.kscience.dataforge.misc.DfType
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
*/ */
@DfId(DataTree.TYPE) @DfType(DataTree.TYPE)
public interface DataTree<out T : Any> : DataSet<T> { public interface DataTree<out T : Any> : DataSet<T> {
/** /**

View File

@ -1,2 +0,0 @@
package space.kscience.dataforge.data

View File

@ -6,7 +6,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.actions.invoke import space.kscience.dataforge.actions.invoke
import space.kscience.dataforge.actions.map import space.kscience.dataforge.actions.mapping
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -20,7 +20,7 @@ internal class ActionsTest {
} }
} }
val plusOne = Action.map<Int, Int> { val plusOne = Action.mapping<Int, Int> {
result { it + 1 } result { it + 1 }
} }
val result = plusOne(data) val result = plusOne(data)
@ -31,7 +31,7 @@ internal class ActionsTest {
fun testDynamicMapAction() = runTest { fun testDynamicMapAction() = runTest {
val data: DataSourceBuilder<Int> = DataSource() val data: DataSourceBuilder<Int> = DataSource()
val plusOne = Action.map<Int, Int> { val plusOne = Action.mapping<Int, Int> {
result { it + 1 } result { it + 1 }
} }

View File

@ -4,12 +4,13 @@ plugins {
description = "IO module" description = "IO module"
val ioVersion = "0.2.1" val ioVersion = "0.3.0"
kscience { kscience {
jvm() jvm()
js() js()
native() native()
wasm()
useSerialization() useSerialization()
useSerialization(sourceSet = space.kscience.gradle.DependencySourceSet.TEST) { useSerialization(sourceSet = space.kscience.gradle.DependencySourceSet.TEST) {
cbor() cbor()

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.DfId import space.kscience.dataforge.misc.DfType
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)
@DfId(ENVELOPE_FORMAT_TYPE) @DfType(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,7 +7,7 @@ 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.DfType
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
@ -72,7 +72,7 @@ public fun <T : Any> Sink.writeWith(format: IOWriter<T>, obj: T): Unit =
format.writeTo(this, obj) format.writeTo(this, obj)
@DfId(IO_FORMAT_TYPE) @DfType(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.DfId import space.kscience.dataforge.misc.DfType
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
} }
@DfId(META_FORMAT_TYPE) @DfType(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

@ -724,6 +724,7 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorBuild
public final fun getAttributes ()Lspace/kscience/dataforge/meta/MutableMeta; public final fun getAttributes ()Lspace/kscience/dataforge/meta/MutableMeta;
public final fun getChildren ()Ljava/util/Map; public final fun getChildren ()Ljava/util/Map;
public final fun getDefault ()Lspace/kscience/dataforge/meta/Value; public final fun getDefault ()Lspace/kscience/dataforge/meta/Value;
public final fun getDescription ()Ljava/lang/String;
public final fun getIndexKey ()Ljava/lang/String; public final fun getIndexKey ()Ljava/lang/String;
public final fun getInfo ()Ljava/lang/String; public final fun getInfo ()Ljava/lang/String;
public final fun getMultiple ()Z public final fun getMultiple ()Z
@ -737,6 +738,7 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorBuild
public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V
public final fun setChildren (Ljava/util/Map;)V public final fun setChildren (Ljava/util/Map;)V
public final fun setDefault (Lspace/kscience/dataforge/meta/Value;)V public final fun setDefault (Lspace/kscience/dataforge/meta/Value;)V
public final fun setDescription (Ljava/lang/String;)V
public final fun setIndexKey (Ljava/lang/String;)V public final fun setIndexKey (Ljava/lang/String;)V
public final fun setInfo (Ljava/lang/String;)V public final fun setInfo (Ljava/lang/String;)V
public final fun setMultiple (Z)V public final fun setMultiple (Z)V
@ -903,7 +905,7 @@ public abstract interface annotation class space/kscience/dataforge/misc/DFExper
public abstract interface annotation class space/kscience/dataforge/misc/DFInternal : java/lang/annotation/Annotation { public abstract interface annotation class space/kscience/dataforge/misc/DFInternal : java/lang/annotation/Annotation {
} }
public abstract interface annotation class space/kscience/dataforge/misc/DfId : java/lang/annotation/Annotation { public abstract interface annotation class space/kscience/dataforge/misc/DfType : java/lang/annotation/Annotation {
public abstract fun id ()Ljava/lang/String; public abstract fun id ()Ljava/lang/String;
} }
@ -944,6 +946,7 @@ public final class space/kscience/dataforge/names/NameKt {
public static final fun asName (Lspace/kscience/dataforge/names/NameToken;)Lspace/kscience/dataforge/names/Name; public static final fun asName (Lspace/kscience/dataforge/names/NameToken;)Lspace/kscience/dataforge/names/Name;
public static final fun cutFirst (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name; public static final fun cutFirst (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun cutLast (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name; public static final fun cutLast (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Z
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z
public static final fun first (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/NameToken; public static final fun first (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/NameToken;
@ -966,6 +969,7 @@ public final class space/kscience/dataforge/names/NameKt {
public static final fun removeHeadOrNull (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name; public static final fun removeHeadOrNull (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun replaceLast (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/names/Name; public static final fun replaceLast (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/names/Name;
public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Z
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z
public static final fun withIndex (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name; public static final fun withIndex (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name;

View File

@ -6,6 +6,7 @@ kscience {
jvm() jvm()
js() js()
native() native()
wasm()
useSerialization{ useSerialization{
json() json()
} }

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.DfId import space.kscience.dataforge.misc.DfType
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
@ -31,7 +31,7 @@ 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.
*/ */
@DfId(Meta.TYPE) @DfType(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?
@ -248,7 +248,7 @@ public inline fun <reified E : Enum<E>> Meta?.enum(): E? = this?.value?.let {
} }
} }
public val Meta.stringList: List<String>? get() = value?.list?.map { it.string } public val Meta?.stringList: List<String>? get() = this?.value?.list?.map { it.string }
/** /**
* Create a provider that uses given provider for default values if those are not found in this provider * Create a provider that uses given provider for default values if those are not found in this provider

View File

@ -6,60 +6,71 @@ import space.kscience.dataforge.names.*
/** /**
* A class that takes [MutableMeta] provider and adds obsevability on top of that * A class that takes [MutableMeta] provider and adds obsevability on top of that
*
* TODO rewrite to properly work with detached nodes
*/ */
private class ObservableMetaWrapper( private class ObservableMetaWrapper(
val root: MutableMeta, val root: MutableMeta,
val absoluteName: Name, val nodeName: Name,
val listeners: MutableSet<MetaListener>, val listeners: MutableSet<MetaListener>,
) : ObservableMutableMeta { ) : ObservableMutableMeta {
override val items: Map<NameToken, ObservableMutableMeta> override val items: Map<NameToken, ObservableMutableMeta>
get() = root.items.keys.associateWith { get() = root.items.keys.associateWith {
ObservableMetaWrapper(root, absoluteName + it, listeners) ObservableMetaWrapper(root, nodeName + it, listeners)
} }
override fun get(name: Name): ObservableMutableMeta? = override fun get(name: Name): ObservableMutableMeta? = if (root[nodeName + name] == null) {
root.get(name)?.let { ObservableMetaWrapper(root, this.absoluteName + name, listeners) } null
} else {
ObservableMetaWrapper(root, nodeName + name, listeners)
}
@ThreadSafe @ThreadSafe
override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) { override fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit) {
listeners.add( listeners.add(
MetaListener(Pair(owner, absoluteName)) { name -> MetaListener(Pair(owner, nodeName)) { fullName ->
if (name.startsWith(absoluteName)) { if (fullName.startsWith(nodeName)) {
(this[absoluteName] ?: Meta.EMPTY).callback(name.removeFirstOrNull(absoluteName)!!) root[nodeName]?.callback(fullName.removeFirstOrNull(nodeName)!!)
} }
} }
) )
} }
override fun removeListener(owner: Any?) { override fun removeListener(owner: Any?) {
listeners.removeAll { it.owner === Pair(owner, absoluteName) } listeners.removeAll { it.owner === Pair(owner, nodeName) }
} }
override fun invalidate(name: Name) { override fun invalidate(name: Name) {
listeners.forEach { it.callback(this, name) } listeners.forEach { it.callback(this, nodeName + name) }
} }
override var value: Value? override var value: Value?
get() = root.value get() = root[nodeName]?.value
set(value) { set(value) {
root.value = value root.getOrCreate(nodeName).value = value
invalidate(Name.EMPTY) invalidate(Name.EMPTY)
} }
override fun getOrCreate(name: Name): ObservableMutableMeta = override fun getOrCreate(name: Name): ObservableMutableMeta =
ObservableMetaWrapper(root, this.absoluteName + name, listeners) ObservableMetaWrapper(root, nodeName + name, listeners)
override fun set(name: Name, node: Meta?) { fun removeNode(name: Name): 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.set(absoluteName + name, node)
return oldMeta
}
override fun set(name: Name, node: Meta?) {
val oldMeta = removeNode(name)
root[nodeName + name] = node
if (oldMeta != node) { if (oldMeta != node) {
invalidate(name) invalidate(name)
} }
} }
override fun toMeta(): Meta = root[absoluteName]?.toMeta() ?: Meta.EMPTY override fun toMeta(): Meta = root[nodeName]?.toMeta() ?: Meta.EMPTY
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

@ -9,7 +9,11 @@ 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 description: String? = null
@Deprecated("Replace by description", ReplaceWith("description"))
public var info: String? by ::description
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 valueRestriction: ValueRestriction = ValueRestriction.NONE public var valueRestriction: ValueRestriction = ValueRestriction.NONE
@ -87,7 +91,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
@PublishedApi @PublishedApi
internal fun build(): MetaDescriptor = MetaDescriptor( internal fun build(): MetaDescriptor = MetaDescriptor(
description = info, description = description,
children = children.mapValues { it.value.build() }, children = children.mapValues { it.value.build() },
multiple = multiple, multiple = multiple,
valueRestriction = valueRestriction, valueRestriction = valueRestriction,
@ -165,7 +169,7 @@ 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.description description = 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
valueRestriction = this@toBuilder.valueRestriction valueRestriction = this@toBuilder.valueRestriction

View File

@ -5,4 +5,7 @@ package space.kscience.dataforge.misc
*/ */
@MustBeDocumented @MustBeDocumented
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
public annotation class DfId(val id: String) public annotation class DfType(val id: String)
@Deprecated("Replace with DfType", replaceWith = ReplaceWith("DfType"))
public typealias DfId = DfType

View File

@ -216,9 +216,13 @@ public fun Name.endsWith(token: NameToken): Boolean = lastOrNull() == token
public fun Name.startsWith(name: Name): Boolean = public fun Name.startsWith(name: Name): Boolean =
this.length >= name.length && (this == name || tokens.subList(0, name.length) == name.tokens) this.length >= name.length && (this == name || tokens.subList(0, name.length) == name.tokens)
public fun Name.startsWith(name: String): Boolean = startsWith(name.parseAsName())
public fun Name.endsWith(name: Name): Boolean = public fun Name.endsWith(name: Name): Boolean =
this.length >= name.length && (this == name || tokens.subList(length - name.length, length) == name.tokens) this.length >= name.length && (this == name || tokens.subList(length - name.length, length) == name.tokens)
public fun Name.endsWith(name: String): Boolean = endsWith(name.parseAsName())
/** /**
* if [this] starts with given [head] name, returns the reminder of the name (could be empty). Otherwise, returns null * if [this] starts with given [head] name, returns the reminder of the name (could be empty). Otherwise, returns null
*/ */

View File

@ -0,0 +1,49 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.names.startsWith
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
class ObservableMetaTest {
@Test
fun asObservable() {
val meta = MutableMeta {
"data" put {
"x" put ListValue(1, 2, 3)
"y" put ListValue(5, 6, 7)
"type" put "scatter"
}
}.asObservable()
assertEquals("scatter", meta["data.type"].string)
}
@Test
@Ignore
fun detachNode() {
val meta = MutableMeta {
"data" put {
"x" put ListValue(1, 2, 3)
"y" put ListValue(5, 6, 7)
"type" put "scatter"
}
}.asObservable()
var collector: Value? = null
meta.onChange(null) { name ->
if (name.startsWith("data")) {
collector = get("data.z")?.value
}
}
val data = meta["data"]!!
meta.remove("data")
data["z"] = ListValue(2, 5, 7)
assertEquals(null, collector)
}
}

View File

@ -11,14 +11,14 @@ class DescriptorTest {
val descriptor = MetaDescriptor { val descriptor = MetaDescriptor {
node("aNode") { node("aNode") {
info = "A root demo node" description = "A root demo node"
value("b", ValueType.NUMBER) { value("b", ValueType.NUMBER) {
info = "b number value" description = "b number value"
} }
node("otherNode") { node("otherNode") {
value("otherValue", ValueType.BOOLEAN) { value("otherValue", ValueType.BOOLEAN) {
default(false) default(false)
info = "default value" description = "default value"
} }
} }
} }

View File

@ -1,5 +1,5 @@
package space.kscience.dataforge.misc package space.kscience.dataforge.misc
import kotlin.js.unsafeCast as unsafeCastJs import kotlin.js.unsafeCast as unsafeCastJs
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
public actual inline fun <T> Any?.unsafeCast(): T = this.unsafeCastJs<T>() public actual inline fun <T> Any?.unsafeCast(): T = unsafeCastJs<T>()

View File

@ -1,4 +1,4 @@
package space.kscience.dataforge.misc package space.kscience.dataforge.misc
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") @Suppress("UNCHECKED_CAST")
public actual inline fun <T> Any?.unsafeCast(): T = this as T public actual inline fun <T> Any?.unsafeCast(): T = this as T

View File

@ -0,0 +1,4 @@
package space.kscience.dataforge.misc
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
public actual inline fun <T> Any?.unsafeCast(): T = this as T

View File

@ -4,15 +4,15 @@ plugins {
kscience{ kscience{
jvm() jvm()
dependencies { commonMain {
api(projects.dataforgeWorkspace) api(projects.dataforgeWorkspace)
implementation(kotlin("scripting-common")) implementation(kotlin("scripting-common"))
} }
dependencies(jvmMain){ jvmMain{
implementation(kotlin("scripting-jvm-host")) implementation(kotlin("scripting-jvm-host"))
implementation(kotlin("scripting-jvm")) implementation(kotlin("scripting-jvm"))
} }
dependencies(jvmTest){ jvmTest{
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)
} }
} }

View File

@ -2,29 +2,27 @@ plugins {
id("space.kscience.gradle.mpp") id("space.kscience.gradle.mpp")
} }
kscience{ kscience {
jvm() jvm()
js() js()
native() native()
wasm()
useCoroutines() useCoroutines()
useSerialization{ useSerialization {
protobuf() protobuf()
} }
commonMain{ commonMain {
dependencies {
api(projects.dataforgeContext) api(projects.dataforgeContext)
api(projects.dataforgeData) api(projects.dataforgeData)
api(projects.dataforgeIo) api(projects.dataforgeIo)
} }
} jvmTest {
jvmTest{
dependencies {
implementation(spclibs.logback.classic) implementation(spclibs.logback.classic)
implementation(projects.dataforgeIo.dataforgeIoYaml) implementation(projects.dataforgeIo.dataforgeIoYaml)
} }
}
} }
readme{ readme {
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
} }

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.DfId import space.kscience.dataforge.misc.DfType
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.
*/ */
@DfId(TYPE) @DfType(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.DfId import space.kscience.dataforge.misc.DfType
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
*/ */
@DfId(Workspace.TYPE) @DfType(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

View File

@ -11,7 +11,6 @@ import space.kscience.dataforge.data.*
import space.kscience.dataforge.io.* import space.kscience.dataforge.io.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.copy import space.kscience.dataforge.meta.copy
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
@ -27,10 +26,7 @@ import java.nio.file.WatchEvent
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.spi.FileSystemProvider import java.nio.file.spi.FileSystemProvider
import java.time.Instant import java.time.Instant
import kotlin.io.path.extension import kotlin.io.path.*
import kotlin.io.path.name
import kotlin.io.path.nameWithoutExtension
import kotlin.io.path.readAttributes
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -92,7 +88,7 @@ public fun <T : Any> IOPlugin.readDataFile(
context(IOPlugin) @DFExperimental context(IOPlugin) @DFExperimental
private fun <T : Any> DataSetBuilder<T>.directory( public fun <T : Any> DataSetBuilder<T>.directory(
path: Path, path: Path,
ignoreExtensions: Set<String>, ignoreExtensions: Set<String>,
formatResolver: FileFormatResolver<T>, formatResolver: FileFormatResolver<T>,
@ -145,7 +141,7 @@ public inline fun <reified T : Any> IOPlugin.readDataDirectory(
): DataTree<T> = readDataDirectory(typeOf<T>(), path, ignoreExtensions, formatResolver) ): DataTree<T> = readDataDirectory(typeOf<T>(), path, ignoreExtensions, formatResolver)
/** /**
* Read raw binary data tree from the directory. All files are read as-is (save for meta files). * Read a raw binary data tree from the directory. All files are read as-is (save for meta files).
*/ */
@DFExperimental @DFExperimental
public fun IOPlugin.readRawDirectory( public fun IOPlugin.readRawDirectory(
@ -260,6 +256,29 @@ public suspend fun <T : Any> IOPlugin.writeDataDirectory(
} }
} }
/**
* Reads the specified resources and returns a [DataTree] containing the data.
*
* @param resources The names of the resources to read.
* @param classLoader The class loader to use for loading the resources. By default, it uses the current thread's context class loader.
* @return A DataTree containing the data read from the resources.
*/
@DFExperimental
private fun IOPlugin.readResources(
vararg resources: String,
classLoader: ClassLoader = Thread.currentThread().contextClassLoader,
): DataTree<Binary> {
// require(resource.isNotBlank()) {"Can't mount root resource tree as data root"}
return DataTree {
resources.forEach { resource ->
val path = classLoader.getResource(resource)?.toURI()?.toPath() ?: error(
"Resource with name $resource is not resolved"
)
node(resource, readRawDirectory(path))
}
}
}
/** /**
* Add file/directory-based data tree item * Add file/directory-based data tree item
* *

View File

@ -6,5 +6,5 @@ kotlin.mpp.stability.nowarn=true
kotlin.incremental.js.ir=true kotlin.incremental.js.ir=true
kotlin.native.ignoreDisabledTargets=true kotlin.native.ignoreDisabledTargets=true
toolsVersion=0.15.1-kotlin-1.9.21 toolsVersion=0.15.2-kotlin-1.9.21
#kotlin.experimental.tryK2=true #kotlin.experimental.tryK2=true