diff --git a/CHANGELOG.md b/CHANGELOG.md index b9d3b6a9..1f59fbae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,41 @@ ### Security +## 0.9.0 - 2024-06-04 + +### Added + +- Custom CoroutineContext during `Context` creation. + +### Changed + +- Kotlin 2.0 +- `MetaSpec` renamed to `MetaReader`. MetaSpec is now reserved for builder-based generation of meta descriptors. +- Add self-type for Meta. Remove unsafe cast method for meta instances. + +### Removed + +- Automatic descriptors for schema. It is not possible to implement them without heavy reflection. + +## 0.8.2 - 2024-04-27 + +### Added + +- Name index comparator +- Specialized ByteArrayValue + +### Changed + +- DataSink `branch` is replaced with `putAll` to avoid confusion with DataTree methods +- Meta delegate now uses a specific class that has a descriptor + +### Fixed + +- `listOfScheme` and `listOfConvertable` delegates provides correct items order. +- Scheme meta setter works with proper sub-branch. +- NameToken.parse improper work with indices. +- Proper data handling for cache. + ## 0.8.0 - 2024-02-03 ### Added diff --git a/build.gradle.kts b/build.gradle.kts index b9349868..72f61abc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,20 +3,21 @@ import space.kscience.gradle.useApache2Licence import space.kscience.gradle.useSPCTeam plugins { - id("space.kscience.gradle.project") + alias(spclibs.plugins.kscience.project) + alias(spclibs.plugins.kotlinx.kover) } allprojects { group = "space.kscience" - version = "0.8.0" + version = "0.9.0" } subprojects { apply(plugin = "maven-publish") tasks.withType<KotlinCompile> { - kotlinOptions { - freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" + compilerOptions { + freeCompilerArgs.add("-Xcontext-receivers") } } } @@ -30,7 +31,7 @@ ksciencePublish { useApache2Licence() useSPCTeam() } - repository("spc","https://maven.sciprog.center/kscience") + repository("spc", "https://maven.sciprog.center/kscience") sonatype("https://oss.sonatype.org") } diff --git a/dataforge-context/README.md b/dataforge-context/README.md index f0aff459..2cd53fd1 100644 --- a/dataforge-context/README.md +++ b/dataforge-context/README.md @@ -6,7 +6,7 @@ Context and provider definitions ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-context:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-context:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-context:0.8.0") + implementation("space.kscience:dataforge-context:0.9.0-dev-1") } ``` diff --git a/dataforge-context/api/dataforge-context.api b/dataforge-context/api/dataforge-context.api index 12bca176..67cd0cba 100644 --- a/dataforge-context/api/dataforge-context.api +++ b/dataforge-context/api/dataforge-context.api @@ -57,6 +57,7 @@ public abstract interface class space/kscience/dataforge/context/ContextAware { public final class space/kscience/dataforge/context/ContextBuilder { public final fun build ()Lspace/kscience/dataforge/context/Context; + public final fun coroutineContext (Lkotlin/coroutines/CoroutineContext;)V public final fun getName ()Lspace/kscience/dataforge/names/Name; public final fun plugin (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V public final fun plugin (Lspace/kscience/dataforge/context/Plugin;)V @@ -69,9 +70,6 @@ public final class space/kscience/dataforge/context/ContextBuilder { public final fun properties (Lkotlin/jvm/functions/Function1;)V } -public final class space/kscience/dataforge/context/ContextBuilderKt { -} - public final class space/kscience/dataforge/context/DefaultLogManager : space/kscience/dataforge/context/AbstractPlugin, space/kscience/dataforge/context/LogManager { public static final field Companion Lspace/kscience/dataforge/context/DefaultLogManager$Companion; public fun <init> ()V @@ -212,14 +210,14 @@ public final class space/kscience/dataforge/context/PluginTag : space/kscience/d public fun toString ()Ljava/lang/String; } -public final class space/kscience/dataforge/context/PluginTag$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +public synthetic class space/kscience/dataforge/context/PluginTag$$serializer : kotlinx/serialization/internal/GeneratedSerializer { public static final field INSTANCE Lspace/kscience/dataforge/context/PluginTag$$serializer; - public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/context/PluginTag; - public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/context/PluginTag; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/context/PluginTag;)V + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/context/PluginTag;)V public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; } @@ -264,17 +262,6 @@ public abstract interface annotation class space/kscience/dataforge/descriptors/ public abstract interface annotation class space/kscience/dataforge/descriptors/Multiple : java/lang/annotation/Annotation { } -public final class space/kscience/dataforge/descriptors/ReflectiveDescriptorsKt { - public static final fun forClass (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor$Companion;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; - public static synthetic fun forClass$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor$Companion;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; -} - -public final class space/kscience/dataforge/properties/MetaAsFlowKt { -} - -public final class space/kscience/dataforge/provider/DfTypeKt { -} - public final class space/kscience/dataforge/provider/Path : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker { public static final field Companion Lspace/kscience/dataforge/provider/Path$Companion; public static final field PATH_SEGMENT_SEPARATOR Ljava/lang/String; diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt index bb74d605..c614598c 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/Context.kt @@ -10,6 +10,7 @@ import space.kscience.dataforge.misc.ThreadSafe import space.kscience.dataforge.names.Name import space.kscience.dataforge.provider.Provider import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top. @@ -26,6 +27,7 @@ public open class Context internal constructor( public val parent: Context?, plugins: Set<Plugin>, // set of unattached plugins meta: Meta, + coroutineContext: CoroutineContext = EmptyCoroutineContext, ) : Named, MetaRepr, Provider, CoroutineScope { /** @@ -65,7 +67,7 @@ public open class Context internal constructor( override val coroutineContext: CoroutineContext by lazy { (parent ?: Global).coroutineContext.let { parenContext -> - parenContext + SupervisorJob(parenContext[Job]) + parenContext + coroutineContext + SupervisorJob(parenContext[Job]) } } diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt index c0db4314..894c5f15 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/context/ContextBuilder.kt @@ -13,6 +13,8 @@ import space.kscience.dataforge.names.plus import kotlin.collections.component1 import kotlin.collections.component2 import kotlin.collections.set +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * A convenience builder for context @@ -59,8 +61,15 @@ public class ContextBuilder internal constructor( plugin(DeFactoPluginFactory(plugin)) } + private var coroutineContext: CoroutineContext = EmptyCoroutineContext + + public fun coroutineContext(coroutineContext: CoroutineContext) { + this.coroutineContext = coroutineContext + } + + public fun build(): Context { - val contextName = name ?: NameToken("@auto",hashCode().toUInt().toString(16)).asName() + val contextName = name ?: NameToken("@auto", hashCode().toUInt().toString(16)).asName() val plugins = HashMap<PluginTag, Plugin>() fun addPlugin(factory: PluginFactory<*>, meta: Meta) { @@ -86,7 +95,7 @@ public class ContextBuilder internal constructor( addPlugin(factory, meta) } - return Context(contextName, parent, plugins.values.toSet(), meta.seal()) + return Context(contextName, parent, plugins.values.toSet(), meta.seal(), coroutineContext) } } diff --git a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/metaAsFlow.kt b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/metaAsFlow.kt index 90fafc5e..da539fcb 100644 --- a/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/metaAsFlow.kt +++ b/dataforge-context/src/commonMain/kotlin/space/kscience/dataforge/properties/metaAsFlow.kt @@ -10,7 +10,7 @@ import space.kscience.dataforge.meta.* import space.kscience.dataforge.misc.DFExperimental @DFExperimental -public fun <T> ObservableMeta.asFlow(converter: MetaSpec<T>): Flow<T> = callbackFlow { +public fun <T> ObservableMeta.asFlow(converter: MetaReader<T>): Flow<T> = callbackFlow { onChange(this){ trySend(converter.read(this)) } diff --git a/dataforge-context/src/jvmMain/kotlin/space/kscience/dataforge/descriptors/reflectiveDescriptors.kt b/dataforge-context/src/jvmMain/kotlin/space/kscience/dataforge/descriptors/reflectiveDescriptors.kt index 1f2db7fc..590324d7 100644 --- a/dataforge-context/src/jvmMain/kotlin/space/kscience/dataforge/descriptors/reflectiveDescriptors.kt +++ b/dataforge-context/src/jvmMain/kotlin/space/kscience/dataforge/descriptors/reflectiveDescriptors.kt @@ -4,18 +4,12 @@ import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream import org.slf4j.LoggerFactory -import space.kscience.dataforge.meta.Scheme -import space.kscience.dataforge.meta.SchemeSpec -import space.kscience.dataforge.meta.ValueType import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder -import space.kscience.dataforge.meta.descriptors.node +import space.kscience.dataforge.misc.DFExperimental import java.net.URL -import kotlin.reflect.KClass -import kotlin.reflect.full.isSubclassOf -import kotlin.reflect.full.memberProperties -import kotlin.reflect.typeOf - +import kotlin.reflect.KAnnotatedElement +import kotlin.reflect.KProperty /** * Description text for meta property, node or whole object @@ -58,19 +52,9 @@ private fun MetaDescriptorBuilder.loadDescriptorFromResource(resource: Descripto } } - -public fun <T : Any> MetaDescriptor.Companion.forClass( - kClass: KClass<T>, - mod: MetaDescriptorBuilder.() -> Unit = {}, -): MetaDescriptor = MetaDescriptor { - when { - kClass.isSubclassOf(Number::class) -> valueType(ValueType.NUMBER) - kClass == String::class -> ValueType.STRING - kClass == Boolean::class -> ValueType.BOOLEAN - kClass == DoubleArray::class -> ValueType.LIST - } - - kClass.annotations.forEach { +@DFExperimental +public fun MetaDescriptorBuilder.forAnnotatedElement(element: KAnnotatedElement) { + element.annotations.forEach { when (it) { is Description -> description = it.value @@ -79,46 +63,70 @@ public fun <T : Any> MetaDescriptor.Companion.forClass( is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url)) } } - kClass.memberProperties.forEach { property -> - - var flag = false - - val descriptor = MetaDescriptor { - //use base type descriptor as a base - (property.returnType.classifier as? KClass<*>)?.let { - from(forClass(it)) - } - property.annotations.forEach { - when (it) { - is Description -> { - description = it.value - flag = true - } - - is Multiple -> { - multiple = true - flag = true - } - - is DescriptorResource -> { - loadDescriptorFromResource(it) - flag = true - } - - is DescriptorUrl -> { - loadDescriptorFromUrl(URL(it.url)) - flag = true - } - } - } - } - if (flag) { - node(property.name, descriptor) - } - } - mod() } -@Suppress("UNCHECKED_CAST") -public inline fun <reified T : Scheme> SchemeSpec<T>.autoDescriptor( noinline mod: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptor = - MetaDescriptor.forClass(typeOf<T>().classifier as KClass<T>, mod) \ No newline at end of file +@DFExperimental +public fun MetaDescriptorBuilder.forProperty(property: KProperty<*>) { + property.annotations.forEach { + when (it) { + is Description -> description = it.value + + is DescriptorResource -> loadDescriptorFromResource(it) + + is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url)) + } + } +} +// +//@DFExperimental +//public fun <T : Scheme> MetaDescriptor.Companion.forScheme( +// spec: SchemeSpec<T>, +// mod: MetaDescriptorBuilder.() -> Unit = {}, +//): MetaDescriptor = MetaDescriptor { +// val scheme = spec.empty() +// val kClass: KClass<T> = scheme::class as KClass<T> +// when { +// kClass.isSubclassOf(Number::class) -> valueType(ValueType.NUMBER) +// kClass == String::class -> ValueType.STRING +// kClass == Boolean::class -> ValueType.BOOLEAN +// kClass == DoubleArray::class -> ValueType.LIST +// kClass == ByteArray::class -> ValueType.LIST +// } +// +// forAnnotatedElement(kClass) +// kClass.memberProperties.forEach { property -> +// node(property.name) { +// +// (property.getDelegate(scheme) as? MetaDelegate<*>)?.descriptor?.let { +// from(it) +// } +// +// property.annotations.forEach { +// when (it) { +// is Description -> { +// description = it.value +// } +// +// is Multiple -> { +// multiple = true +// } +// +// is DescriptorResource -> { +// loadDescriptorFromResource(it) +// } +// +// is DescriptorUrl -> { +// loadDescriptorFromUrl(URL(it.url)) +// } +// } +// } +// } +// +// } +// mod() +//} +// +//@DFExperimental +//public inline fun <reified T : Scheme> SchemeSpec<T>.autoDescriptor( +// noinline mod: MetaDescriptorBuilder.() -> Unit = {}, +//): MetaDescriptor = MetaDescriptor.forScheme(this, mod) \ No newline at end of file diff --git a/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt b/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt index 617e85cc..3b1fce3d 100644 --- a/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt +++ b/dataforge-context/src/jvmTest/kotlin/space/kscience/dataforge/descriptors/TestAutoDescriptors.kt @@ -1,31 +1,29 @@ +@file:OptIn(DFExperimental::class) + package space.kscience.dataforge.descriptors -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import org.junit.jupiter.api.Test -import space.kscience.dataforge.meta.Scheme -import space.kscience.dataforge.meta.SchemeSpec -import space.kscience.dataforge.meta.descriptors.MetaDescriptor -import space.kscience.dataforge.meta.int -import space.kscience.dataforge.meta.string +import space.kscience.dataforge.misc.DFExperimental -private class TestScheme: Scheme(){ - - @Description("A") - val a by string() - - @Description("B") - val b by int() - - companion object: SchemeSpec<TestScheme>(::TestScheme){ - override val descriptor: MetaDescriptor = autoDescriptor() - } -} - -class TestAutoDescriptors { - @Test - fun autoDescriptor(){ - val autoDescriptor = MetaDescriptor.forClass(TestScheme::class) - println(Json{prettyPrint = true}.encodeToString(autoDescriptor)) - } -} \ No newline at end of file +// +//class TestScheme : Scheme() { +// +// @Description("A") +// val a by string() +// +// @Description("B") +// val b by int() +// +// val c by int() +// +// companion object : SchemeSpec<TestScheme>(::TestScheme) { +// override val descriptor: MetaDescriptor = autoDescriptor() +// } +//} +// +//class TestAutoDescriptors { +// @Test +// fun autoDescriptor() { +// val autoDescriptor = MetaDescriptor.forScheme(TestScheme) +// println(Json { prettyPrint = true }.encodeToString(autoDescriptor)) +// } +//} \ No newline at end of file diff --git a/dataforge-data/README.md b/dataforge-data/README.md index d77ed1b9..35aaa4e6 100644 --- a/dataforge-data/README.md +++ b/dataforge-data/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-data:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-data:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-data:0.8.0") + implementation("space.kscience:dataforge-data:0.9.0-dev-1") } ``` diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/AbstractAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/AbstractAction.kt index 7cd1ced5..4ed5f8df 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/AbstractAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/AbstractAction.kt @@ -1,11 +1,14 @@ package space.kscience.dataforge.actions -import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import space.kscience.dataforge.data.* +import space.kscience.dataforge.data.DataSink +import space.kscience.dataforge.data.DataTree +import space.kscience.dataforge.data.DataUpdate +import space.kscience.dataforge.data.launchUpdate import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.startsWith import kotlin.reflect.KType @@ -21,7 +24,7 @@ internal fun MutableMap<Name, *>.removeWhatStartsWith(name: Name) { /** * An action that caches results on-demand and recalculates them on source push */ -public abstract class AbstractAction<T : Any, R : Any>( +public abstract class AbstractAction<T, R>( public val outputType: KType, ) : Action<T, R> { @@ -29,7 +32,7 @@ public abstract class AbstractAction<T : Any, R : Any>( * Generate initial content of the output */ protected abstract fun DataSink<R>.generate( - data: DataTree<T>, + source: DataTree<T>, meta: Meta, ) @@ -37,36 +40,31 @@ public abstract class AbstractAction<T : Any, R : Any>( * Update part of the data set using provided data * * @param source the source data tree in case we need several data items to update + * @param meta the metadata used for the whole data tree + * @param updatedData an updated item */ - protected open fun DataSink<R>.update( + protected open suspend fun DataSink<R>.update( source: DataTree<T>, meta: Meta, - namedData: NamedData<T>, - ){ + updatedData: DataUpdate<T>, + ) { //by default regenerate the whole data set - generate(source,meta) + generate(source, meta) } - @OptIn(DFInternal::class) + @OptIn(UnsafeKType::class) override fun execute( - dataSet: DataTree<T>, + source: DataTree<T>, meta: Meta, - ): DataTree<R> = if(dataSet.isObservable()) { - MutableDataTree<R>(outputType, dataSet.updatesScope).apply { - generate(dataSet, meta) - dataSet.updates().onEach { - update(dataSet, meta, it) - }.launchIn(updatesScope) - - //close updates when the source is closed - updatesScope.launch { - dataSet.awaitClose() - close() - } - } - } else{ - DataTree(outputType){ - generate(dataSet, meta) + updatesScope: CoroutineScope + ): DataTree<R> = DataTree(outputType) { + generate(source, meta) + //propagate updates + launchUpdate(updatesScope) { + source.updates.onEach { update -> + update(source, meta, update) + }.collect() } } } + diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/Action.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/Action.kt index 5ed60db9..80898aa8 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/Action.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/Action.kt @@ -1,5 +1,8 @@ package space.kscience.dataforge.actions +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.misc.DFExperimental @@ -13,7 +16,7 @@ public fun interface Action<T, R> { * Transform the data in the node, producing a new node. By default, it is assumed that all calculations are lazy * so not actual computation is started at this moment. */ - public fun execute(dataSet: DataTree<T>, meta: Meta): DataTree<R> + public fun execute(source: DataTree<T>, meta: Meta, updatesScope: CoroutineScope): DataTree<R> public companion object } @@ -21,23 +24,27 @@ public fun interface Action<T, R> { /** * A convenience method to transform data using given [action] */ +@OptIn(DelicateCoroutinesApi::class) public fun <T, R> DataTree<T>.transform( action: Action<T, R>, meta: Meta = Meta.EMPTY, -): DataTree<R> = action.execute(this, meta) + updateScope: CoroutineScope = GlobalScope, +): DataTree<R> = action.execute(this, meta, updateScope) /** * Action composition. The result is terminal if one of its parts is terminal */ -public infix fun <T, I, R> Action<T, I>.then(action: Action<I, R>): Action<T, R> = Action { dataSet, meta -> - action.execute(this@then.execute(dataSet, meta), meta) +public infix fun <T, I, R> Action<T, I>.then(action: Action<I, R>): Action<T, R> = Action { dataSet, meta, scope -> + action.execute(this@then.execute(dataSet, meta, scope), meta, scope) } @DFExperimental +@OptIn(DelicateCoroutinesApi::class) public operator fun <T, R> Action<T, R>.invoke( dataSet: DataTree<T>, meta: Meta = Meta.EMPTY, -): DataTree<R> = execute(dataSet, meta) + updateScope: CoroutineScope = GlobalScope, +): DataTree<R> = execute(dataSet, meta, updateScope) diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt index 1f40ed73..08bf08e9 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/MapAction.kt @@ -6,8 +6,7 @@ import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.seal import space.kscience.dataforge.meta.toMutableMeta import space.kscience.dataforge.misc.DFBuilder -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import kotlin.reflect.KType import kotlin.reflect.typeOf @@ -49,13 +48,18 @@ public class MapActionBuilder<T, R>( public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(T) -> R1): Unit = result(typeOf<R1>(), f) } -@PublishedApi -internal class MapAction<T : Any, R : Any>( +@UnsafeKType +public class MapAction<T, R>( outputType: KType, private val block: MapActionBuilder<T, R>.() -> Unit, ) : AbstractAction<T, R>(outputType) { - private fun DataSink<R>.mapOne(name: Name, data: Data<T>, meta: Meta) { + private fun DataSink<R>.mapOne(name: Name, data: Data<T>?, meta: Meta) { + //fast return for null data + if (data == null) { + put(name, null) + return + } // Creating a new environment for action using **old** name, old meta and task meta val env = ActionEnv(name, data.meta, meta) @@ -74,7 +78,6 @@ internal class MapAction<T : Any, R : Any>( //getting new meta val newMeta = builder.meta.seal() - @OptIn(DFInternal::class) val newData = Data(builder.outputType, newMeta, dependencies = listOf(data)) { builder.result(env, data.await()) } @@ -82,12 +85,18 @@ internal class MapAction<T : Any, R : Any>( put(newName, newData) } - override fun DataSink<R>.generate(data: DataTree<T>, meta: Meta) { - data.forEach { mapOne(it.name, it.data, meta) } + override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) { + source.forEach { mapOne(it.name, it.data, meta) } } - override fun DataSink<R>.update(source: DataTree<T>, meta: Meta, namedData: NamedData<T>) { - mapOne(namedData.name, namedData.data, namedData.meta) + + + override suspend fun DataSink<R>.update( + source: DataTree<T>, + meta: Meta, + updatedData: DataUpdate<T>, + ) { + mapOne(updatedData.name, updatedData.data, meta) } } @@ -95,8 +104,9 @@ internal class MapAction<T : Any, R : Any>( /** * A one-to-one mapping action */ -@DFExperimental -public inline fun <T : Any, reified R : Any> Action.Companion.mapping( + +@OptIn(UnsafeKType::class) +public inline fun <T, reified R> Action.Companion.mapping( noinline builder: MapActionBuilder<T, R>.() -> Unit, ): Action<T, R> = MapAction(typeOf<R>(), builder) diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt index 9440be55..93278442 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/ReduceAction.kt @@ -4,15 +4,14 @@ import space.kscience.dataforge.data.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.misc.DFBuilder -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.parseAsName import kotlin.reflect.KType import kotlin.reflect.typeOf -public class JoinGroup<T : Any, R : Any>( +public class JoinGroup<T, R>( public var name: String, internal val set: DataTree<T>, @PublishedApi internal var outputType: KType, @@ -22,12 +21,12 @@ public class JoinGroup<T : Any, R : Any>( public lateinit var result: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R - internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) { + internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) { this.outputType = outputType this.result = f; } - public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) { + public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) { outputType = typeOf<R1>() this.result = f; } @@ -35,7 +34,7 @@ public class JoinGroup<T : Any, R : Any>( } @DFBuilder -public class ReduceGroupBuilder<T : Any, R : Any>( +public class ReduceGroupBuilder<T, R>( public val actionMeta: Meta, private val outputType: KType, ) { @@ -67,7 +66,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>( /** * Apply transformation to the whole node */ - public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R) { + public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R) { groupRules += { node -> listOf(JoinGroup<T, R>(resultName, node, outputType).apply { result(outputType, f) }) } @@ -79,14 +78,14 @@ public class ReduceGroupBuilder<T : Any, R : Any>( } @PublishedApi -internal class ReduceAction<T : Any, R : Any>( +internal class ReduceAction<T, R>( outputType: KType, private val action: ReduceGroupBuilder<T, R>.() -> Unit, ) : AbstractAction<T, R>(outputType) { //TODO optimize reduction. Currently, the whole action recalculates on push - override fun DataSink<R>.generate(data: DataTree<T>, meta: Meta) { - ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(data).forEach { group -> + override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) { + ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(source).forEach { group -> val dataFlow: Map<Name, Data<T>> = group.set.asSequence().fold(HashMap()) { acc, value -> acc.apply { acc[value.name] = value.data @@ -98,7 +97,7 @@ internal class ReduceAction<T : Any, R : Any>( val groupMeta = group.meta val env = ActionEnv(groupName.parseAsName(), groupMeta, meta) - @OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData( + @OptIn(UnsafeKType::class) val res: Data<R> = dataFlow.reduceToData( group.outputType, meta = groupMeta ) { group.result.invoke(env, it) } @@ -111,7 +110,6 @@ internal class ReduceAction<T : Any, R : Any>( /** * A one-to-one mapping action */ -@DFExperimental -public inline fun <reified T : Any, reified R : Any> Action.Companion.reducing( +public inline fun <reified T, reified R> Action.Companion.reducing( noinline builder: ReduceGroupBuilder<T, R>.() -> Unit, ): Action<T, R> = ReduceAction(typeOf<R>(), builder) diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt index 057419a7..2268b0fa 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/actions/SplitAction.kt @@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.toMutableMeta -import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.parseAsName import kotlin.collections.set @@ -13,9 +12,9 @@ import kotlin.reflect.KType import kotlin.reflect.typeOf -public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) { +public class SplitBuilder<T, R>(public val name: Name, public val meta: Meta) { - public class FragmentRule<T : Any, R : Any>( + public class FragmentRule<T, R>( public val name: Name, public var meta: MutableMeta, @PublishedApi internal var outputType: KType, @@ -44,15 +43,15 @@ public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val me * Action that splits each incoming element into a number of fragments defined in builder */ @PublishedApi -internal class SplitAction<T : Any, R : Any>( +internal class SplitAction<T, R>( outputType: KType, private val action: SplitBuilder<T, R>.() -> Unit, ) : AbstractAction<T, R>(outputType) { - private fun DataSink<R>.splitOne(name: Name, data: Data<T>, meta: Meta) { - val laminate = Laminate(data.meta, meta) + private fun DataSink<R>.splitOne(name: Name, data: Data<T>?, meta: Meta) { + val laminate = Laminate(data?.meta, meta) - val split = SplitBuilder<T, R>(name, data.meta).apply(action) + val split = SplitBuilder<T, R>(name, data?.meta ?: Meta.EMPTY).apply(action) // apply individual fragment rules to result @@ -64,28 +63,36 @@ internal class SplitAction<T : Any, R : Any>( ).apply(rule) //data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName) - put( - fragmentName, - @Suppress("OPT_IN_USAGE") Data(outputType, meta = env.meta, dependencies = listOf(data)) { - env.result(data.await()) - } - ) + if (data == null) { + put(fragmentName, null) + } else { + put( + fragmentName, + @Suppress("OPT_IN_USAGE") Data(outputType, meta = env.meta, dependencies = listOf(data)) { + env.result(data.await()) + } + ) + } } } - override fun DataSink<R>.generate(data: DataTree<T>, meta: Meta) { - data.forEach { splitOne(it.name, it.data, meta) } + override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) { + source.forEach { splitOne(it.name, it.data, meta) } } - override fun DataSink<R>.update(source: DataTree<T>, meta: Meta, namedData: NamedData<T>) { - splitOne(namedData.name, namedData.data, namedData.meta) + override suspend fun DataSink<R>.update( + source: DataTree<T>, + meta: Meta, + updatedData: DataUpdate<T>, + ) { + splitOne(updatedData.name, updatedData.data, meta) } } /** * Action that splits each incoming element into a number of fragments defined in builder */ -@DFExperimental -public inline fun <T : Any, reified R : Any> Action.Companion.splitting( + +public inline fun <T, reified R> Action.Companion.splitting( noinline builder: SplitBuilder<T, R>.() -> Unit, ): Action<T, R> = SplitAction(typeOf<R>(), builder) \ No newline at end of file diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/Data.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/Data.kt index a0bb58ea..b9946a48 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/Data.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/Data.kt @@ -4,8 +4,8 @@ import kotlinx.coroutines.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MetaRepr import space.kscience.dataforge.meta.isEmpty -import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DfType +import space.kscience.dataforge.misc.UnsafeKType import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlin.reflect.KType @@ -41,7 +41,7 @@ public interface Data<out T> : Goal<T>, MetaRepr { */ internal val TYPE_OF_NOTHING: KType = typeOf<Unit>() - public inline fun <reified T> static( + public inline fun <reified T> wrapValue( value: T, meta: Meta = Meta.EMPTY, ): Data<T> = StaticData(typeOf<T>(), value, meta) @@ -50,10 +50,10 @@ public interface Data<out T> : Goal<T>, MetaRepr { * An empty data containing only meta */ @OptIn(DelicateCoroutinesApi::class) - public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> { - override val type: KType = TYPE_OF_NOTHING + public fun buildEmpty(meta: Meta): Data<Nothing> = object : Data<Nothing> { + override val type: KType get() = TYPE_OF_NOTHING override val meta: Meta = meta - override val dependencies: Collection<Goal<*>> = emptyList() + override val dependencies: Collection<Goal<*>> get() = emptyList() override val deferred: Deferred<Nothing> get() = GlobalScope.async(start = CoroutineStart.LAZY) { error("The Data is empty and could not be computed") @@ -62,6 +62,8 @@ public interface Data<out T> : Goal<T>, MetaRepr { override fun async(coroutineScope: CoroutineScope): Deferred<Nothing> = deferred override fun reset() {} } + + public val EMPTY: Data<Nothing> = buildEmpty(Meta.EMPTY) } } @@ -87,7 +89,7 @@ public class StaticData<T>( public inline fun <reified T> Data(value: T, meta: Meta = Meta.EMPTY): StaticData<T> = StaticData(typeOf<T>(), value, meta) -@DFInternal +@UnsafeKType public fun <T> Data( type: KType, meta: Meta = Meta.EMPTY, @@ -96,7 +98,7 @@ public fun <T> Data( block: suspend () -> T, ): Data<T> = LazyData(type, meta, context, dependencies, block) -@OptIn(DFInternal::class) +@OptIn(UnsafeKType::class) public inline fun <reified T> Data( meta: Meta = Meta.EMPTY, context: CoroutineContext = EmptyCoroutineContext, diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataFilter.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataFilter.kt index f45570ad..38174e50 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataFilter.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataFilter.kt @@ -1,28 +1,30 @@ package space.kscience.dataforge.data -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.NameToken +import space.kscience.dataforge.names.plus import kotlin.reflect.KType public fun interface DataFilter { - public fun accepts(name: Name, meta: Meta, type: KType): Boolean + public fun accepts(name: Name, meta: Meta?, type: KType): Boolean public companion object { public val EMPTY: DataFilter = DataFilter { _, _, _ -> true } } } -public fun DataFilter.accepts(data: NamedData<*>): Boolean = accepts(data.name, data.meta, data.type) -public fun <T> Sequence<NamedData<T>>.filterData(predicate: DataFilter): Sequence<NamedData<T>> = filter { data -> +public fun DataFilter.accepts(update: DataUpdate<*>): Boolean = accepts(update.name, update.data?.meta, update.type) + +public fun <T, DU : DataUpdate<T>> Sequence<DU>.filterData(predicate: DataFilter): Sequence<DU> = filter { data -> predicate.accepts(data) } -public fun <T> Flow<NamedData<T>>.filterData(predicate: DataFilter): Flow<NamedData<T>> = filter { data -> +public fun <T, DU : DataUpdate<T>> Flow<DU>.filterData(predicate: DataFilter): Flow<DU> = filter { data -> predicate.accepts(data) } @@ -41,7 +43,8 @@ public fun <T> DataSource<T>.filterData( public fun <T> ObservableDataSource<T>.filterData( predicate: DataFilter, ): ObservableDataSource<T> = object : ObservableDataSource<T> { - override fun updates(): Flow<NamedData<T>> = this@filterData.updates().filter { predicate.accepts(it) } + override val updates: Flow<DataUpdate<T>> + get() = this@filterData.updates.filter { predicate.accepts(it) } override val dataType: KType get() = this@filterData.dataType @@ -49,14 +52,32 @@ public fun <T> ObservableDataSource<T>.filterData( this@filterData.read(name)?.takeIf { predicate.accepts(name, it.meta, it.type) } } -public fun <T> GenericDataTree<T, *>.filterData( - predicate: DataFilter, -): DataTree<T> = asSequence().filterData(predicate).toTree(dataType) +internal class FilteredDataTree<T>( + val source: DataTree<T>, + val filter: DataFilter, + val branch: Name, + override val dataType: KType = source.dataType, +) : DataTree<T> { -public fun <T> GenericObservableDataTree<T, *>.filterData( - scope: CoroutineScope, + override val data: Data<T>? + get() = source[branch].takeIf { + filter.accepts(Name.EMPTY, it?.meta, it?.type ?: dataType) + } + + override val items: Map<NameToken, DataTree<T>> + get() = source.branch(branch)?.items + ?.mapValues { FilteredDataTree(source, filter, branch + it.key) } + ?.filter { !it.value.isEmpty() } + ?: emptyMap() + + override val updates: Flow<DataUpdate<T>> + get() = source.updates.filter { filter.accepts(it) } +} + + +public fun <T> DataTree<T>.filterData( predicate: DataFilter, -): ObservableDataTree<T> = asSequence().filterData(predicate).toObservableTree(dataType, scope, updates().filterData(predicate)) +): DataTree<T> = FilteredDataTree(this, predicate, Name.EMPTY) ///** diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSink.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSink.kt new file mode 100644 index 00000000..6daeae98 --- /dev/null +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSink.kt @@ -0,0 +1,159 @@ +package space.kscience.dataforge.data + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.launch +import space.kscience.dataforge.misc.UnsafeKType +import space.kscience.dataforge.names.* +import kotlin.reflect.KType +import kotlin.reflect.typeOf + +public interface DataSink<in T> { + /** + * Put data without notification + */ + public fun put(name: Name, data: Data<T>?) + + /** + * Put data and propagate changes downstream + */ + public suspend fun update(name: Name, data: Data<T>?) +} + +/** + * Launch continuous update using + */ +public fun <T> DataSink<T>.launchUpdate( + scope: CoroutineScope, + updater: suspend DataSink<T>.() -> Unit, +): Job = scope.launch { + object : DataSink<T> { + override fun put(name: Name, data: Data<T>?) { + launch { + this@launchUpdate.update(name, data) + } + } + + override suspend fun update(name: Name, data: Data<T>?) { + this@launchUpdate.update(name, data) + } + }.updater() +} + +/** + * A mutable version of [DataTree] + */ +public interface MutableDataTree<T> : DataTree<T>, DataSink<T> { + override var data: Data<T>? + + override val items: Map<NameToken, MutableDataTree<T>> + + public fun getOrCreateItem(token: NameToken): MutableDataTree<T> + + public operator fun set(token: NameToken, data: Data<T>?) + + override fun put(name: Name, data: Data<T>?): Unit = set(name, data) +} + +public tailrec operator fun <T> MutableDataTree<T>.set(name: Name, data: Data<T>?): Unit { + when (name.length) { + 0 -> this.data = data + 1 -> set(name.first(), data) + else -> getOrCreateItem(name.first())[name.cutFirst()] = data + } +} + +/** + * Provide a mutable subtree if it exists + */ +public tailrec fun <T> MutableDataTree<T>.branch(name: Name): MutableDataTree<T>? = + when (name.length) { + 0 -> this + 1 -> items[name.first()] + else -> items[name.first()]?.branch(name.cutFirst()) + } + +private class MutableDataTreeRoot<T>( + override val dataType: KType, +) : MutableDataTree<T> { + + override val updates = MutableSharedFlow<DataUpdate<T>>(100, onBufferOverflow = BufferOverflow.DROP_LATEST) + + + inner class MutableDataTreeBranch(val branchName: Name) : MutableDataTree<T> { + + override var data: Data<T>? = null + + override val items = HashMap<NameToken, MutableDataTree<T>>() + + override val updates: Flow<DataUpdate<T>> = this@MutableDataTreeRoot.updates.mapNotNull { update -> + update.name.removeFirstOrNull(branchName)?.let { + DataUpdate(update.data?.type ?: dataType, it, update.data) + } + } + override val dataType: KType get() = this@MutableDataTreeRoot.dataType + + + override fun getOrCreateItem(token: NameToken): MutableDataTree<T> = + items.getOrPut(token) { MutableDataTreeBranch(branchName + token) } + + + override fun set(token: NameToken, data: Data<T>?) { + val subTree = getOrCreateItem(token) + subTree.data = data + } + + override suspend fun update(name: Name, data: Data<T>?) { + if (name.isEmpty()) { + this.data = data + this@MutableDataTreeRoot.updates.emit(DataUpdate(data?.type ?: dataType, branchName + name, data)) + } else { + getOrCreateItem(name.first()).update(name.cutFirst(), data) + } + } + + } + + + override var data: Data<T>? = null + + override val items = HashMap<NameToken, MutableDataTree<T>>() + + override fun getOrCreateItem(token: NameToken): MutableDataTree<T> = items.getOrPut(token) { + MutableDataTreeBranch(token.asName()) + } + + override fun set(token: NameToken, data: Data<T>?) { + val subTree = getOrCreateItem(token) + subTree.data = data + } + + override suspend fun update(name: Name, data: Data<T>?) { + if (name.isEmpty()) { + this.data = data + updates.emit(DataUpdate(data?.type ?: dataType, name, data)) + } else { + getOrCreateItem(name.first()).update(name.cutFirst(), data) + } + } +} + +/** + * Create a new [MutableDataTree] + */ +@UnsafeKType +public fun <T> MutableDataTree( + type: KType, +): MutableDataTree<T> = MutableDataTreeRoot<T>(type) + +/** + * Create and initialize a observable mutable data tree. + */ +@OptIn(UnsafeKType::class) +public inline fun <reified T> MutableDataTree( + generator: MutableDataTree<T>.() -> Unit = {}, +): MutableDataTree<T> = MutableDataTree<T>(typeOf<T>()).apply { generator() } \ No newline at end of file diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSource.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSource.kt index d379d027..a9756be7 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSource.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/DataSource.kt @@ -1,9 +1,8 @@ package space.kscience.dataforge.data -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emptyFlow import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.names.* import kotlin.contracts.contract import kotlin.reflect.KType @@ -33,46 +32,42 @@ public interface ObservableDataSource<out T> : DataSource<T> { /** * Flow updates made to the data */ - public fun updates(): Flow<NamedData<T>> + public val updates: Flow<DataUpdate<T>> } /** * A tree like structure for data holding */ -public interface GenericDataTree<out T, out TR : GenericDataTree<T, TR>> : DataSource<T> { - public val self: TR +public interface DataTree<out T> : ObservableDataSource<T> { public val data: Data<T>? - public val items: Map<NameToken, TR> - + public val items: Map<NameToken, DataTree<T>> override fun read(name: Name): Data<T>? = when (name.length) { 0 -> data else -> items[name.first()]?.read(name.cutFirst()) } + /** + * Flow updates made to the data + */ + override val updates: Flow<DataUpdate<T>> + public companion object { - private object EmptyDataTree : GenericDataTree<Nothing, EmptyDataTree> { - override val self: EmptyDataTree get() = this + private object EmptyDataTree : + DataTree<Nothing> { override val data: Data<Nothing>? = null override val items: Map<NameToken, EmptyDataTree> = emptyMap() override val dataType: KType = typeOf<Unit>() override fun read(name: Name): Data<Nothing>? = null - + override val updates: Flow<DataUpdate<Nothing>> get() = emptyFlow() } - public val EMPTY: GenericDataTree<Nothing, *> = EmptyDataTree + public val EMPTY: DataTree<Nothing> = EmptyDataTree } } -public typealias DataTree<T> = GenericDataTree<T, GenericDataTree<T, *>> - -/** - * Return a single data in this tree. Throw error if it is not single. - */ -public fun <T> DataTree<T>.single(): NamedData<T> = asSequence().single() - /** * An alias for easier access to tree values */ @@ -93,238 +88,44 @@ public fun <T> DataTree<T>.asSequence( } } +/** + * Walk the data tree depth-first. + * + * @return a [Sequence] of pairs [Name]-[DataTree] for all nodes including the root one. + */ +public fun <T> DataTree<T>.walk( + namePrefix: Name = Name.EMPTY, +): Sequence<Pair<Name, DataTree<T>>> = sequence { + yield(namePrefix to this@walk) + items.forEach { (token, tree) -> + yieldAll(tree.walk(namePrefix + token)) + } +} + public val DataTree<*>.meta: Meta? get() = data?.meta /** * Provide subtree if it exists */ -public tailrec fun <T, TR : GenericDataTree<T, TR>> GenericDataTree<T, TR>.branch(name: Name): TR? = +public tailrec fun <T> DataTree<T>.branch(name: Name): DataTree<T>? = when (name.length) { - 0 -> self + 0 -> this 1 -> items[name.first()] else -> items[name.first()]?.branch(name.cutFirst()) } -public fun <T, TR : GenericDataTree<T, TR>> GenericDataTree<T, TR>.branch(name: String): TR? = +public fun <T> DataTree<T>.branch(name: String): DataTree<T>? = branch(name.parseAsName()) -public fun GenericDataTree<*, *>.isEmpty(): Boolean = data == null && items.isEmpty() - -@PublishedApi -internal class FlatDataTree<T>( - override val dataType: KType, - private val dataSet: Map<Name, Data<T>>, - private val prefix: Name, -) : GenericDataTree<T, FlatDataTree<T>> { - override val self: FlatDataTree<T> get() = this - override val data: Data<T>? get() = dataSet[prefix] - override val items: Map<NameToken, FlatDataTree<T>> - get() = dataSet.keys - .filter { it.startsWith(prefix) && it.length > prefix.length } - .map { it.tokens[prefix.length] } - .associateWith { FlatDataTree(dataType, dataSet, prefix + it) } - - override fun read(name: Name): Data<T>? = dataSet[prefix + name] -} - -/** - * Represent this flat data map as a [DataTree] without copying it - */ -public inline fun <reified T> Map<Name, Data<T>>.asTree(): DataTree<T> = FlatDataTree(typeOf<T>(), this, Name.EMPTY) - -internal fun <T> Sequence<NamedData<T>>.toTree(type: KType): DataTree<T> = - FlatDataTree(type, associate { it.name to it.data }, Name.EMPTY) - -/** - * Collect a sequence of [NamedData] to a [DataTree] - */ -public inline fun <reified T> Sequence<NamedData<T>>.toTree(): DataTree<T> = - FlatDataTree(typeOf<T>(), associate { it.name to it.data }, Name.EMPTY) - -public interface GenericObservableDataTree<out T, out TR : GenericObservableDataTree<T, TR>> : - GenericDataTree<T, TR>, ObservableDataSource<T>, AutoCloseable { - - /** - * A scope that is used to propagate updates. When this scope is closed, no new updates could arrive. - */ - public val updatesScope: CoroutineScope - - /** - * Close this data tree updates channel - */ - override fun close() { - updatesScope.cancel() - } - -} - -public typealias ObservableDataTree<T> = GenericObservableDataTree<T, GenericObservableDataTree<T, *>> +public fun DataTree<*>.isEmpty(): Boolean = data == null && items.isEmpty() /** * Check if the [DataTree] is observable */ -public fun <T> DataTree<T>.isObservable(): Boolean { +public fun <T> DataSource<T>.isObservable(): Boolean { contract { - returns(true) implies (this@isObservable is GenericObservableDataTree<T, *>) + returns(true) implies (this@isObservable is ObservableDataSource<T>) } - return this is GenericObservableDataTree<T, *> + return this is ObservableDataSource<T> } -/** - * Wait for this data tree to stop spawning updates (updatesScope is closed). - * If this [DataTree] is not observable, return immediately. - */ -public suspend fun <T> DataTree<T>.awaitClose() { - if (isObservable()) { - updatesScope.coroutineContext[Job]?.join() - } -} - -public fun <T> DataTree<T>.updates(): Flow<NamedData<T>> = - if (this is GenericObservableDataTree<T, *>) updates() else emptyFlow() - -public fun interface DataSink<in T> { - public fun put(name: Name, data: Data<T>?) -} - -@DFInternal -public class DataTreeBuilder<T>(private val type: KType) : DataSink<T> { - private val map = HashMap<Name, Data<T>>() - override fun put(name: Name, data: Data<T>?) { - if (data == null) { - map.remove(name) - } else { - map[name] = data - } - } - - public fun build(): DataTree<T> = FlatDataTree(type, map, Name.EMPTY) -} - -@DFInternal -public inline fun <T> DataTree( - dataType: KType, - generator: DataSink<T>.() -> Unit, -): DataTree<T> = DataTreeBuilder<T>(dataType).apply(generator).build() - -/** - * Create and a data tree. - */ -@OptIn(DFInternal::class) -public inline fun <reified T> DataTree( - generator: DataSink<T>.() -> Unit, -): DataTree<T> = DataTreeBuilder<T>(typeOf<T>()).apply(generator).build() - -/** - * A mutable version of [GenericDataTree] - */ -public interface MutableDataTree<T> : GenericObservableDataTree<T, MutableDataTree<T>>, DataSink<T> { - override var data: Data<T>? - - override val items: Map<NameToken, MutableDataTree<T>> - - public fun getOrCreateItem(token: NameToken): MutableDataTree<T> - - public operator fun set(token: NameToken, data: Data<T>?) - - override fun put(name: Name, data: Data<T>?): Unit = set(name, data) -} - -public tailrec operator fun <T> MutableDataTree<T>.set(name: Name, data: Data<T>?): Unit { - when (name.length) { - 0 -> this.data = data - 1 -> set(name.first(), data) - else -> getOrCreateItem(name.first())[name.cutFirst()] = data - } -} - -private class MutableDataTreeImpl<T>( - override val dataType: KType, - override val updatesScope: CoroutineScope, -) : MutableDataTree<T> { - - - private val updates = MutableSharedFlow<NamedData<T>>() - - private val children = HashMap<NameToken, MutableDataTree<T>>() - - override var data: Data<T>? = null - set(value) { - if (!updatesScope.isActive) error("Can't send updates to closed MutableDataTree") - field = value - if (value != null) { - updatesScope.launch { - updates.emit(value.named(Name.EMPTY)) - } - } - } - - override val items: Map<NameToken, MutableDataTree<T>> get() = children - - override fun getOrCreateItem(token: NameToken): MutableDataTree<T> = children.getOrPut(token){ - MutableDataTreeImpl(dataType, updatesScope) - } - - override val self: MutableDataTree<T> get() = this - - override fun set(token: NameToken, data: Data<T>?) { - if (!updatesScope.isActive) error("Can't send updates to closed MutableDataTree") - val subTree = getOrCreateItem(token) - subTree.updates().onEach { - updates.emit(it.named(token + it.name)) - }.launchIn(updatesScope) - subTree.data = data - } - - override fun updates(): Flow<NamedData<T>> = updates -} - -/** - * Create a new [MutableDataTree] - * - * @param parentScope a [CoroutineScope] to control data propagation. By default uses [GlobalScope] - */ -@OptIn(DelicateCoroutinesApi::class) -public fun <T> MutableDataTree( - type: KType, - parentScope: CoroutineScope = GlobalScope, -): MutableDataTree<T> = MutableDataTreeImpl<T>( - type, - CoroutineScope(parentScope.coroutineContext + Job(parentScope.coroutineContext[Job])) -) - -/** - * Create and initialize a observable mutable data tree. - */ -@OptIn(DelicateCoroutinesApi::class) -public inline fun <reified T> MutableDataTree( - parentScope: CoroutineScope = GlobalScope, - generator: MutableDataTree<T>.() -> Unit = {}, -): MutableDataTree<T> = MutableDataTree<T>(typeOf<T>(), parentScope).apply { generator() } - -//@DFInternal -//public fun <T> ObservableDataTree( -// type: KType, -// scope: CoroutineScope, -// generator: suspend MutableDataTree<T>.() -> Unit = {}, -//): ObservableDataTree<T> = MutableDataTree<T>(type, scope.coroutineContext).apply(generator) - -public inline fun <reified T> ObservableDataTree( - parentScope: CoroutineScope, - generator: MutableDataTree<T>.() -> Unit = {}, -): ObservableDataTree<T> = MutableDataTree<T>(typeOf<T>(), parentScope).apply(generator) - - -/** - * Collect a [Sequence] into an observable tree with additional [updates] - */ -public fun <T> Sequence<NamedData<T>>.toObservableTree( - dataType: KType, - parentScope: CoroutineScope, - updates: Flow<NamedData<T>>, -): ObservableDataTree<T> = MutableDataTree<T>(dataType, parentScope).apply { - this.putAll(this@toObservableTree) - updates.onEach { - put(it.name, it.data) - }.launchIn(updatesScope) -} diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GroupRule.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GroupRule.kt index 90486d85..6dd3caa9 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GroupRule.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/GroupRule.kt @@ -17,10 +17,10 @@ package space.kscience.dataforge.data import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.string -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType public interface GroupRule { - public fun <T : Any> gather(set: DataTree<T>): Map<String, DataTree<T>> + public fun <T> gather(set: DataTree<T>): Map<String, DataTree<T>> public companion object { /** @@ -31,24 +31,24 @@ public interface GroupRule { * @param defaultTagValue * @return */ - @OptIn(DFInternal::class) + @OptIn(UnsafeKType::class) public fun byMetaValue( key: String, defaultTagValue: String, ): GroupRule = object : GroupRule { - override fun <T : Any> gather( + override fun <T> gather( set: DataTree<T>, ): Map<String, DataTree<T>> { - val map = HashMap<String, DataTreeBuilder<T>>() + val map = HashMap<String, MutableDataTree<T>>() set.forEach { data -> val tagValue: String = data.meta[key]?.string ?: defaultTagValue - map.getOrPut(tagValue) { DataTreeBuilder(set.dataType) }.put(data.name, data.data) + map.getOrPut(tagValue) { MutableDataTree(set.dataType) }.put(data.name, data.data) } - return map.mapValues { it.value.build() } + return map } } } diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/MetaMaskData.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/MetaMaskData.kt index acf2410d..85f0b2f9 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/MetaMaskData.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/MetaMaskData.kt @@ -20,4 +20,4 @@ public fun <T> Data<T>.withMeta(newMeta: Meta): Data<T> = if (this is MetaMaskDa * Create a new [Data] with the same computation, but different meta. The meta is created by applying [block] to * the existing data meta. */ -public inline fun <T> Data<T>.mapMeta(block: MutableMeta.() -> Unit): Data<T> = withMeta(meta.copy(block)) \ No newline at end of file +public inline fun <T> Data<T>.withMeta(block: MutableMeta.() -> Unit): Data<T> = withMeta(meta.copy(block)) \ No newline at end of file diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/NamedData.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/NamedData.kt index 63e36a3f..9cb4c2d9 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/NamedData.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/NamedData.kt @@ -3,14 +3,34 @@ package space.kscience.dataforge.data import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.misc.Named import space.kscience.dataforge.names.Name +import kotlin.reflect.KType -public interface NamedData<out T> : Named, Data<T> { +/** + * An interface implementing a data update event. + * + * If [data] is null, then corresponding element should be removed. + */ +public interface DataUpdate<out T> : Named { + public val type: KType override val name: Name - public val data: Data<T> + public val data: Data<T>? +} + +public fun <T> DataUpdate(type: KType, name: Name, data: Data<T>?): DataUpdate<T> = object : DataUpdate<T> { + override val type: KType = type + override val name: Name = name + override val data: Data<T>? = data +} + +/** + * A data coupled to a name. + */ +public interface NamedData<out T> : DataUpdate<T>, Data<T> { + override val data: Data<T> } public operator fun NamedData<*>.component1(): Name = name -public operator fun <T: Any> NamedData<T>.component2(): Data<T> = data +public operator fun <T> NamedData<T>.component2(): Data<T> = data private class NamedDataImpl<T>( override val name: Name, @@ -32,4 +52,6 @@ public fun <T> Data<T>.named(name: Name): NamedData<T> = if (this is NamedData) NamedDataImpl(name, this.data) } else { NamedDataImpl(name, this) -} \ No newline at end of file +} + +public fun <T> NamedData(name: Name, data: Data<T>): NamedData<T> = data.named(name) \ No newline at end of file diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataBuilders.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataBuilders.kt index 8e8b6eaa..649cfd19 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataBuilders.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataBuilders.kt @@ -1,62 +1,64 @@ package space.kscience.dataforge.data +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.asName -import space.kscience.dataforge.names.isEmpty -import space.kscience.dataforge.names.plus +import space.kscience.dataforge.names.* public fun <T> DataSink<T>.put(value: NamedData<T>) { put(value.name, value.data) } -public fun <T> DataSink<T>.branch(dataTree: DataTree<T>) { - putAll(dataTree.asSequence()) -} - -public inline fun <T> DataSink<T>.branch( +public inline fun <T> DataSink<T>.putAll( prefix: Name, block: DataSink<T>.() -> Unit, ) { if (prefix.isEmpty()) { apply(block) } else { - val proxyDataSink = DataSink { nameWithoutPrefix, data -> - this.put(prefix + nameWithoutPrefix, data) + val proxyDataSink = object :DataSink<T>{ + override fun put(name: Name, data: Data<T>?) { + this@putAll.put(prefix + name, data) + } + + override suspend fun update(name: Name, data: Data<T>?) { + this@putAll.update(prefix + name, data) + } + } proxyDataSink.apply(block) } } -public inline fun <T> DataSink<T>.branch( + +public inline fun <T> DataSink<T>.putAll( prefix: String, block: DataSink<T>.() -> Unit, -): Unit = branch(prefix.asName(), block) +): Unit = putAll(prefix.asName(), block) public fun <T> DataSink<T>.put(name: String, value: Data<T>) { put(Name.parse(name), value) } -public fun <T> DataSink<T>.branch(name: Name, set: DataTree<T>) { - branch(name) { putAll(set.asSequence()) } +public fun <T> DataSink<T>.putAll(name: Name, tree: DataTree<T>) { + putAll(name) { putAll(tree.asSequence()) } } -public fun <T> DataSink<T>.branch(name: String, set: DataTree<T>) { - branch(Name.parse(name)) { putAll(set.asSequence()) } + +public fun <T> DataSink<T>.putAll(name: String, tree: DataTree<T>) { + putAll(Name.parse(name)) { putAll(tree.asSequence()) } } /** * Produce lazy [Data] and emit it into the [MutableDataTree] */ -public inline fun <reified T> DataSink<T>.put( +public inline fun <reified T> DataSink<T>.putValue( name: String, meta: Meta = Meta.EMPTY, noinline producer: suspend () -> T, @@ -65,7 +67,7 @@ public inline fun <reified T> DataSink<T>.put( put(name, data) } -public inline fun <reified T> DataSink<T>.put( +public inline fun <reified T> DataSink<T>.putValue( name: Name, meta: Meta = Meta.EMPTY, noinline producer: suspend () -> T, @@ -77,24 +79,35 @@ public inline fun <reified T> DataSink<T>.put( /** * Emit static data with the fixed value */ -public inline fun <reified T> DataSink<T>.wrap( - name: String, - data: T, - meta: Meta = Meta.EMPTY, -): Unit = put(name, Data.static(data, meta)) - -public inline fun <reified T> DataSink<T>.wrap( +public inline fun <reified T> DataSink<T>.putValue( name: Name, - data: T, + value: T, meta: Meta = Meta.EMPTY, -): Unit = put(name, Data.static(data, meta)) +): Unit = put(name, Data.wrapValue(value, meta)) -public inline fun <reified T> DataSink<T>.wrap( +public inline fun <reified T> DataSink<T>.putValue( name: String, - data: T, - mutableMeta: MutableMeta.() -> Unit, -): Unit = put(Name.parse(name), Data.static(data, Meta(mutableMeta))) + value: T, + meta: Meta = Meta.EMPTY, +): Unit = put(name, Data.wrapValue(value, meta)) +public inline fun <reified T> DataSink<T>.putValue( + name: String, + value: T, + metaBuilder: MutableMeta.() -> Unit, +): Unit = put(Name.parse(name), Data.wrapValue(value, Meta(metaBuilder))) + +public suspend inline fun <reified T> DataSink<T>.updateValue( + name: Name, + value: T, + meta: Meta = Meta.EMPTY, +): Unit = update(name, Data.wrapValue(value, meta)) + +public suspend inline fun <reified T> DataSink<T>.updateValue( + name: String, + value: T, + meta: Meta = Meta.EMPTY, +): Unit = update(name.parseAsName(), Data.wrapValue(value, meta)) public fun <T> DataSink<T>.putAll(sequence: Sequence<NamedData<T>>) { sequence.forEach { @@ -103,30 +116,19 @@ public fun <T> DataSink<T>.putAll(sequence: Sequence<NamedData<T>>) { } public fun <T> DataSink<T>.putAll(tree: DataTree<T>) { - this.putAll(tree.asSequence()) -} - - -/** - * Update data with given node data and meta with node meta. - */ -@DFExperimental -public fun <T> MutableDataTree<T>.putAll(source: DataTree<T>) { - source.forEach { - put(it.name, it.data) - } + putAll(tree.asSequence()) } /** * Copy given data set and mirror its changes to this [DataSink] in [this@setAndObserve]. Returns an update [Job] */ -public fun <T : Any> DataSink<T>.watchBranch( - name: Name, - dataSet: ObservableDataTree<T>, +public fun <T : Any> DataSink<T>.putAllAndWatch( + scope: CoroutineScope, + branchName: Name = Name.EMPTY, + source: DataTree<T>, ): Job { - branch(name, dataSet) - return dataSet.updates().onEach { - put(name + it.name, it.data) - }.launchIn(dataSet.updatesScope) - + putAll(branchName, source) + return source.updates.onEach { + update(branchName + it.name, it.data) + }.launchIn(scope) } \ No newline at end of file diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTransform.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTransform.kt index 8c7ce70e..c0d92e9e 100644 --- a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTransform.kt +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTransform.kt @@ -1,7 +1,7 @@ package space.kscience.dataforge.data import space.kscience.dataforge.meta.* -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import kotlin.coroutines.CoroutineContext @@ -18,6 +18,24 @@ public data class NamedValueWithMeta<T>(val name: Name, val value: T, val meta: public suspend fun <T> NamedData<T>.awaitWithMeta(): NamedValueWithMeta<T> = NamedValueWithMeta(name, await(), meta) +/** + * Lazily transform this data to another data. By convention [block] should not use external data (be pure). + * @param type explicit type of the resulting [Data] + * @param coroutineContext additional [CoroutineContext] elements used for data computation. + * @param meta for the resulting data. By default equals input data. + * @param block the transformation itself + */ +@UnsafeKType +public fun <T, R> Data<T>.transform( + type: KType, + meta: Meta = this.meta, + coroutineContext: CoroutineContext = EmptyCoroutineContext, + block: suspend (T) -> R, +): Data<R> = Data(type, meta, coroutineContext, listOf(this)) { + block(await()) +} + + /** * Lazily transform this data to another data. By convention [block] should not use external data (be pure). @@ -68,7 +86,7 @@ internal fun Map<*, Data<*>>.joinMeta(): Meta = Meta { } } -@DFInternal +@UnsafeKType public fun <K, T, R> Map<K, Data<T>>.reduceToData( outputType: KType, meta: Meta = joinMeta(), @@ -103,7 +121,7 @@ public inline fun <K, T, reified R> Map<K, Data<T>>.reduceToData( //Iterable operations -@DFInternal +@UnsafeKType public inline fun <T, R> Iterable<Data<T>>.reduceToData( outputType: KType, meta: Meta = joinMeta(), @@ -118,7 +136,7 @@ public inline fun <T, R> Iterable<Data<T>>.reduceToData( transformation(map { it.awaitWithMeta() }) } -@OptIn(DFInternal::class) +@OptIn(UnsafeKType::class) public inline fun <T, reified R> Iterable<Data<T>>.reduceToData( meta: Meta = joinMeta(), coroutineContext: CoroutineContext = EmptyCoroutineContext, @@ -141,7 +159,7 @@ public inline fun <T, reified R> Iterable<Data<T>>.foldToData( /** * Transform an [Iterable] of [NamedData] to a single [Data]. */ -@DFInternal +@UnsafeKType public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData( outputType: KType, meta: Meta = joinMeta(), @@ -156,7 +174,7 @@ public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData( transformation(map { it.awaitWithMeta() }) } -@OptIn(DFInternal::class) +@OptIn(UnsafeKType::class) public inline fun <T, reified R> Iterable<NamedData<T>>.reduceNamedToData( meta: Meta = joinMeta(), coroutineContext: CoroutineContext = EmptyCoroutineContext, @@ -181,7 +199,8 @@ public inline fun <T, reified R> Iterable<NamedData<T>>.foldNamedToData( //DataSet operations -@DFInternal + +@UnsafeKType public suspend fun <T, R> DataTree<T>.transform( outputType: KType, metaTransform: MutableMeta.() -> Unit = {}, @@ -198,7 +217,7 @@ public suspend fun <T, R> DataTree<T>.transform( } } -@OptIn(DFInternal::class) +@OptIn(UnsafeKType::class) public suspend inline fun <T, reified R> DataTree<T>.transform( noinline metaTransform: MutableMeta.() -> Unit = {}, coroutineContext: CoroutineContext = EmptyCoroutineContext, diff --git a/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTreeBuilder.kt b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTreeBuilder.kt new file mode 100644 index 00000000..ac0492f0 --- /dev/null +++ b/dataforge-data/src/commonMain/kotlin/space/kscience/dataforge/data/dataTreeBuilder.kt @@ -0,0 +1,112 @@ +package space.kscience.dataforge.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import space.kscience.dataforge.misc.UnsafeKType +import space.kscience.dataforge.names.* +import kotlin.reflect.KType +import kotlin.reflect.typeOf + + +private class FlatDataTree<T>( + override val dataType: KType, + private val dataSet: Map<Name, Data<T>>, + private val sourceUpdates: Flow<DataUpdate<T>>, + private val prefix: Name, +) : DataTree<T> { + override val data: Data<T>? get() = dataSet[prefix] + override val items: Map<NameToken, FlatDataTree<T>> + get() = dataSet.keys + .filter { it.startsWith(prefix) && it.length > prefix.length } + .map { it.tokens[prefix.length] } + .associateWith { FlatDataTree(dataType, dataSet, sourceUpdates, prefix + it) } + + override fun read(name: Name): Data<T>? = dataSet[prefix + name] + + override val updates: Flow<DataUpdate<T>> = + sourceUpdates.mapNotNull { update -> + update.name.removeFirstOrNull(prefix)?.let { DataUpdate(dataType, it, update.data) } + } +} + +/** + * A builder for static [DataTree]. + */ +private class DataTreeBuilder<T>( + private val type: KType, + initialData: Map<Name, Data<T>> = emptyMap(), +) : DataSink<T> { + + private val map = HashMap<Name, Data<T>>(initialData) + + private val mutex = Mutex() + + private val updatesFlow = MutableSharedFlow<DataUpdate<T>>() + + override fun put(name: Name, data: Data<T>?) { + if (data == null) { + map.remove(name) + } else { + map[name] = data + } + } + + override suspend fun update(name: Name, data: Data<T>?) { + mutex.withLock { + if (data == null) { + map.remove(name) + } else { + map.put(name, data) + } + } + updatesFlow.emit(DataUpdate(data?.type ?: type, name, data)) + } + + public fun build(): DataTree<T> = FlatDataTree(type, map, updatesFlow, Name.EMPTY) +} + +/** + * Create a static [DataTree] + */ +@UnsafeKType +public fun <T> DataTree( + dataType: KType, + generator: DataSink<T>.() -> Unit, +): DataTree<T> = DataTreeBuilder<T>(dataType).apply(generator).build() + +/** + * Create and a data tree. + */ +@OptIn(UnsafeKType::class) +public inline fun <reified T> DataTree( + noinline generator: DataSink<T>.() -> Unit, +): DataTree<T> = DataTree(typeOf<T>(), generator) + + +/** + * Represent this flat data map as a [DataTree] without copying it + */ +@UnsafeKType +public fun <T> Map<Name, Data<T>>.asTree(type: KType): DataTree<T> = + DataTreeBuilder(type, this).build() + +/** + * Represent this flat data map as a [DataTree] without copying it + */ +@OptIn(UnsafeKType::class) +public inline fun <reified T> Map<Name, Data<T>>.asTree(): DataTree<T> = asTree(typeOf<T>()) + + +@UnsafeKType +public fun <T> Sequence<NamedData<T>>.toTree(type: KType): DataTree<T> = + DataTreeBuilder(type, associate { it.name to it.data }).build() + + +/** + * Collect a sequence of [NamedData] to a [DataTree] + */ +@OptIn(UnsafeKType::class) +public inline fun <reified T> Sequence<NamedData<T>>.toTree(): DataTree<T> = toTree(typeOf<T>()) diff --git a/dataforge-data/src/commonTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt b/dataforge-data/src/commonTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt new file mode 100644 index 00000000..760aeec2 --- /dev/null +++ b/dataforge-data/src/commonTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt @@ -0,0 +1,73 @@ +package space.kscience.dataforge.data + +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.test.runTest +import space.kscience.dataforge.names.asName +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.milliseconds + + +internal class DataTreeBuilderTest { + @Test + fun testTreeBuild() = runTest(timeout = 500.milliseconds) { + val node = DataTree<Any> { + putAll("primary") { + putValue("a", "a") + putValue("b", "b") + } + putValue("c.d", "c.d") + putValue("c.f", "c.f") + } + assertEquals("a", node["primary.a"]?.await()) + assertEquals("b", node["primary.b"]?.await()) + assertEquals("c.d", node["c.d"]?.await()) + assertEquals("c.f", node["c.f"]?.await()) + + } + + @Test + fun testDataUpdate() = runTest(timeout = 500.milliseconds) { + val updateData = DataTree<Any> { + putAll("update") { + put("a", Data.wrapValue("a")) + put("b", Data.wrapValue("b")) + } + } + + val node = DataTree<Any> { + putAll("primary") { + putValue("a", "a") + putValue("b", "b") + } + putValue("root", "root") + putAll(updateData) + } + + assertEquals("a", node["update.a"]?.await()) + assertEquals("a", node["primary.a"]?.await()) + } + + @Test + fun testDynamicUpdates() = runTest(timeout = 500.milliseconds) { + var job: Job? = null + + val subNode = MutableDataTree<Int>() + + val rootNode = MutableDataTree<Int>() { + job = putAllAndWatch(this@runTest, "sub".asName(), subNode) + } + + repeat(10) { + subNode.updateValue("value[$it]", it) + } + + rootNode.updates.take(10).collect() + assertEquals(9, rootNode["sub.value[9]"]?.await()) + assertEquals(8, rootNode["sub.value[8]"]?.await()) + + job?.cancel() + } +} \ No newline at end of file diff --git a/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataFilterJvm.kt b/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataFilterJvm.kt index 48155595..0cc81f7a 100644 --- a/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataFilterJvm.kt +++ b/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataFilterJvm.kt @@ -1,6 +1,5 @@ package space.kscience.dataforge.data -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.filter import space.kscience.dataforge.misc.DFInternal @@ -25,32 +24,40 @@ private fun <R> Data<*>.castOrNull(type: KType): Data<R>? = @Suppress("UNCHECKED_CAST") @DFInternal -public fun <R> Sequence<NamedData<*>>.filterByDataType(type: KType): Sequence<NamedData<R>> = +public fun <R> Sequence<DataUpdate<*>>.filterByDataType(type: KType): Sequence<NamedData<R>> = filter { it.type.isSubtypeOf(type) } as Sequence<NamedData<R>> @Suppress("UNCHECKED_CAST") @DFInternal -public fun <R> Flow<NamedData<*>>.filterByDataType(type: KType): Flow<NamedData<R>> = +public fun <R> Flow<DataUpdate<*>>.filterByDataType(type: KType): Flow<NamedData<R>> = filter { it.type.isSubtypeOf(type) } as Flow<NamedData<R>> /** * Select all data matching given type and filters. Does not modify paths * - * @param predicate additional filtering condition based on item name and meta. By default, accepts all + * @param filter additional filtering condition based on item name and meta. By default, accepts all */ +@Suppress("UNCHECKED_CAST") @DFInternal public fun <R> DataTree<*>.filterByType( type: KType, - predicate: DataFilter = DataFilter.EMPTY, -): DataTree<R> = asSequence().filterByDataType<R>(type).filterData(predicate).toTree(type) + branch: Name = Name.EMPTY, + filter: DataFilter = DataFilter.EMPTY, +): DataTree<R> { + val filterWithType = DataFilter { name, meta, dataType -> + filter.accepts(name, meta, dataType) && dataType.isSubtypeOf(type) + } + return FilteredDataTree(this, filterWithType, branch, type) as DataTree<R> +} /** * Select a single datum of the appropriate type */ @OptIn(DFInternal::class) public inline fun <reified R : Any> DataTree<*>.filterByType( - predicate: DataFilter = DataFilter.EMPTY, -): DataTree<R> = filterByType(typeOf<R>(), predicate) + branch: Name = Name.EMPTY, + filter: DataFilter = DataFilter.EMPTY, +): DataTree<R> = filterByType(typeOf<R>(), branch, filter = filter) /** * Select a single datum if it is present and of given [type] @@ -63,25 +70,3 @@ public inline fun <reified R : Any> DataTree<*>.getByType(name: Name): NamedData public inline fun <reified R : Any> DataTree<*>.getByType(name: String): NamedData<R>? = this@getByType.getByType(typeOf<R>(), Name.parse(name)) - -/** - * Select all data matching given type and filters. Does not modify paths - * - * @param predicate additional filtering condition based on item name and meta. By default, accepts all - */ -@DFInternal -public fun <R> ObservableDataTree<*>.filterByType( - type: KType, - scope: CoroutineScope, - predicate: DataFilter = DataFilter.EMPTY, -): ObservableDataTree<R> = asSequence() - .filterByDataType<R>(type) - .filterData(predicate) - .toObservableTree(type, scope, updates().filterByDataType<R>(type).filterData(predicate)) - - -@OptIn(DFInternal::class) -public inline fun <reified R> ObservableDataTree<*>.filterByType( - scope: CoroutineScope, - predicate: DataFilter = DataFilter.EMPTY, -): ObservableDataTree<R> = filterByType(typeOf<R>(),scope,predicate) \ No newline at end of file diff --git a/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataSetBuilderInContext.kt b/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataSetBuilderInContext.kt index cfccb02b..8ce50a22 100644 --- a/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataSetBuilderInContext.kt +++ b/dataforge-data/src/jvmMain/kotlin/space/kscience/dataforge/data/dataSetBuilderInContext.kt @@ -14,14 +14,14 @@ public infix fun <T : Any> String.put(data: Data<T>): Unit = * Append node */ context(DataSink<T>) -public infix fun <T : Any> String.put(dataSet: DataTree<T>): Unit = - branch(this, dataSet) +public infix fun <T : Any> String.putAll(dataSet: DataTree<T>): Unit = + putAll(this, dataSet) /** * Build and append node */ context(DataSink<T>) -public infix fun <T : Any> String.put( +public infix fun <T : Any> String.putAll( block: DataSink<T>.() -> Unit, -): Unit = branch(Name.parse(this), block) +): Unit = putAll(Name.parse(this), block) diff --git a/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/ActionsTest.kt b/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/ActionsTest.kt index 4aa6e6d4..13660eee 100644 --- a/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/ActionsTest.kt +++ b/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/ActionsTest.kt @@ -1,22 +1,24 @@ package space.kscience.dataforge.data -import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.take import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Test import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.invoke import space.kscience.dataforge.actions.mapping import space.kscience.dataforge.misc.DFExperimental +import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.milliseconds @OptIn(DFExperimental::class) internal class ActionsTest { @Test - fun testStaticMapAction() = runTest { + fun testStaticMapAction() = runTest(timeout = 500.milliseconds) { val data: DataTree<Int> = DataTree { repeat(10) { - wrap(it.toString(), it) + putValue(it.toString(), it) } } @@ -28,7 +30,7 @@ internal class ActionsTest { } @Test - fun testDynamicMapAction() = runBlocking { + fun testDynamicMapAction() = runTest(timeout = 500.milliseconds) { val source: MutableDataTree<Int> = MutableDataTree() val plusOne = Action.mapping<Int, Int> { @@ -39,13 +41,10 @@ internal class ActionsTest { repeat(10) { - source.wrap(it.toString(), it) + source.updateValue(it.toString(), it) } - delay(10) - - source.close() - result.awaitClose() + result.updates.take(10).onEach { println(it.name) }.collect() assertEquals(2, result["1"]?.await()) } diff --git a/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt b/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt deleted file mode 100644 index 95b7a7bd..00000000 --- a/dataforge-data/src/jvmTest/kotlin/space/kscience/dataforge/data/DataTreeBuilderTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package space.kscience.dataforge.data - -import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.test.runTest -import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.names.asName -import kotlin.test.Test -import kotlin.test.assertEquals - - -internal class DataTreeBuilderTest { - @Test - fun testTreeBuild() = runTest { - val node = DataTree<Any> { - "primary" put { - wrap("a", "a") - wrap("b", "b") - } - wrap("c.d", "c.d") - wrap("c.f", "c.f") - } - assertEquals("a", node["primary.a"]?.await()) - assertEquals("b", node["primary.b"]?.await()) - assertEquals("c.d", node["c.d"]?.await()) - assertEquals("c.f", node["c.f"]?.await()) - - } - - @OptIn(DFExperimental::class) - @Test - fun testDataUpdate() = runTest { - val updateData = DataTree<Any> { - "update" put { - "a" put Data.static("a") - "b" put Data.static("b") - } - } - - val node = DataTree<Any> { - "primary" put { - wrap("a", "a") - wrap("b", "b") - } - wrap("root", "root") - putAll(updateData) - } - - assertEquals("a", node["update.a"]?.await()) - assertEquals("a", node["primary.a"]?.await()) - } - - @Test - fun testDynamicUpdates() = runBlocking { - val subNode = MutableDataTree<Int>() - - val rootNode = MutableDataTree<Int> { - watchBranch("sub".asName(), subNode) - } - - repeat(10) { - subNode.wrap("value[$it]", it) - } - - delay(20) - assertEquals(9, rootNode["sub.value[9]"]?.await()) - } -} \ No newline at end of file diff --git a/dataforge-io/README.md b/dataforge-io/README.md index 85e49e5a..5a9979a9 100644 --- a/dataforge-io/README.md +++ b/dataforge-io/README.md @@ -6,7 +6,7 @@ IO module ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-io:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-io:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-io:0.8.0") + implementation("space.kscience:dataforge-io:0.9.0-dev-1") } ``` diff --git a/dataforge-io/dataforge-io-yaml/README.md b/dataforge-io/dataforge-io-yaml/README.md index 20f5b4f6..f70a1490 100644 --- a/dataforge-io/dataforge-io-yaml/README.md +++ b/dataforge-io/dataforge-io-yaml/README.md @@ -6,7 +6,7 @@ YAML meta IO ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-io-yaml:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-io-yaml:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-io-yaml:0.8.0") + implementation("space.kscience:dataforge-io-yaml:0.9.0-dev-1") } ``` diff --git a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/EnvelopeParts.kt b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/EnvelopeParts.kt index 183e7b03..88231899 100644 --- a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/EnvelopeParts.kt +++ b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/EnvelopeParts.kt @@ -11,6 +11,7 @@ import space.kscience.dataforge.io.PartDescriptor.Companion.PARTS_KEY import space.kscience.dataforge.io.PartDescriptor.Companion.SEPARATOR_KEY import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.asName +import space.kscience.dataforge.names.getIndexedList import space.kscience.dataforge.names.plus private class PartDescriptor : Scheme() { @@ -84,7 +85,7 @@ public fun EnvelopeBuilder.envelopes( public fun Envelope.parts(): EnvelopeParts { if (data == null) return emptyList() //TODO add zip folder reader - val parts = meta.getIndexed(PARTS_KEY).values.map { + val parts = meta.getIndexedList(PARTS_KEY).map { PartDescriptor.read(it) } return if (parts.isEmpty()) { diff --git a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/IOPlugin.kt b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/IOPlugin.kt index 0d79da4d..f431a731 100644 --- a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/IOPlugin.kt +++ b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/IOPlugin.kt @@ -6,7 +6,7 @@ import space.kscience.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE import space.kscience.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.string -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import kotlin.reflect.KType import kotlin.reflect.typeOf @@ -19,11 +19,11 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) { } @Suppress("UNCHECKED_CAST") - @DFInternal + @UnsafeKType public fun <T> resolveIOFormat(type: KType, meta: Meta): IOFormat<T>? = ioFormatFactories.singleOrNull { it.type == type }?.build(context, meta) as? IOFormat<T> - @OptIn(DFInternal::class) + @OptIn(UnsafeKType::class) public inline fun <reified T> resolveIOFormat(meta: Meta = Meta.EMPTY): IOFormat<T>? = resolveIOFormat(typeOf<T>(), meta) diff --git a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt index 93fd210a..b5e56dfe 100644 --- a/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt +++ b/dataforge-io/src/commonMain/kotlin/space/kscience/dataforge/io/ioMisc.kt @@ -5,7 +5,6 @@ import kotlinx.io.bytestring.ByteString import kotlinx.io.bytestring.decodeToString import kotlinx.io.bytestring.encodeToByteString import space.kscience.dataforge.meta.Meta -import space.kscience.dataforge.misc.DFExperimental import kotlin.math.min /** @@ -52,7 +51,6 @@ public fun IOPlugin.peekBinaryEnvelopeFormat(binary: Binary): EnvelopeFormat? { /** * A zero-copy read from */ -@DFExperimental public fun IOPlugin.readEnvelope( binary: Binary, readNonEnvelopes: Boolean = false, @@ -62,7 +60,6 @@ public fun IOPlugin.readEnvelope( Envelope(Meta.EMPTY, binary) } else error("Can't infer format for $binary") -@DFExperimental public fun IOPlugin.readEnvelope( string: String, readNonEnvelopes: Boolean = false, diff --git a/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt index c15280f3..7df23eb5 100644 --- a/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt +++ b/dataforge-io/src/jvmMain/kotlin/space/kscience/dataforge/io/fileIO.kt @@ -77,14 +77,12 @@ public fun Path.rewrite(block: Sink.() -> Unit): Unit { stream.asSink().buffered().use(block) } -@DFExperimental public fun EnvelopeFormat.readFile(path: Path): Envelope = readFrom(path.asBinary()) /** * Resolve IOFormat based on type */ @Suppress("UNCHECKED_CAST") -@DFExperimental public inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? = ioFormatFactories.find { it.type.isSupertypeOf(typeOf<T>()) } as IOFormat<T>? @@ -192,7 +190,6 @@ public fun IOPlugin.peekFileEnvelopeFormat(path: Path): EnvelopeFormat? { * * Return null otherwise. */ -@DFExperimental public fun IOPlugin.readEnvelopeFile( path: Path, readNonEnvelopes: Boolean = false, diff --git a/dataforge-meta/README.md b/dataforge-meta/README.md index bd11ebf1..e4fcacb1 100644 --- a/dataforge-meta/README.md +++ b/dataforge-meta/README.md @@ -6,7 +6,7 @@ Meta definition and basic operations on meta ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-meta:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-meta:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-meta:0.8.0") + implementation("space.kscience:dataforge-meta:0.9.0-dev-1") } ``` diff --git a/dataforge-meta/api/dataforge-meta.api b/dataforge-meta/api/dataforge-meta.api index 49f28259..0bb4a908 100644 --- a/dataforge-meta/api/dataforge-meta.api +++ b/dataforge-meta/api/dataforge-meta.api @@ -1,3 +1,15 @@ +public final class space/kscience/dataforge/meta/ByteArrayValue : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker, space/kscience/dataforge/meta/Value { + public fun <init> ([B)V + public fun equals (Ljava/lang/Object;)Z + public fun getList ()Ljava/util/List; + public fun getType ()Lspace/kscience/dataforge/meta/ValueType; + public synthetic fun getValue ()Ljava/lang/Object; + public fun getValue ()[B + public fun hashCode ()I + public fun iterator ()Ljava/util/Iterator; + public fun toString ()Ljava/lang/String; +} + public abstract interface class space/kscience/dataforge/meta/Configurable { public abstract fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta; } @@ -30,7 +42,20 @@ public final class space/kscience/dataforge/meta/EnumValue : space/kscience/data } public final class space/kscience/dataforge/meta/ExoticValuesKt { + public static final fun asValue ([B)Lspace/kscience/dataforge/meta/Value; public static final fun asValue ([D)Lspace/kscience/dataforge/meta/Value; + public static final fun byteArray (Lspace/kscience/dataforge/meta/MetaProvider;[BLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; + public static final fun byteArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[BLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; + public static synthetic fun byteArray$default (Lspace/kscience/dataforge/meta/MetaProvider;[BLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun byteArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[BLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; + public static final fun doubleArray (Lspace/kscience/dataforge/meta/MetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; + public static final fun doubleArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; + public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; + public static final fun getByteArray (Lspace/kscience/dataforge/meta/Meta;)[B + public static final fun getByteArray (Lspace/kscience/dataforge/meta/Value;)[B + public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Meta;)[D + public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Value;)[D public static final fun lazyParseValue (Ljava/lang/String;)Lspace/kscience/dataforge/meta/LazyParsedValue; } @@ -78,6 +103,8 @@ public final class space/kscience/dataforge/meta/Laminate : space/kscience/dataf public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMeta; public fun getItems ()Ljava/util/Map; public final fun getLayers ()Ljava/util/List; + public fun getSelf ()Lspace/kscience/dataforge/meta/Laminate; + public synthetic fun getSelf ()Lspace/kscience/dataforge/meta/TypedMeta; public fun getValue ()Lspace/kscience/dataforge/meta/Value; public fun hashCode ()I public final fun merge ()Lspace/kscience/dataforge/meta/SealedMeta; @@ -173,7 +200,7 @@ public final class space/kscience/dataforge/meta/MetaBuilder : space/kscience/da public abstract interface annotation class space/kscience/dataforge/meta/MetaBuilderMarker : java/lang/annotation/Annotation { } -public abstract interface class space/kscience/dataforge/meta/MetaConverter : space/kscience/dataforge/meta/MetaSpec { +public abstract interface class space/kscience/dataforge/meta/MetaConverter : space/kscience/dataforge/meta/MetaReader { public static final field Companion Lspace/kscience/dataforge/meta/MetaConverter$Companion; public abstract fun convert (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta; public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; @@ -199,53 +226,56 @@ public final class space/kscience/dataforge/meta/MetaConverterKt { public static final fun convertNullable (Lspace/kscience/dataforge/meta/MetaConverter;Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta; } +public abstract interface class space/kscience/dataforge/meta/MetaDelegate : kotlin/properties/ReadOnlyProperty, space/kscience/dataforge/meta/descriptors/Described { +} + public final class space/kscience/dataforge/meta/MetaDelegateKt { - public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty; - public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun listOfSpec (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun listOfSpec$default (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaSpec;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaSpec;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun spec (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun spec$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; - public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; - public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun listOfSpec (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun listOfSpec$default (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaReader;)Lkotlin/properties/ReadOnlyProperty; + public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaReader;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun spec (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun spec$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; + public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate; } public final class space/kscience/dataforge/meta/MetaKt { @@ -266,7 +296,6 @@ public final class space/kscience/dataforge/meta/MetaKt { public static final fun getLong (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Long; public static final synthetic fun getNonNullable (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/NameToken;)Lspace/kscience/dataforge/meta/Meta; public static final fun getNumber (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Number; - public static final fun getSelf (Lspace/kscience/dataforge/meta/TypedMeta;)Lspace/kscience/dataforge/meta/TypedMeta; public static final fun getShort (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Short; public static final fun getString (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/String; public static final fun getStringList (Lspace/kscience/dataforge/meta/Meta;)Ljava/util/List; @@ -283,6 +312,16 @@ public abstract interface class space/kscience/dataforge/meta/MetaProvider : spa public fun getValue (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Value; } +public abstract interface class space/kscience/dataforge/meta/MetaReader : space/kscience/dataforge/meta/descriptors/Described { + public fun read (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; + public abstract fun readOrNull (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; +} + +public final class space/kscience/dataforge/meta/MetaReaderKt { + public static final fun readNullable (Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; + public static final fun readValue (Lspace/kscience/dataforge/meta/MetaReader;Lspace/kscience/dataforge/meta/Value;)Ljava/lang/Object; +} + public abstract interface class space/kscience/dataforge/meta/MetaRepr { public abstract fun toMeta ()Lspace/kscience/dataforge/meta/Meta; } @@ -296,16 +335,6 @@ public final class space/kscience/dataforge/meta/MetaSerializer : kotlinx/serial public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/Meta;)V } -public abstract interface class space/kscience/dataforge/meta/MetaSpec : space/kscience/dataforge/meta/descriptors/Described { - public fun read (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; - public abstract fun readOrNull (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; -} - -public final class space/kscience/dataforge/meta/MetaSpecKt { - public static final fun readNullable (Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object; - public static final fun readValue (Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/meta/Value;)Ljava/lang/Object; -} - public final class space/kscience/dataforge/meta/MetaTransformation { public static final field Companion Lspace/kscience/dataforge/meta/MetaTransformation$Companion; public static final fun apply-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Meta; @@ -352,6 +381,7 @@ public abstract interface class space/kscience/dataforge/meta/MutableMeta : spac public fun put (Ljava/lang/String;Lspace/kscience/dataforge/meta/MetaRepr;)V public fun put (Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)V public fun put (Ljava/lang/String;Z)V + public fun put (Ljava/lang/String;[B)V public fun put (Ljava/lang/String;[D)V public fun put (Lspace/kscience/dataforge/names/Name;Ljava/lang/Enum;)V public fun put (Lspace/kscience/dataforge/names/Name;Ljava/lang/Number;)V @@ -371,68 +401,70 @@ public final class space/kscience/dataforge/meta/MutableMeta$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public abstract interface class space/kscience/dataforge/meta/MutableMetaDelegate : kotlin/properties/ReadWriteProperty, space/kscience/dataforge/meta/descriptors/Described { +} + public final class space/kscience/dataforge/meta/MutableMetaDelegateKt { - public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; - public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun convertable (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun convertable$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun doubleArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun listOfConvertable (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun listOfConvertable$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun listValue (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun listValue$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun numberList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun numberList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; - public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; - public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; + public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun convertable (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun convertable$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun listOfConvertable (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun listOfConvertable$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun listValue (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun listValue$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun numberList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun numberList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; + public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate; } public final class space/kscience/dataforge/meta/MutableMetaKt { public static final fun ObservableMutableMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta; public static final fun ObservableMutableMeta (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/ObservableMutableMeta; + public static final fun ObservableMutableMeta (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/ObservableMutableMeta; public static synthetic fun ObservableMutableMeta$default (Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/ObservableMutableMeta; public static final fun append (Lspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lspace/kscience/dataforge/meta/Meta;)V public static final fun append (Lspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)V @@ -446,6 +478,7 @@ public final class space/kscience/dataforge/meta/MutableMetaKt { public static final fun getOrCreate (Lspace/kscience/dataforge/meta/MutableTypedMeta;Ljava/lang/String;)Lspace/kscience/dataforge/meta/MutableTypedMeta; public static final fun remove (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;)V public static final fun remove (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)V + public static final fun reset (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Meta;)V public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Ljava/lang/Iterable;)V public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/meta/Meta;)V public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Ljava/lang/Iterable;)V @@ -519,6 +552,8 @@ public abstract interface class space/kscience/dataforge/meta/ObservableMutableM public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/ObservableMutableMeta; public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMeta; public abstract fun getOrCreate (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/ObservableMutableMeta; + public fun getSelf ()Lspace/kscience/dataforge/meta/ObservableMutableMeta; + public synthetic fun getSelf ()Lspace/kscience/dataforge/meta/TypedMeta; } public final class space/kscience/dataforge/meta/RegexItemTransformationRule : space/kscience/dataforge/meta/TransformationRule { @@ -538,6 +573,8 @@ public final class space/kscience/dataforge/meta/RegexItemTransformationRule : s public class space/kscience/dataforge/meta/Scheme : space/kscience/dataforge/meta/Configurable, space/kscience/dataforge/meta/MetaRepr, space/kscience/dataforge/meta/MutableMetaProvider, space/kscience/dataforge/meta/descriptors/Described { public fun <init> ()V + public fun <init> (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V + public synthetic fun <init> (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta; public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMeta; public final fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; @@ -555,6 +592,10 @@ public final class space/kscience/dataforge/meta/SchemeKt { public static final fun copy (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme; public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Scheme; public static final fun invoke (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme; + public static final fun listOfScheme (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; + public static final fun listOfScheme (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; + public static synthetic fun listOfScheme$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; + public static synthetic fun listOfScheme$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; public static final fun scheme (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; public static final fun scheme (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; public static synthetic fun scheme$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; @@ -586,19 +627,21 @@ public final class space/kscience/dataforge/meta/SealedMeta : space/kscience/dat public fun <init> (Lspace/kscience/dataforge/meta/Value;Ljava/util/Map;)V public fun equals (Ljava/lang/Object;)Z public fun getItems ()Ljava/util/Map; + public fun getSelf ()Lspace/kscience/dataforge/meta/SealedMeta; + public synthetic fun getSelf ()Lspace/kscience/dataforge/meta/TypedMeta; public fun getValue ()Lspace/kscience/dataforge/meta/Value; public fun hashCode ()I public fun toString ()Ljava/lang/String; } -public final class space/kscience/dataforge/meta/SealedMeta$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +public synthetic class space/kscience/dataforge/meta/SealedMeta$$serializer : kotlinx/serialization/internal/GeneratedSerializer { public static final field INSTANCE Lspace/kscience/dataforge/meta/SealedMeta$$serializer; - public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/SealedMeta; - public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/SealedMeta; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/SealedMeta;)V + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/SealedMeta;)V public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; } @@ -672,6 +715,7 @@ public abstract interface class space/kscience/dataforge/meta/TypedMeta : space/ public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta; public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMeta; public abstract fun getItems ()Ljava/util/Map; + public abstract fun getSelf ()Lspace/kscience/dataforge/meta/TypedMeta; public fun toMeta ()Lspace/kscience/dataforge/meta/Meta; } @@ -696,7 +740,6 @@ public final class space/kscience/dataforge/meta/Value$Companion { public final class space/kscience/dataforge/meta/ValueExtensionsKt { public static final fun getBoolean (Lspace/kscience/dataforge/meta/Value;)Z public static final fun getDouble (Lspace/kscience/dataforge/meta/Value;)D - public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Value;)[D public static final fun getFloat (Lspace/kscience/dataforge/meta/Value;)F public static final fun getInt (Lspace/kscience/dataforge/meta/Value;)I public static final fun getLong (Lspace/kscience/dataforge/meta/Value;)J @@ -715,7 +758,6 @@ public final class space/kscience/dataforge/meta/ValueKt { public static final fun asValue (Ljava/lang/Number;)Lspace/kscience/dataforge/meta/Value; public static final fun asValue (Ljava/lang/String;)Lspace/kscience/dataforge/meta/Value; public static final fun asValue (Z)Lspace/kscience/dataforge/meta/Value; - public static final fun asValue ([B)Lspace/kscience/dataforge/meta/Value; public static final fun asValue ([F)Lspace/kscience/dataforge/meta/Value; public static final fun asValue ([I)Lspace/kscience/dataforge/meta/Value; public static final fun asValue ([J)Lspace/kscience/dataforge/meta/Value; @@ -808,14 +850,14 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptor { public fun toString ()Ljava/lang/String; } -public final class space/kscience/dataforge/meta/descriptors/MetaDescriptor$$serializer : kotlinx/serialization/internal/GeneratedSerializer { +public synthetic class space/kscience/dataforge/meta/descriptors/MetaDescriptor$$serializer : kotlinx/serialization/internal/GeneratedSerializer { public static final field INSTANCE Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor$$serializer; - public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; - public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; } @@ -837,17 +879,16 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorBuild 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 getInfo ()Ljava/lang/String; public final fun getMultiple ()Z public final fun getValueRestriction ()Lspace/kscience/dataforge/meta/descriptors/ValueRestriction; public final fun getValueTypes ()Ljava/util/List; + public final fun node (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V public final fun setAllowedValues (Ljava/util/List;)V public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V public final fun setChildren (Ljava/util/Map;)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 setInfo (Ljava/lang/String;)V public final fun setMultiple (Z)V public final fun setValueRestriction (Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;)V public final fun setValueTypes (Ljava/util/List;)V @@ -893,10 +934,6 @@ public final class space/kscience/dataforge/meta/descriptors/ValueRestriction$Co public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class space/kscience/dataforge/misc/CastJvmKt { - public static final fun unsafeCast (Ljava/lang/Object;)Ljava/lang/Object; -} - public abstract interface annotation class space/kscience/dataforge/misc/DFBuilder : java/lang/annotation/Annotation { } @@ -923,6 +960,9 @@ public final class space/kscience/dataforge/misc/NamedKt { public static final fun isAnonymous (Lspace/kscience/dataforge/misc/Named;)Z } +public abstract interface annotation class space/kscience/dataforge/misc/UnsafeKType : java/lang/annotation/Annotation { +} + public final class space/kscience/dataforge/names/Name { public static final field Companion Lspace/kscience/dataforge/names/Name$Companion; public static final field NAME_SEPARATOR Ljava/lang/String; @@ -940,6 +980,16 @@ public final class space/kscience/dataforge/names/Name$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } +public final class space/kscience/dataforge/names/NameIndexComparator : java/util/Comparator { + public static final field INSTANCE Lspace/kscience/dataforge/names/NameIndexComparator; + public synthetic fun compare (Ljava/lang/Object;Ljava/lang/Object;)I + public fun compare (Ljava/lang/String;Ljava/lang/String;)I +} + +public final class space/kscience/dataforge/names/NameIndexComparatorKt { + public static final fun getIndexedList (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;)Ljava/util/List; +} + public final class space/kscience/dataforge/names/NameKt { public static final fun appendFirst (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name; public static final fun appendLeft (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name; diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Laminate.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Laminate.kt index 87284107..0ae84bb6 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Laminate.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Laminate.kt @@ -9,6 +9,8 @@ import space.kscience.dataforge.names.NameToken */ public class Laminate internal constructor(public val layers: List<Meta>) : TypedMeta<Laminate> { + override val self: Laminate get() = this + override val value: Value? = layers.firstNotNullOfOrNull { it.value } override val items: Map<NameToken, Laminate> by lazy { diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt index 5cf53c75..fd953085 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Meta.kt @@ -3,7 +3,6 @@ package space.kscience.dataforge.meta import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import space.kscience.dataforge.misc.DfType -import space.kscience.dataforge.misc.unsafeCast import space.kscience.dataforge.names.* import kotlin.jvm.JvmName @@ -151,6 +150,8 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta { override val items: Map<NameToken, M> + public val self: M + override fun get(name: Name): M? { tailrec fun M.find(name: Name): M? = if (name.isEmpty()) { this @@ -164,11 +165,6 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta { override fun toMeta(): Meta = this } -/** - * Access self as a recursive type instance - */ -public inline val <M : TypedMeta<M>> TypedMeta<M>.self: M get() = unsafeCast() - //public typealias Meta = TypedMeta<*> public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt index 8959ae4a..9baf0087 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaConverter.kt @@ -11,7 +11,7 @@ import space.kscience.dataforge.misc.DFExperimental /** * A converter of generic object to and from [Meta] */ -public interface MetaConverter<T>: MetaSpec<T> { +public interface MetaConverter<T>: MetaReader<T> { /** * A descriptor for resulting meta @@ -135,16 +135,17 @@ public interface MetaConverter<T>: MetaSpec<T> { @DFExperimental public inline fun <reified T> serializable( descriptor: MetaDescriptor? = null, + jsonEncoder: Json = Json, ): MetaConverter<T> = object : MetaConverter<T> { private val serializer: KSerializer<T> = serializer() override fun readOrNull(source: Meta): T? { val json = source.toJson(descriptor) - return Json.decodeFromJsonElement(serializer, json) + return jsonEncoder.decodeFromJsonElement(serializer, json) } override fun convert(obj: T): Meta { - val json = Json.encodeToJsonElement(obj) + val json = jsonEncoder.encodeToJsonElement(obj) return json.toMeta(descriptor) } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt index a24f7371..1b506b44 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaDelegate.kt @@ -1,25 +1,41 @@ package space.kscience.dataforge.meta +import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty /* Meta delegates */ -public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = ReadOnlyProperty { _, property -> - get(key ?: property.name.asName()) +public interface MetaDelegate<T> : ReadOnlyProperty<Any?, T>, Described + + +public fun MetaProvider.node( + key: Name? = null, + descriptor: MetaDescriptor? = null, +): MetaDelegate<Meta?> = object : MetaDelegate<Meta?> { + override val descriptor: MetaDescriptor? = descriptor + + override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { + return get(key ?: property.name.asName()) + } } /** - * Use [metaSpec] to read the Meta node + * Use [metaReader] to read the Meta node */ public fun <T> MetaProvider.spec( - metaSpec: MetaSpec<T>, + metaReader: MetaReader<T>, key: Name? = null, -): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property -> - get(key ?: property.name.asName())?.let { metaSpec.read(it) } +): MetaDelegate<T?> = object : MetaDelegate<T?> { + override val descriptor: MetaDescriptor? get() = metaReader.descriptor + + override fun getValue(thisRef: Any?, property: KProperty<*>): T? { + return get(key ?: property.name.asName())?.let { metaReader.read(it) } + } } /** @@ -27,94 +43,106 @@ public fun <T> MetaProvider.spec( */ @DFExperimental public inline fun <reified T> MetaProvider.serializable( - descriptor: MetaDescriptor? = null, key: Name? = null, -): ReadOnlyProperty<Any?, T?> = spec(MetaConverter.serializable(descriptor), key) + descriptor: MetaDescriptor? = null, +): MetaDelegate<T?> = spec(MetaConverter.serializable(descriptor), key) @Deprecated("Use convertable", ReplaceWith("convertable(converter, key)")) public fun <T> MetaProvider.node( key: Name? = null, - converter: MetaSpec<T>, + converter: MetaReader<T>, ): ReadOnlyProperty<Any?, T?> = spec(converter, key) /** * Use [converter] to convert a list of same name siblings meta to object */ public fun <T> Meta.listOfSpec( - converter: MetaSpec<T>, + converter: MetaReader<T>, key: Name? = null, -): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty{_, property -> - val name = key ?: property.name.asName() - getIndexed(name).values.map { converter.read(it) } +): MetaDelegate<List<T>> = object : MetaDelegate<List<T>> { + override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> { + val name = key ?: property.name.asName() + return getIndexed(name).values.map { converter.read(it) } + } + + override val descriptor: MetaDescriptor? = converter.descriptor?.copy(multiple = true) } @DFExperimental public inline fun <reified T> Meta.listOfSerializable( - descriptor: MetaDescriptor? = null, key: Name? = null, -): ReadOnlyProperty<Any?, List<T>> = listOfSpec(MetaConverter.serializable(descriptor), key) + descriptor: MetaDescriptor? = null, +): MetaDelegate<List<T>> = listOfSpec(MetaConverter.serializable(descriptor), key) /** * A property delegate that uses custom key */ -public fun MetaProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = ReadOnlyProperty { _, property -> - get(key ?: property.name.asName())?.value +public fun MetaProvider.value( + key: Name? = null, + descriptor: MetaDescriptor? = null, +): MetaDelegate<Value?> = object : MetaDelegate<Value?> { + override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = get(key ?: property.name.asName())?.value + + override val descriptor: MetaDescriptor? = descriptor } public fun <R> MetaProvider.value( key: Name? = null, + descriptor: MetaDescriptor? = null, reader: (Value?) -> R, -): ReadOnlyProperty<Any?, R> = ReadOnlyProperty { _, property -> - reader(get(key ?: property.name.asName())?.value) +): MetaDelegate<R> = object : MetaDelegate<R> { + override fun getValue(thisRef: Any?, property: KProperty<*>): R = reader(get(key ?: property.name.asName())?.value) + + override val descriptor: MetaDescriptor? = descriptor } //TODO add caching for sealed nodes /* Read-only delegates for [Meta] */ -public fun MetaProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> = value(key) { it?.string } +public fun MetaProvider.string(key: Name? = null): MetaDelegate<String?> = value(key = key) { it?.string } -public fun MetaProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> = value(key) { it?.boolean } +public fun MetaProvider.boolean(key: Name? = null): MetaDelegate<Boolean?> = value(key = key) { it?.boolean } -public fun MetaProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> = value(key) { it?.numberOrNull } +public fun MetaProvider.number(key: Name? = null): MetaDelegate<Number?> = value(key = key) { it?.numberOrNull } -public fun MetaProvider.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> = value(key) { it?.double } +public fun MetaProvider.double(key: Name? = null): MetaDelegate<Double?> = value(key = key) { it?.double } -public fun MetaProvider.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> = value(key) { it?.float } +public fun MetaProvider.float(key: Name? = null): MetaDelegate<Float?> = value(key = key) { it?.float } -public fun MetaProvider.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> = value(key) { it?.int } +public fun MetaProvider.int(key: Name? = null): MetaDelegate<Int?> = value(key = key) { it?.int } -public fun MetaProvider.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> = value(key) { it?.long } +public fun MetaProvider.long(key: Name? = null): MetaDelegate<Long?> = value(key = key) { it?.long } -public fun MetaProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> = - value(key) { it?.string ?: default } +public fun MetaProvider.string(default: String, key: Name? = null): MetaDelegate<String> = + value(key = key) { it?.string ?: default } -public fun MetaProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> = - value(key) { it?.boolean ?: default } +public fun MetaProvider.boolean(default: Boolean, key: Name? = null): MetaDelegate<Boolean> = + value(key = key) { it?.boolean ?: default } -public fun MetaProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> = - value(key) { it?.numberOrNull ?: default } +public fun MetaProvider.number(default: Number, key: Name? = null): MetaDelegate<Number> = + value(key = key) { it?.numberOrNull ?: default } -public fun MetaProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> = - value(key) { it?.double ?: default } +public fun MetaProvider.double(default: Double, key: Name? = null): MetaDelegate<Double> = + value(key = key) { it?.double ?: default } -public fun MetaProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> = - value(key) { it?.float ?: default } +public fun MetaProvider.float(default: Float, key: Name? = null): MetaDelegate<Float> = + value(key = key) { it?.float ?: default } -public fun MetaProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> = - value(key) { it?.int ?: default } +public fun MetaProvider.int(default: Int, key: Name? = null): MetaDelegate<Int> = + value(key = key) { it?.int ?: default } -public fun MetaProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> = - value(key) { it?.long ?: default } +public fun MetaProvider.long(default: Long, key: Name? = null): MetaDelegate<Long> = + value(key = key) { it?.long ?: default } -public inline fun <reified E : Enum<E>> MetaProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> = - value<E>(key) { it?.enum<E>() ?: default } +public inline fun <reified E : Enum<E>> MetaProvider.enum(default: E, key: Name? = null): MetaDelegate<E> = + value<E>(key = key) { it?.enum<E>() ?: default } -public fun MetaProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> = - value(key) { it?.string ?: default() } +public fun MetaProvider.string(key: Name? = null, default: () -> String): MetaDelegate<String> = + value(key = key) { it?.string ?: default() } -public fun MetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> = - value(key) { it?.boolean ?: default() } +public fun MetaProvider.boolean(key: Name? = null, default: () -> Boolean): MetaDelegate<Boolean> = + value(key = key) { it?.boolean ?: default() } -public fun MetaProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> = - value(key) { it?.numberOrNull ?: default() } +public fun MetaProvider.number(key: Name? = null, default: () -> Number): MetaDelegate<Number> = + value(key = key) { it?.numberOrNull ?: default() } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaReader.kt similarity index 59% rename from dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt rename to dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaReader.kt index 9918d504..a8514d63 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaSpec.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaReader.kt @@ -2,7 +2,7 @@ package space.kscience.dataforge.meta import space.kscience.dataforge.meta.descriptors.Described -public interface MetaSpec<out T> : Described { +public interface MetaReader<out T> : Described { /** * Read the source meta into an object and return null if Meta could not be interpreted as a target type @@ -10,12 +10,12 @@ public interface MetaSpec<out T> : Described { public fun readOrNull(source: Meta): T? /** - * Read generic read-only meta with this [MetaSpec] producing instance of the desired type. + * Read generic read-only meta with this [MetaReader] producing instance of the desired type. * Throws an error if conversion could not be done. */ public fun read(source: Meta): T = readOrNull(source) ?: error("Meta $source could not be interpreted by $this") } -public fun <T : Any> MetaSpec<T>.readNullable(item: Meta?): T? = item?.let { read(it) } -public fun <T> MetaSpec<T>.readValue(value: Value): T? = read(Meta(value)) +public fun <T : Any> MetaReader<T>.readNullable(item: Meta?): T? = item?.let { read(it) } +public fun <T> MetaReader<T>.readValue(value: Value): T? = read(Meta(value)) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaRef.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaRef.kt new file mode 100644 index 00000000..413fe404 --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MetaRef.kt @@ -0,0 +1,64 @@ +package space.kscience.dataforge.meta + +import space.kscience.dataforge.meta.descriptors.Described +import space.kscience.dataforge.meta.descriptors.MetaDescriptor +import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder +import space.kscience.dataforge.misc.DFExperimental +import space.kscience.dataforge.names.Name +import space.kscience.dataforge.names.asName +import kotlin.properties.PropertyDelegateProvider +import kotlin.properties.ReadOnlyProperty + + +/** + * A reference to a read-only value of type [T] inside [MetaProvider] + */ +@DFExperimental +public data class MetaRef<T>( + public val name: Name, + public val converter: MetaConverter<T>, + override val descriptor: MetaDescriptor? = converter.descriptor, +) : Described + +@DFExperimental +public operator fun <T> MetaProvider.get(ref: MetaRef<T>): T? = get(ref.name)?.let { ref.converter.readOrNull(it) } + +@DFExperimental +public operator fun <T> MutableMetaProvider.set(ref: MetaRef<T>, value: T) { + set(ref.name, ref.converter.convert(value)) +} + +@DFExperimental +public class MetaSpec( + private val configuration: MetaDescriptorBuilder.() -> Unit = {}, +) : Described { + private val refs: MutableList<MetaRef<*>> = mutableListOf() + + private fun registerRef(ref: MetaRef<*>) { + refs.add(ref) + } + + public fun <T> item( + converter: MetaConverter<T>, + descriptor: MetaDescriptor? = converter.descriptor, + key: Name? = null, + ): PropertyDelegateProvider<MetaSpec, ReadOnlyProperty<MetaSpec, MetaRef<T>>> = + PropertyDelegateProvider { _, property -> + val ref = MetaRef(key ?: property.name.asName(), converter, descriptor) + registerRef(ref) + ReadOnlyProperty { _, _ -> + ref + } + } + + override val descriptor: MetaDescriptor by lazy { + MetaDescriptor { + refs.forEach { ref -> + ref.descriptor?.let { + node(ref.name, ref.descriptor) + } + } + configuration() + } + } +} \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMeta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMeta.kt index 231f9e54..7be16cc9 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMeta.kt @@ -19,6 +19,10 @@ public annotation class MetaBuilderMarker public interface MutableMetaProvider : MetaProvider, MutableValueProvider { override fun get(name: Name): MutableMeta? public operator fun set(name: Name, node: Meta?) + + /** + * Set value with the given name. Does nothing if value is not changed. + */ override fun setValue(name: Name, value: Value?) } @@ -48,11 +52,13 @@ public interface MutableMeta : Meta, MutableMetaProvider { } override fun setValue(name: Name, value: Value?) { - getOrCreate(name).value = value + if (value != getValue(name)) { + getOrCreate(name).value = value + } } /** - * Get existing node or create a new one + * Get an existing node or create a new one */ public fun getOrCreate(name: Name): MutableMeta @@ -122,6 +128,10 @@ public interface MutableMeta : Meta, MutableMetaProvider { setValue(Name.parse(this), array.asValue()) } + public infix fun String.put(array: ByteArray) { + setValue(Name.parse(this), array.asValue()) + } + public infix fun String.put(repr: MetaRepr) { set(Name.parse(this), repr.toMeta()) } @@ -198,10 +208,8 @@ public operator fun MutableMetaProvider.set(key: String, metas: Iterable<Meta>): /** - * Update existing mutable node with another node. The rules are following: - * * value replaces anything - * * node updates node and replaces anything but node - * * node list updates node list if number of nodes in the list is the same and replaces anything otherwise + * Update the existing mutable node with another node. + * Values that are present in the current provider and are missing in [meta] are kept. */ public fun MutableMetaProvider.update(meta: Meta) { meta.valueSequence().forEach { (name, value) -> @@ -222,7 +230,7 @@ public fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.edit(name: Name, builde getOrCreate(name).apply(builder) /** - * Set a value at a given [name]. If node does not exist, create it. + * Set a value at a given [name]. If a node does not exist, create it. */ public operator fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.set(name: Name, value: Value?) { edit(name) { @@ -245,6 +253,9 @@ private class MutableMetaImpl( value: Value?, children: Map<NameToken, Meta> = emptyMap(), ) : AbstractObservableMeta(), ObservableMutableMeta { + + override val self get() = this + override var value = value @ThreadSafe set(value) { val oldValue = field @@ -367,6 +378,21 @@ public fun MutableMeta.append(name: Name, value: Value): Unit = append(name, Met public fun MutableMeta.append(key: String, value: Value): Unit = append(Name.parse(key), value) +/** + * Update all items that exist in the [newMeta] and remove existing items that are missing in [newMeta]. + * This produces the same result as clearing all items and updating blank meta with a [newMeta], but does not + * produce unnecessary invalidation events (if they are supported). + */ +public fun MutableMeta.reset(newMeta: Meta) { + //remove old items + (items.keys - newMeta.items.keys).forEach { + remove(it.asName()) + } + newMeta.items.forEach { (token, item)-> + set(token, item) + } +} + /** * Create a mutable copy of this meta. The copy is created even if the Meta is already mutable */ @@ -378,6 +404,11 @@ public fun Meta.asMutableMeta(): MutableMeta = (this as? MutableMeta) ?: toMutab @JsName("newObservableMutableMeta") public fun ObservableMutableMeta(): ObservableMutableMeta = MutableMetaImpl(null) +/** + * Create a pre-filled [ObservableMutableMeta] + */ +public fun ObservableMutableMeta(content: Meta): ObservableMutableMeta = ObservableMutableMeta { update(content) } + /** * Build a [MutableMeta] using given transformation */ diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt index f6e96109..37140c6f 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/MutableMetaDelegate.kt @@ -1,26 +1,36 @@ package space.kscience.dataforge.meta +import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName +import space.kscience.dataforge.names.getIndexedList import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty + /* Read-write delegates */ -public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = - object : ReadWriteProperty<Any?, Meta?> { - override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { - return get(key ?: property.name.asName()) - } +public interface MutableMetaDelegate<T> : ReadWriteProperty<Any?, T>, Described - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { - val name = key ?: property.name.asName() - set(name, value) - } +public fun MutableMetaProvider.node( + key: Name? = null, + descriptor: MetaDescriptor? = null, +): MutableMetaDelegate<Meta?> = object : MutableMetaDelegate<Meta?> { + + override val descriptor: MetaDescriptor? = descriptor + + override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? { + return get(key ?: property.name.asName()) } + override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { + val name = key ?: property.name.asName() + set(name, value) + } +} + /** * Use [converter] to transform an object to Meta and back. * Note that mutation of the object does not change Meta. @@ -28,21 +38,24 @@ public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, public fun <T> MutableMetaProvider.convertable( converter: MetaConverter<T>, key: Name? = null, -): ReadWriteProperty<Any?, T?> = - object : ReadWriteProperty<Any?, T?> { - override fun getValue(thisRef: Any?, property: KProperty<*>): T? { - val name = key ?: property.name.asName() - return get(name)?.let { converter.read(it) } - } +): MutableMetaDelegate<T?> = object : MutableMetaDelegate<T?> { - override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { - val name = key ?: property.name.asName() - set(name, value?.let { converter.convert(it) }) - } + override val descriptor: MetaDescriptor? get() = converter.descriptor + + + override fun getValue(thisRef: Any?, property: KProperty<*>): T? { + val name = key ?: property.name.asName() + return get(name)?.let { converter.read(it) } } + override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { + val name = key ?: property.name.asName() + set(name, value?.let { converter.convert(it) }) + } +} + @Deprecated("Use convertable", ReplaceWith("convertable(converter, key)")) -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>): MutableMetaDelegate<T?> = convertable(converter, key) /** @@ -53,7 +66,7 @@ public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConver public inline fun <reified T> MutableMetaProvider.serializable( descriptor: MetaDescriptor? = null, key: Name? = null, -): ReadWriteProperty<Any?, T?> = convertable(MetaConverter.serializable(descriptor), key) +): MutableMetaDelegate<T?> = convertable(MetaConverter.serializable(descriptor), key) /** * Use [converter] to convert a list of same name siblings meta to object and back. @@ -62,10 +75,12 @@ public inline fun <reified T> MutableMetaProvider.serializable( public fun <T> MutableMeta.listOfConvertable( converter: MetaConverter<T>, key: Name? = null, -): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> { +): MutableMetaDelegate<List<T>> = object : MutableMetaDelegate<List<T>> { + override val descriptor: MetaDescriptor? = converter.descriptor?.copy(multiple = true) + override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> { val name = key ?: property.name.asName() - return getIndexed(name).values.map { converter.read(it) } + return getIndexedList(name).map { converter.read(it) } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) { @@ -76,26 +91,33 @@ public fun <T> MutableMeta.listOfConvertable( @DFExperimental public inline fun <reified T> MutableMeta.listOfSerializable( - descriptor: MetaDescriptor? = null, key: Name? = null, -): ReadWriteProperty<Any?, List<T>> = listOfConvertable(MetaConverter.serializable(descriptor), key) + descriptor: MetaDescriptor? = null, +): MutableMetaDelegate<List<T>> = listOfConvertable(MetaConverter.serializable(descriptor), key) -public fun MutableMetaProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> = - object : ReadWriteProperty<Any?, Value?> { - override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = - get(key ?: property.name.asName())?.value +public fun MutableMetaProvider.value( + key: Name? = null, + descriptor: MetaDescriptor? = null, +): MutableMetaDelegate<Value?> = object : MutableMetaDelegate<Value?> { + override val descriptor: MetaDescriptor? = descriptor - override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { - setValue(key ?: property.name.asName(), value) - } + override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = + get(key ?: property.name.asName())?.value + + override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { + setValue(key ?: property.name.asName(), value) } +} public fun <T> MutableMetaProvider.value( key: Name? = null, writer: (T) -> Value? = { Value.of(it) }, + descriptor: MetaDescriptor? = null, reader: (Value?) -> T, -): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> { +): MutableMetaDelegate<T> = object : MutableMetaDelegate<T> { + override val descriptor: MetaDescriptor? = descriptor + override fun getValue(thisRef: Any?, property: KProperty<*>): T = reader(get(key ?: property.name.asName())?.value) @@ -106,65 +128,65 @@ public fun <T> MutableMetaProvider.value( /* Read-write delegates for [MutableItemProvider] */ -public fun MutableMetaProvider.string(key: Name? = null): ReadWriteProperty<Any?, String?> = +public fun MutableMetaProvider.string(key: Name? = null): MutableMetaDelegate<String?> = value(key) { it?.string } -public fun MutableMetaProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> = +public fun MutableMetaProvider.boolean(key: Name? = null): MutableMetaDelegate<Boolean?> = value(key) { it?.boolean } -public fun MutableMetaProvider.number(key: Name? = null): ReadWriteProperty<Any?, Number?> = +public fun MutableMetaProvider.number(key: Name? = null): MutableMetaDelegate<Number?> = value(key) { it?.number } -public fun MutableMetaProvider.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> = +public fun MutableMetaProvider.string(default: String, key: Name? = null): MutableMetaDelegate<String> = value(key) { it?.string ?: default } -public fun MutableMetaProvider.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> = +public fun MutableMetaProvider.boolean(default: Boolean, key: Name? = null): MutableMetaDelegate<Boolean> = value(key) { it?.boolean ?: default } -public fun MutableMetaProvider.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> = +public fun MutableMetaProvider.number(default: Number, key: Name? = null): MutableMetaDelegate<Number> = value(key) { it?.number ?: default } -public fun MutableMetaProvider.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> = +public fun MutableMetaProvider.string(key: Name? = null, default: () -> String): MutableMetaDelegate<String> = value(key) { it?.string ?: default() } -public fun MutableMetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> = +public fun MutableMetaProvider.boolean(key: Name? = null, default: () -> Boolean): MutableMetaDelegate<Boolean> = value(key) { it?.boolean ?: default() } -public fun MutableMetaProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> = +public fun MutableMetaProvider.number(key: Name? = null, default: () -> Number): MutableMetaDelegate<Number> = value(key) { it?.number ?: default() } public inline fun <reified E : Enum<E>> MutableMetaProvider.enum( default: E, key: Name? = null, -): ReadWriteProperty<Any?, E> = value(key) { value -> value?.string?.let { enumValueOf<E>(it) } ?: default } +): MutableMetaDelegate<E> = value(key) { value -> value?.string?.let { enumValueOf<E>(it) } ?: default } /* Number delegates */ -public fun MutableMetaProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> = +public fun MutableMetaProvider.int(key: Name? = null): MutableMetaDelegate<Int?> = value(key) { it?.int } -public fun MutableMetaProvider.double(key: Name? = null): ReadWriteProperty<Any?, Double?> = +public fun MutableMetaProvider.double(key: Name? = null): MutableMetaDelegate<Double?> = value(key) { it?.double } -public fun MutableMetaProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> = +public fun MutableMetaProvider.long(key: Name? = null): MutableMetaDelegate<Long?> = value(key) { it?.long } -public fun MutableMetaProvider.float(key: Name? = null): ReadWriteProperty<Any?, Float?> = +public fun MutableMetaProvider.float(key: Name? = null): MutableMetaDelegate<Float?> = value(key) { it?.float } /* Safe number delegates*/ -public fun MutableMetaProvider.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> = +public fun MutableMetaProvider.int(default: Int, key: Name? = null): MutableMetaDelegate<Int> = value(key) { it?.int ?: default } -public fun MutableMetaProvider.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> = +public fun MutableMetaProvider.double(default: Double, key: Name? = null): MutableMetaDelegate<Double> = value(key) { it?.double ?: default } -public fun MutableMetaProvider.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> = +public fun MutableMetaProvider.long(default: Long, key: Name? = null): MutableMetaDelegate<Long> = value(key) { it?.long ?: default } -public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> = +public fun MutableMetaProvider.float(default: Float, key: Name? = null): MutableMetaDelegate<Float> = value(key) { it?.float ?: default } @@ -173,7 +195,7 @@ public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWri public fun MutableMetaProvider.stringList( vararg default: String, key: Name? = null, -): ReadWriteProperty<Any?, List<String>> = value( +): MutableMetaDelegate<List<String>> = value( key, writer = { list -> list.map { str -> str.asValue() }.asValue() }, reader = { it?.stringList ?: listOf(*default) }, @@ -181,7 +203,7 @@ public fun MutableMetaProvider.stringList( public fun MutableMetaProvider.stringList( key: Name? = null, -): ReadWriteProperty<Any?, List<String>?> = value( +): MutableMetaDelegate<List<String>?> = value( key, writer = { it -> it?.map { str -> str.asValue() }?.asValue() }, reader = { it?.stringList }, @@ -190,29 +212,18 @@ public fun MutableMetaProvider.stringList( public fun MutableMetaProvider.numberList( vararg default: Number, key: Name? = null, -): ReadWriteProperty<Any?, List<Number>> = value( +): MutableMetaDelegate<List<Number>> = value( key, writer = { it.map { num -> num.asValue() }.asValue() }, reader = { it?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) }, ) -/* A special delegate for double arrays */ - - -public fun MutableMetaProvider.doubleArray( - vararg default: Double, - key: Name? = null, -): ReadWriteProperty<Any?, DoubleArray> = value( - key, - writer = { DoubleArrayValue(it) }, - reader = { it?.doubleArray ?: doubleArrayOf(*default) }, -) public fun <T> MutableMetaProvider.listValue( key: Name? = null, writer: (T) -> Value = { Value.of(it) }, reader: (Value) -> T, -): ReadWriteProperty<Any?, List<T>?> = value( +): MutableMetaDelegate<List<T>?> = value( key, writer = { it?.map(writer)?.asValue() }, reader = { it?.list?.map(reader) } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMeta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMeta.kt index b481962e..7cd28746 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMeta.kt @@ -39,6 +39,9 @@ public interface ObservableMeta : Meta { * A [Meta] which is both observable and mutable */ public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> { + + override val self: ObservableMutableMeta get() = this + override fun getOrCreate(name: Name): ObservableMutableMeta override fun get(name: Name): ObservableMutableMeta? { diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMetaWrapper.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMetaWrapper.kt index 71e15aa9..7c62f692 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMetaWrapper.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/ObservableMetaWrapper.kt @@ -14,10 +14,13 @@ private class ObservableMetaWrapper( val nodeName: Name, val listeners: MutableSet<MetaListener>, ) : ObservableMutableMeta { + + override val self get() = this + override val items: Map<NameToken, ObservableMutableMeta> - get() = root.items.keys.associateWith { + get() = root[nodeName]?.items?.keys?.associateWith { ObservableMetaWrapper(root, nodeName + it, listeners) - } + } ?: emptyMap() override fun get(name: Name): ObservableMutableMeta? = if (root[nodeName + name] == null) { null diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt index 2e9edc1d..fe121c42 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Scheme.kt @@ -12,33 +12,29 @@ import kotlin.reflect.KProperty import kotlin.reflect.KProperty1 /** - * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaSpec]. - * Default item provider and [MetaDescriptor] are optional + * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaReader]. + * + * @param prototype default values provided by this scheme */ -public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurable { +public open class Scheme( + private var prototype: Meta? = null, + descriptor: MetaDescriptor? = null, +) : Described, MetaRepr, MutableMetaProvider, Configurable { /** * Meta to be mutated by this scheme */ - private var target: MutableMeta? = null - get() { - // automatic initialization of target if it is missing - if (field == null) { - field = MutableMeta() - } - return field - } + internal var target: MutableMeta = MutableMeta() /** - * Default values provided by this scheme + * A descriptor of this scheme */ - private var prototype: Meta? = null + final override var descriptor: MetaDescriptor? = descriptor + private set + final override val meta: ObservableMutableMeta = SchemeMeta(Name.EMPTY) - final override var descriptor: MetaDescriptor? = null - private set - /** * This method must be called before the scheme could be used */ @@ -84,13 +80,16 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl override fun toString(): String = meta.toString() private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta { + + override val self get() = this + override var value: Value? get() = target[pathName]?.value ?: prototype?.get(pathName)?.value ?: descriptor?.get(pathName)?.defaultValue set(value) { val oldValue = target[pathName]?.value - target!![pathName] = value + target[pathName] = value if (oldValue != value) { invalidate(Name.EMPTY) } @@ -126,7 +125,7 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl override fun hashCode(): Int = Meta.hashCode(this) override fun set(name: Name, node: Meta?) { - target!![name] = node + target[pathName + name] = node invalidate(name) } @@ -176,18 +175,22 @@ public open class SchemeSpec<T : Scheme>( it.initialize(MutableMeta(), source, descriptor) } + /** + * Write changes made to the [Scheme] to target [MutableMeta]. If the empty [Scheme] contains any data it is copied to the target. + */ public fun write(target: MutableMeta): T = empty().also { + target.update(it.meta) it.initialize(target, Meta.EMPTY, descriptor) } /** - * Generate an empty object + * Generate a blank object. The object could contain some elements if they are defined in a constructor */ public fun empty(): T = builder().also { - it.initialize(MutableMeta(), Meta.EMPTY, descriptor) + it.initialize(MutableMeta(), it.target, descriptor) } - override fun convert(obj: T): Meta = obj.meta + override fun convert(obj: T): Meta = obj.meta /** * A convenience method to use specifications in builders @@ -197,7 +200,6 @@ public open class SchemeSpec<T : Scheme>( } - /** * Update a [MutableMeta] using given specification */ @@ -217,7 +219,7 @@ public fun <T : Scheme> Configurable.updateWith( /** - * A delegate that uses a [MetaSpec] to wrap a child of this provider + * A delegate that uses a [MetaReader] to wrap a child of this provider */ public fun <T : Scheme> MutableMeta.scheme( spec: SchemeSpec<T>, @@ -240,7 +242,7 @@ public fun <T : Scheme> Scheme.scheme( ): ReadWriteProperty<Any?, T> = meta.scheme(spec, key) /** - * A delegate that uses a [MetaSpec] to wrap a child of this provider. + * A delegate that uses a [MetaReader] to wrap a child of this provider. * Returns null if meta with given name does not exist. */ public fun <T : Scheme> MutableMeta.schemeOrNull( @@ -265,18 +267,17 @@ public fun <T : Scheme> Scheme.schemeOrNull( ): ReadWriteProperty<Any?, T?> = meta.schemeOrNull(spec, key) /** - * A delegate that uses a [MetaSpec] to wrap a list of child providers. + * A delegate that uses a [MetaReader] to wrap a list of child providers. * If children are mutable, the changes in list elements are reflected on them. * The list is a snapshot of children state, so change in structure is not reflected on its composition. */ -@DFExperimental public fun <T : Scheme> MutableMeta.listOfScheme( spec: SchemeSpec<T>, key: Name? = null, ): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> { override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> { val name = key ?: property.name.asName() - return getIndexed(name).values.map { spec.write(it as MutableMeta) } + return getIndexedList(name).map { spec.write(it as MutableMeta) } } override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) { @@ -286,7 +287,6 @@ public fun <T : Scheme> MutableMeta.listOfScheme( } -@DFExperimental public fun <T : Scheme> Scheme.listOfScheme( spec: SchemeSpec<T>, key: Name? = null, diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/SealedMeta.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/SealedMeta.kt index e842b990..b218fad6 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/SealedMeta.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/SealedMeta.kt @@ -13,6 +13,9 @@ public class SealedMeta( override val value: Value?, override val items: Map<NameToken, SealedMeta>, ) : TypedMeta<SealedMeta> { + + override val self: SealedMeta get() = this + override fun toString(): String = Meta.toString(this) override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta) @@ -76,6 +79,8 @@ internal class MetaBuilder( override fun set(name: Name, node: Meta?) { + //skip setting if value has not changed + if(node == get(name)) return when (name.length) { 0 -> error("Can't set a meta with empty name") 1 -> { @@ -89,7 +94,7 @@ internal class MetaBuilder( } else -> { - getOrCreate(name.first().asName()).set(name.cutFirst(), node) + getOrCreate(name.first().asName())[name.cutFirst()] = node } } } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Value.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Value.kt index 66e14c86..2ab7b9ee 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Value.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/Value.kt @@ -256,8 +256,6 @@ public fun ShortArray.asValue(): Value = if (isEmpty()) Null else ListValue(map public fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) -public fun ByteArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) }) - public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this) diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt index 5d4d81ad..2590273e 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder.kt @@ -11,9 +11,6 @@ import kotlin.collections.set public class MetaDescriptorBuilder @PublishedApi internal constructor() { 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 multiple: Boolean = false public var valueRestriction: ValueRestriction = ValueRestriction.NONE @@ -50,6 +47,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() { ): Unit { when (name.length) { 0 -> error("Can't set descriptor to root") + 1 -> { children[name.first().body] = descriptorBuilder } @@ -60,7 +58,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() { } } - internal fun node( + public fun node( name: Name, descriptorBuilder: MetaDescriptor, ): Unit { diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/schemeDescriptor.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/schemeDescriptor.kt index a2a77182..c7b73508 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/schemeDescriptor.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/descriptors/schemeDescriptor.kt @@ -3,11 +3,12 @@ package space.kscience.dataforge.meta.descriptors import space.kscience.dataforge.meta.Scheme import space.kscience.dataforge.meta.SchemeSpec import space.kscience.dataforge.meta.ValueType -import space.kscience.dataforge.misc.DFExperimental import kotlin.reflect.KProperty1 import kotlin.reflect.typeOf -@DFExperimental +/** + * Add a value item to a [MetaDescriptor] inferring some of its properties from the type + */ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value( property: KProperty1<S, T>, noinline block: MetaDescriptorBuilder.() -> Unit = {}, @@ -39,7 +40,9 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value( else -> node(property.name, block) } -@DFExperimental +/** + * Add a schem-based branch to a [MetaDescriptor] + */ public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme( property: KProperty1<S, T>, spec: SchemeSpec<T>, diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/exoticValues.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/exoticValues.kt index 74952053..eb39e985 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/exoticValues.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/exoticValues.kt @@ -1,5 +1,9 @@ package space.kscience.dataforge.meta +import space.kscience.dataforge.names.Name +import kotlin.properties.ReadOnlyProperty +import kotlin.properties.ReadWriteProperty + /** * A value built from string which content and type are parsed on-demand @@ -44,3 +48,79 @@ public class DoubleArrayValue(override val value: DoubleArray) : Value, Iterable } public fun DoubleArray.asValue(): Value = if (isEmpty()) Null else DoubleArrayValue(this) + +public val Value.doubleArray: DoubleArray + get() = if (this is DoubleArrayValue) { + value + } else { + DoubleArray(list.size) { list[it].double } + } + +public val Meta?.doubleArray: DoubleArray? get() = this?.value?.doubleArray + +public fun MetaProvider.doubleArray( + vararg default: Double, + key: Name? = null, +): ReadOnlyProperty<Any?, DoubleArray> = value( + key, + reader = { it?.doubleArray ?: doubleArrayOf(*default) }, +) + +public fun MutableMetaProvider.doubleArray( + vararg default: Double, + key: Name? = null, +): ReadWriteProperty<Any?, DoubleArray> = value( + key, + writer = { DoubleArrayValue(it) }, + reader = { it?.doubleArray ?: doubleArrayOf(*default) }, +) + + +public class ByteArrayValue(override val value: ByteArray) : Value, Iterable<Byte> { + override val type: ValueType get() = ValueType.LIST + override val list: List<Value> get() = value.map { NumberValue(it) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Value) return false + + return when (other) { + is ByteArrayValue -> value.contentEquals(other.value) + else -> list == other.list + } + } + + override fun hashCode(): Int = value.contentHashCode() + + override fun toString(): String = list.joinToString(prefix = "[", postfix = "]") + + override fun iterator(): Iterator<Byte> = value.iterator() +} + +public fun ByteArray.asValue(): Value = ByteArrayValue(this) + +public val Value.byteArray: ByteArray + get() = if (this is ByteArrayValue) { + value + } else { + ByteArray(list.size) { list[it].number.toByte() } + } + +public val Meta?.byteArray: ByteArray? get() = this?.value?.byteArray + +public fun MetaProvider.byteArray( + vararg default: Byte, + key: Name? = null, +): ReadOnlyProperty<Any?, ByteArray> = value( + key, + reader = { it?.byteArray ?: byteArrayOf(*default) }, +) + +public fun MutableMetaProvider.byteArray( + vararg default: Byte, + key: Name? = null, +): ReadWriteProperty<Any?, ByteArray> = value( + key, + writer = { ByteArrayValue(it) }, + reader = { it?.byteArray ?: byteArrayOf(*default) }, +) \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/valueExtensions.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/valueExtensions.kt index e6b622ff..73464305 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/valueExtensions.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/meta/valueExtensions.kt @@ -31,12 +31,5 @@ public inline fun <reified E : Enum<E>> Value.enum(): E = if (this is EnumValue< public val Value.stringList: List<String> get() = list.map { it.string } -public val Value.doubleArray: DoubleArray - get() = if (this is DoubleArrayValue) { - value - } else { - DoubleArray(list.size) { list[it].double } - } - public fun Value.toMeta(): Meta = Meta(this) \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/annotations.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/annotations.kt index 3c9d6ac3..29568403 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/annotations.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/annotations.kt @@ -18,4 +18,11 @@ public annotation class DFExperimental */ @RequiresOptIn(level = RequiresOptIn.Level.WARNING) @Retention(AnnotationRetention.BINARY) -public annotation class DFInternal \ No newline at end of file +public annotation class DFInternal + +/** + * Annotation marks methods that explicitly use KType without checking that it corresponds to the type parameter + */ +@RequiresOptIn(level = RequiresOptIn.Level.WARNING) +@Retention(AnnotationRetention.BINARY) +public annotation class UnsafeKType \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/cast.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/cast.kt deleted file mode 100644 index e714d596..00000000 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/misc/cast.kt +++ /dev/null @@ -1,3 +0,0 @@ -package space.kscience.dataforge.misc - -public expect inline fun <T> Any?.unsafeCast(): T \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt index b46a3507..7867330c 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/Name.kt @@ -58,7 +58,7 @@ public class Name(public val tokens: List<NameToken>) { */ public fun parse(string: String): Name { if (string.isBlank()) return EMPTY - val tokens = sequence { + val tokens = buildList<NameToken> { var bodyBuilder = StringBuilder() var queryBuilder = StringBuilder() var bracketCount = 0 @@ -91,7 +91,7 @@ public class Name(public val tokens: List<NameToken>) { else -> when (it) { '.' -> { val query = if (queryBuilder.isEmpty()) null else queryBuilder.toString() - yield(NameToken(bodyBuilder.toString(), query)) + add(NameToken(bodyBuilder.toString(), query)) bodyBuilder = StringBuilder() queryBuilder = StringBuilder() } @@ -106,9 +106,9 @@ public class Name(public val tokens: List<NameToken>) { } } val query = if (queryBuilder.isEmpty()) null else queryBuilder.toString() - yield(NameToken(bodyBuilder.toString(), query)) + add(NameToken(bodyBuilder.toString(), query)) } - return Name(tokens.toList()) + return Name(tokens) } } } diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameIndexComparator.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameIndexComparator.kt new file mode 100644 index 00000000..742f8ebb --- /dev/null +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameIndexComparator.kt @@ -0,0 +1,30 @@ +package space.kscience.dataforge.names + +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.getIndexed + + +/** + * A comparator for indices in a [Name]. If both indices are integers, compare them as integers. + * Null always stays "before" non-null index. + */ +public object NameIndexComparator : Comparator<String?> { + override fun compare(a: String?, b: String?): Int { + if (a == b) return 0 + if (a == null) return 1 + if (b == null) return -1 + val aInt = a.toIntOrNull() + val bInt = b.toIntOrNull() + return if (aInt != null && bInt != null) { + aInt.compareTo(bInt) + } else { + a.compareTo(b) + } + } + +} + +public fun Meta.getIndexedList(name: Name): List<Meta> = getIndexed(name).entries.sortedWith( + //sort by index + compareBy(space.kscience.dataforge.names.NameIndexComparator) { it.key } +).map{it.value} \ No newline at end of file diff --git a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt index 0dc83c57..83752b9a 100644 --- a/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt +++ b/dataforge-meta/src/commonMain/kotlin/space/kscience/dataforge/names/NameToken.kt @@ -69,7 +69,7 @@ public class NameToken(public val body: String, public val index: String? = null public fun parse(string: String): NameToken { val body = string.substringBefore('[') val index = string.substringAfter('[', "") - if (index.isNotEmpty() && index.endsWith(']')) error("NameToken with index must end with ']'") + if (index.isNotEmpty() && !index.endsWith(']')) error("NameToken with index must end with ']'") return NameToken(body, index.removeSuffix("]")) } } diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaTest.kt index 85db7bd6..78b5cdb4 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/MetaTest.kt @@ -61,4 +61,33 @@ class MetaTest { assertEquals(null, indexed["8"]) assertEquals(12, indexed["12"].int) } + + @Test + fun reset() { + val oldMeta = MutableMeta { + "a" put { + "value" put "aValue" + } + "b" put { + "value" put "bValue" + } + "c" put { + "value" put "cValue" + } + } + val newMeta = Meta { + "a" put { + "value" put "aValue" + } + "b" put { + "value" put "bValue" + } + "d" put { + "value" put "dValue" + } + } + oldMeta.reset(newMeta) + println(oldMeta) + assertEquals(setOf("a", "b", "d"), oldMeta.items.keys.map { it.toString() }.toSet()) + } } \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt deleted file mode 100644 index bb2736ce..00000000 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SchemeTest.kt +++ /dev/null @@ -1,49 +0,0 @@ -package space.kscience.dataforge.meta - -import space.kscience.dataforge.misc.DFExperimental -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull - -@DFExperimental -class SchemeTest { - @Test - fun testSchemeWrappingBeforeEdit() { - val config = MutableMeta() - val scheme = TestScheme.write(config) - scheme.a = 29 - assertEquals(29, config["a"].int) - } - - @Test - fun testSchemeWrappingAfterEdit() { - val scheme = TestScheme.empty() - scheme.a = 29 - val config = MutableMeta() - scheme.retarget(config) - assertEquals(29, scheme.a) - } - - @Test - fun testSchemeSubscription() { - val scheme = TestScheme.empty() - var flag: Int? = null - scheme.useProperty(TestScheme::a) { a -> - flag = a - } - scheme.a = 2 - assertEquals(2, flag) - } - - @Test - fun testListSubscription(){ - val scheme = TestScheme.empty() - var value: Value? = null - scheme.v = ListValue(0.0,0.0,0.0) - scheme.useProperty(TestScheme::v){ - value = it - } - scheme.v = ListValue(1.0, 2.0, 3.0) - assertNotNull(value) - } -} \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt index 8d4d3537..dc9b9d64 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/meta/SpecificationTest.kt @@ -1,7 +1,17 @@ package space.kscience.dataforge.meta +import space.kscience.dataforge.misc.DFExperimental import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertNotNull + + +internal class SubScheme : Scheme() { + + var subValue by string() + + companion object : SchemeSpec<SubScheme>(::SubScheme) +} internal class TestScheme : Scheme() { var list by numberList(1, 2, 3) @@ -11,9 +21,23 @@ internal class TestScheme : Scheme() { var v by value() + var sub by scheme(SubScheme) + companion object : SchemeSpec<TestScheme>(::TestScheme) } +private class SchemeWithInit: Scheme(){ + init { + set("initial", "initialValue") + } + + var initial by string() + + companion object: SchemeSpec<SchemeWithInit>(::SchemeWithInit) +} + + + class SpecificationTest { // @Test @@ -71,4 +95,64 @@ class SpecificationTest { assertEquals(22, config["child.a"].int) assertEquals("test", config["child.b"].string) } + + @Test + fun testSchemeWrappingBeforeEdit() { + val config = MutableMeta() + val scheme = TestScheme.write(config) + scheme.a = 29 + assertEquals(29, config["a"].int) + } + + @OptIn(DFExperimental::class) + @Test + fun testSchemeWrappingAfterEdit() { + val scheme = TestScheme.empty() + scheme.a = 29 + val config = MutableMeta() + scheme.retarget(config) + assertEquals(29, scheme.a) + } + + @Test + fun testSchemeSubscription() { + val scheme = TestScheme.empty() + var flag: Int? = null + scheme.useProperty(TestScheme::a) { a -> + flag = a + } + scheme.a = 2 + assertEquals(2, flag) + } + + @Test + fun testListSubscription(){ + val scheme = TestScheme.empty() + var value: Value? = null + scheme.v = ListValue(0.0,0.0,0.0) + scheme.useProperty(TestScheme::v){ + value = it + } + scheme.v = ListValue(1.0, 2.0, 3.0) + assertNotNull(value) + } + + @Test + fun testSubScheme(){ + val scheme = TestScheme.empty() + + scheme.sub.subValue = "aaa" + + assertEquals("aaa",scheme.sub.subValue) + } + + + @Test + fun testSchemeWithInit(){ + val scheme = SchemeWithInit() + assertEquals("initialValue", scheme.initial) + scheme.initial = "none" + assertEquals("none", scheme.initial) + } + } \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/names/NameTest.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/names/NameTest.kt index a5bdf3fc..db630487 100644 --- a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/names/NameTest.kt +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/names/NameTest.kt @@ -1,9 +1,6 @@ package space.kscience.dataforge.names -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue +import kotlin.test.* class NameTest { @Test @@ -50,4 +47,19 @@ class NameTest { val name = Name.parse("a.b.c") assertEquals("a.b".parseAsName(), name.cutLast()) } + + @Test + fun tokenParseTest(){ + val token1 = NameToken.parse("token[index]") + assertEquals("token", token1.body) + assertEquals("index", token1.index) + + val token2 = NameToken.parse("token-body") + assertEquals("token-body", token2.body) + assertEquals("", token2.index) + + assertFails { + NameToken.parse("token[22") + } + } } \ No newline at end of file diff --git a/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/values/DoubleArrayValue.kt b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/values/DoubleArrayValue.kt new file mode 100644 index 00000000..30bc2adc --- /dev/null +++ b/dataforge-meta/src/commonTest/kotlin/space/kscience/dataforge/values/DoubleArrayValue.kt @@ -0,0 +1,24 @@ +package space.kscience.dataforge.values + +import space.kscience.dataforge.meta.DoubleArrayValue +import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.doubleArray +import space.kscience.dataforge.meta.get +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +class DoubleArrayValue { + @Test + fun doubleArrayWriteRead(){ + val meta = Meta{ + "doubleArray" put doubleArrayOf(1.0,2.0,3.0) + } + + assertTrue { + meta["doubleArray"]?.value is DoubleArrayValue + } + + assertEquals(2.0, meta["doubleArray"].doubleArray?.get(1)) + } +} \ No newline at end of file diff --git a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt b/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt index b38d5891..57d324c7 100644 --- a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt +++ b/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/meta/DynamicMeta.kt @@ -31,6 +31,9 @@ public fun Meta.toDynamic(): dynamic { } public class DynamicMeta(internal val obj: dynamic) : TypedMeta<DynamicMeta> { + + override val self: DynamicMeta get() = this + private fun keys(): Array<String> = js("Object").keys(obj) as Array<String> private fun isArray(obj: dynamic): Boolean = diff --git a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/misc/castJs.kt b/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/misc/castJs.kt deleted file mode 100644 index b057bcbe..00000000 --- a/dataforge-meta/src/jsMain/kotlin/space/kscience/dataforge/misc/castJs.kt +++ /dev/null @@ -1,5 +0,0 @@ -package space.kscience.dataforge.misc -import kotlin.js.unsafeCast as unsafeCastJs - -@Suppress("NOTHING_TO_INLINE") -public actual inline fun <T> Any?.unsafeCast(): T = unsafeCastJs<T>() \ No newline at end of file diff --git a/dataforge-meta/src/jvmMain/kotlin/space/kscience/dataforge/misc/castJvm.kt b/dataforge-meta/src/jvmMain/kotlin/space/kscience/dataforge/misc/castJvm.kt deleted file mode 100644 index 27d399fe..00000000 --- a/dataforge-meta/src/jvmMain/kotlin/space/kscience/dataforge/misc/castJvm.kt +++ /dev/null @@ -1,4 +0,0 @@ -package space.kscience.dataforge.misc - -@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") -public actual inline fun <T> Any?.unsafeCast(): T = this as T \ No newline at end of file diff --git a/dataforge-meta/src/nativeMain/kotlin/space/kscience/dataforge/misc/castNative.kt b/dataforge-meta/src/nativeMain/kotlin/space/kscience/dataforge/misc/castNative.kt deleted file mode 100644 index 4d9aa758..00000000 --- a/dataforge-meta/src/nativeMain/kotlin/space/kscience/dataforge/misc/castNative.kt +++ /dev/null @@ -1,4 +0,0 @@ -package space.kscience.dataforge.misc - -@Suppress("UNCHECKED_CAST") -public actual inline fun <T> Any?.unsafeCast(): T = this as T \ No newline at end of file diff --git a/dataforge-meta/src/wasmJsMain/kotlin/space/kscience/dataforge/misc/castWasm.kt b/dataforge-meta/src/wasmJsMain/kotlin/space/kscience/dataforge/misc/castWasm.kt deleted file mode 100644 index 27d399fe..00000000 --- a/dataforge-meta/src/wasmJsMain/kotlin/space/kscience/dataforge/misc/castWasm.kt +++ /dev/null @@ -1,4 +0,0 @@ -package space.kscience.dataforge.misc - -@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE") -public actual inline fun <T> Any?.unsafeCast(): T = this as T \ No newline at end of file diff --git a/dataforge-scripting/README.md b/dataforge-scripting/README.md index fbc5cb69..1f650bea 100644 --- a/dataforge-scripting/README.md +++ b/dataforge-scripting/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-scripting:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-scripting:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-scripting:0.8.0") + implementation("space.kscience:dataforge-scripting:0.9.0-dev-1") } ``` diff --git a/dataforge-workspace/README.md b/dataforge-workspace/README.md index cea37368..87b38c6e 100644 --- a/dataforge-workspace/README.md +++ b/dataforge-workspace/README.md @@ -6,7 +6,7 @@ ## Artifact: -The Maven coordinates of this project are `space.kscience:dataforge-workspace:0.8.0`. +The Maven coordinates of this project are `space.kscience:dataforge-workspace:0.9.0-dev-1`. **Gradle Kotlin DSL:** ```kotlin @@ -16,6 +16,6 @@ repositories { } dependencies { - implementation("space.kscience:dataforge-workspace:0.8.0") + implementation("space.kscience:dataforge-workspace:0.9.0-dev-1") } ``` diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt index e636de49..a1a754a4 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Task.kt @@ -5,11 +5,12 @@ import space.kscience.dataforge.data.DataSink import space.kscience.dataforge.data.GoalExecutionRestriction import space.kscience.dataforge.data.MutableDataTree import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.MetaReader import space.kscience.dataforge.meta.MetaRepr -import space.kscience.dataforge.meta.MetaSpec import space.kscience.dataforge.meta.descriptors.Described import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.misc.DfType +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import space.kscience.dataforge.workspace.Task.Companion.TYPE import kotlin.reflect.KType @@ -43,10 +44,10 @@ public interface Task<T> : Described { } /** - * A [Task] with [MetaSpec] for wrapping and unwrapping task configuration + * A [Task] with [MetaReader] for wrapping and unwrapping task configuration */ public interface TaskWithSpec<T, C : Any> : Task<T> { - public val spec: MetaSpec<C> + public val spec: MetaReader<C> override val descriptor: MetaDescriptor? get() = spec.descriptor public suspend fun execute(workspace: Workspace, taskName: Name, configuration: C): TaskResult<T> @@ -90,7 +91,8 @@ public fun <T : Any> Task( taskMeta: Meta, ): TaskResult<T> { //TODO use safe builder and check for external data on add and detects cycles - val dataset = MutableDataTree<T>(resultType, workspace.context).apply { + @OptIn(UnsafeKType::class) + val dataset = MutableDataTree<T>(resultType).apply { TaskResultBuilder(workspace, taskName, taskMeta, this).apply { withContext(GoalExecutionRestriction() + workspace.goalLogger) { builder() @@ -98,7 +100,6 @@ public fun <T : Any> Task( } } return workspace.wrapResult(dataset, taskName, taskMeta) - } } @@ -117,13 +118,14 @@ public inline fun <reified T : Any> Task( * @param builder for resulting data set */ + @Suppress("FunctionName") public fun <T : Any, C : MetaRepr> Task( resultType: KType, - specification: MetaSpec<C>, + specification: MetaReader<C>, builder: suspend TaskResultBuilder<T>.(C) -> Unit, ): TaskWithSpec<T, C> = object : TaskWithSpec<T, C> { - override val spec: MetaSpec<C> = specification + override val spec: MetaReader<C> = specification override suspend fun execute( workspace: Workspace, @@ -132,7 +134,8 @@ public fun <T : Any, C : MetaRepr> Task( ): TaskResult<T> = withContext(GoalExecutionRestriction() + workspace.goalLogger) { //TODO use safe builder and check for external data on add and detects cycles val taskMeta = configuration.toMeta() - val dataset = MutableDataTree<T>(resultType, this).apply { + @OptIn(UnsafeKType::class) + val dataset = MutableDataTree<T>(resultType).apply { TaskResultBuilder(workspace, taskName, taskMeta, this).apply { builder(configuration) } } workspace.wrapResult(dataset, taskName, taskMeta) @@ -140,6 +143,6 @@ public fun <T : Any, C : MetaRepr> Task( } public inline fun <reified T : Any, C : MetaRepr> Task( - specification: MetaSpec<C>, + specification: MetaReader<C>, noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit, ): Task<T> = Task(typeOf<T>(), specification, builder) \ No newline at end of file diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/TaskResult.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/TaskResult.kt index 7aa94101..d4d4291a 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/TaskResult.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/TaskResult.kt @@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch -import space.kscience.dataforge.data.ObservableDataTree +import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.asSequence import space.kscience.dataforge.data.launch import space.kscience.dataforge.meta.Meta @@ -17,16 +17,16 @@ import space.kscience.dataforge.names.Name * @param taskMeta The configuration of the task that produced the result */ public data class TaskResult<T>( - public val content: ObservableDataTree<T>, + public val content: DataTree<T>, public val workspace: Workspace, public val taskName: Name, public val taskMeta: Meta, -) : ObservableDataTree<T> by content +) : DataTree<T> by content /** * Wrap data into [TaskResult] */ -public fun <T> Workspace.wrapResult(data: ObservableDataTree<T>, taskName: Name, taskMeta: Meta): TaskResult<T> = +public fun <T> Workspace.wrapResult(data: DataTree<T>, taskName: Name, taskMeta: Meta): TaskResult<T> = TaskResult(data, this, taskName, taskMeta) /** diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Workspace.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Workspace.kt index f3ea322c..7247240b 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Workspace.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/Workspace.kt @@ -2,7 +2,10 @@ package space.kscience.dataforge.workspace import kotlinx.coroutines.CoroutineScope import space.kscience.dataforge.context.ContextAware -import space.kscience.dataforge.data.* +import space.kscience.dataforge.data.Data +import space.kscience.dataforge.data.DataTree +import space.kscience.dataforge.data.asSequence +import space.kscience.dataforge.data.get import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.misc.DfType @@ -11,7 +14,7 @@ import space.kscience.dataforge.provider.Provider import kotlin.coroutines.CoroutineContext -public fun interface DataSelector<T> { +public fun interface DataSelector<out T> { public suspend fun select(workspace: Workspace, meta: Meta): DataTree<T> } @@ -26,7 +29,7 @@ public interface Workspace : ContextAware, Provider, CoroutineScope { /** * The whole data node for current workspace */ - public val data: ObservableDataTree<*> + public val data: DataTree<*> /** * All targets associated with the workspace diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt index 4705c3b0..013c0171 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceBuilder.kt @@ -1,6 +1,5 @@ package space.kscience.dataforge.workspace -import kotlinx.coroutines.CoroutineScope import space.kscience.dataforge.actions.Action import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.ContextBuilder @@ -12,6 +11,7 @@ import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder import space.kscience.dataforge.misc.DFBuilder +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.asName import kotlin.collections.set @@ -71,10 +71,10 @@ public inline fun <reified T : Any> TaskContainer.task( } /** - * Create a task based on [MetaSpec] + * Create a task based on [MetaReader] */ public inline fun <reified T : Any, C : MetaRepr> TaskContainer.task( - specification: MetaSpec<C>, + specification: MetaReader<C>, noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit, ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<T>>> = PropertyDelegateProvider { _, property -> val taskName = Name.parse(property.name) @@ -98,19 +98,19 @@ public inline fun <reified T : Any> TaskContainer.task( public inline fun <T : Any, reified R : Any> TaskContainer.action( selector: DataSelector<T>, action: Action<T, R>, - noinline metaTransform: MutableMeta.()-> Unit = {}, + noinline metaTransform: MutableMeta.() -> Unit = {}, noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<R>>> = task(MetaDescriptor(descriptorBuilder)) { - result(action.execute(from(selector), taskMeta.copy(metaTransform))) + result(action.execute(from(selector), taskMeta.copy(metaTransform), workspace)) } public class WorkspaceBuilder( private val parentContext: Context = Global, - private val coroutineScope: CoroutineScope = parentContext, ) : TaskContainer { private var context: Context? = null - private val data = MutableDataTree<Any?>(typeOf<Any?>(), coroutineScope) + @OptIn(UnsafeKType::class) + private val data = MutableDataTree<Any?>(typeOf<Any?>()) private val targets: HashMap<String, Meta> = HashMap() private val tasks = HashMap<Name, Task<*>>() private var cache: WorkspaceCache? = null diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceImpl.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceImpl.kt index 21c5e8c2..94839d62 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceImpl.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/WorkspaceImpl.kt @@ -2,14 +2,14 @@ package space.kscience.dataforge.workspace import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.gather -import space.kscience.dataforge.data.ObservableDataTree +import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.names.Name internal class WorkspaceImpl internal constructor( override val context: Context, - override val data: ObservableDataTree<*>, + override val data: DataTree<*>, override val targets: Map<String, Meta>, tasks: Map<Name, Task<*>>, private val postProcess: suspend (TaskResult<*>) -> TaskResult<*>, diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/envelopeData.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/envelopeData.kt index d54ff510..a74f8f05 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/envelopeData.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/envelopeData.kt @@ -3,14 +3,14 @@ package space.kscience.dataforge.workspace import space.kscience.dataforge.data.Data import space.kscience.dataforge.data.await import space.kscience.dataforge.io.* -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import kotlin.reflect.typeOf /** * Convert an [Envelope] to a data via given format. The actual parsing is done lazily. */ -@OptIn(DFInternal::class) +@OptIn(UnsafeKType::class) public inline fun <reified T : Any> Envelope.toData(format: IOReader<T>): Data<T> = Data(typeOf<T>(), meta) { data?.readWith(format) ?: error("Can't convert envelope without data to Data") } diff --git a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/taskBuilders.kt b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/taskBuilders.kt index 1900ff23..15565995 100644 --- a/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/taskBuilders.kt +++ b/dataforge-workspace/src/commonMain/kotlin/space/kscience/dataforge/workspace/taskBuilders.kt @@ -3,8 +3,8 @@ package space.kscience.dataforge.workspace import space.kscience.dataforge.actions.Action import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.data.DataTree -import space.kscience.dataforge.data.branch import space.kscience.dataforge.data.forEach +import space.kscience.dataforge.data.putAll import space.kscience.dataforge.data.transform import space.kscience.dataforge.meta.* import space.kscience.dataforge.misc.DFExperimental @@ -101,7 +101,7 @@ public suspend inline fun <T, reified R> TaskResultBuilder<R>.transformEach( * Set given [dataSet] as a task result. */ public fun <T> TaskResultBuilder<T>.result(dataSet: DataTree<T>) { - branch(dataSet) + this.putAll(dataSet) } /** @@ -113,7 +113,7 @@ public suspend inline fun <T, reified R> TaskResultBuilder<R>.actionFrom( action: Action<T, R>, dependencyMeta: Meta = defaultDependencyMeta, ) { - branch(action.execute(from(selector, dependencyMeta), dependencyMeta)) + putAll(action.execute(from(selector, dependencyMeta), dependencyMeta, workspace)) } diff --git a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/CachingAction.kt b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/CachingAction.kt new file mode 100644 index 00000000..5f88ab74 --- /dev/null +++ b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/CachingAction.kt @@ -0,0 +1,19 @@ +package space.kscience.dataforge.workspace + +import space.kscience.dataforge.actions.AbstractAction +import space.kscience.dataforge.data.* +import space.kscience.dataforge.meta.Meta +import kotlin.reflect.KType + +internal class CachingAction<T>(type: KType, private val caching: (NamedData<T>) -> NamedData<T>) : + AbstractAction<T, T>(type) { + override fun DataSink<T>.generate(source: DataTree<T>, meta: Meta) { + source.forEach { + put(caching(it)) + } + } + + override suspend fun DataSink<T>.update(source: DataTree<T>, meta: Meta, updatedData: DataUpdate<T>) { + put(updatedData.name, updatedData.data?.named(updatedData.name)?.let(caching)) + } +} \ No newline at end of file diff --git a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCache.kt b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCache.kt index a43657f8..4d2578e5 100644 --- a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCache.kt +++ b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCache.kt @@ -1,19 +1,22 @@ package space.kscience.dataforge.workspace -import kotlinx.coroutines.flow.map import kotlinx.io.* import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.serializer +import space.kscience.dataforge.actions.Action +import space.kscience.dataforge.actions.invoke import space.kscience.dataforge.context.error import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.request -import space.kscience.dataforge.data.* +import space.kscience.dataforge.data.Data +import space.kscience.dataforge.data.await +import space.kscience.dataforge.data.named import space.kscience.dataforge.io.* import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.misc.DFInternal +import space.kscience.dataforge.misc.UnsafeKType import space.kscience.dataforge.names.withIndex import java.nio.file.Path import kotlin.io.path.deleteIfExists @@ -51,7 +54,8 @@ public class FileWorkspaceCache(public val cacheDirectory: Path) : WorkspaceCach // private fun <T : Any> TaskData<*>.checkType(taskType: KType): TaskData<T> = this as TaskData<T> - @OptIn(DFExperimental::class, DFInternal::class) + + @OptIn(DFExperimental::class, UnsafeKType::class) override suspend fun <T> cache(result: TaskResult<T>): TaskResult<T> { val io = result.workspace.context.request(IOPlugin) @@ -59,8 +63,8 @@ public class FileWorkspaceCache(public val cacheDirectory: Path) : WorkspaceCach ?: ProtobufIOFormat(result.dataType) ?: error("Can't resolve IOFormat for ${result.dataType}") - fun cacheOne(data: NamedData<T>): NamedData<T> { + val cachingAction: Action<T, T> = CachingAction(result.dataType) { data -> val path = cacheDirectory / result.taskName.withIndex(result.taskMeta.hashCode().toString(16)).toString() / data.name.toString() @@ -79,7 +83,7 @@ public class FileWorkspaceCache(public val cacheDirectory: Path) : WorkspaceCach } } - //waiting for data in current scope because Envelope is synchronous + //waiting for data in the current scope because Envelope is synchronous return@Data data.await().also { result -> val envelope = Envelope { meta = data.meta @@ -91,12 +95,10 @@ public class FileWorkspaceCache(public val cacheDirectory: Path) : WorkspaceCach } } - return datum.named(data.name) + datum.named(data.name) } - - val cachedTree = result.asSequence().map { cacheOne(it) } - .toObservableTree(result.dataType, result.workspace, result.updates().map { cacheOne(it) }) + val cachedTree = cachingAction(result) return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta) } diff --git a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/InMemoryWorkspaceCache.kt b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/InMemoryWorkspaceCache.kt index a3792231..8ba39ec1 100644 --- a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/InMemoryWorkspaceCache.kt +++ b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/InMemoryWorkspaceCache.kt @@ -1,8 +1,11 @@ package space.kscience.dataforge.workspace -import kotlinx.coroutines.flow.map -import space.kscience.dataforge.data.* +import space.kscience.dataforge.actions.Action +import space.kscience.dataforge.actions.invoke +import space.kscience.dataforge.data.Data +import space.kscience.dataforge.data.named import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.Name import kotlin.reflect.KType import kotlin.reflect.full.isSubtypeOf @@ -19,19 +22,18 @@ public class InMemoryWorkspaceCache : WorkspaceCache { if (type.isSubtypeOf(taskType)) this as Data<T> else error("Cached data type mismatch: expected $taskType but got $type") + @OptIn(DFExperimental::class) override suspend fun <T> cache(result: TaskResult<T>): TaskResult<T> { - fun cacheOne(data: NamedData<T>): NamedData<T> { + val cachingAction: Action<T, T> = CachingAction(result.dataType) { data -> val cachedData = cache.getOrPut(TaskResultId(result.taskName, result.taskMeta)){ HashMap() }.getOrPut(data.name){ data.data } - return cachedData.checkType<T>(result.dataType).named(data.name) + cachedData.checkType<T>(result.dataType).named(data.name) } - - val cachedTree = result.asSequence().map { cacheOne(it) } - .toObservableTree(result.dataType, result.workspace, result.updates().map { cacheOne(it) }) + val cachedTree = cachingAction(result) return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta) } diff --git a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/readFileData.kt b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/readFileData.kt index 1815c3e4..37dafab9 100644 --- a/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/readFileData.kt +++ b/dataforge-workspace/src/jvmMain/kotlin/space/kscience/dataforge/workspace/readFileData.kt @@ -8,15 +8,11 @@ import space.kscience.dataforge.io.* import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.copy import space.kscience.dataforge.misc.DFExperimental -import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.plus -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.StandardWatchEventKinds -import java.nio.file.WatchEvent +import java.nio.file.* import java.nio.file.attribute.BasicFileAttributes import java.nio.file.spi.FileSystemProvider import kotlin.io.path.* @@ -39,7 +35,6 @@ public object FileData { * Read data with supported envelope format and binary format. If the envelope format is null, then read binary directly from file. * The operation is blocking since it must read the meta header. The reading of envelope body is lazy */ -@OptIn(DFExperimental::class) public fun IOPlugin.readFileData( path: Path, ): Data<Binary> { @@ -127,8 +122,6 @@ public fun DataSink<Binary>.files( private fun Path.toName() = Name(map { NameToken.parse(it.nameWithoutExtension) }) -@DFInternal -@DFExperimental public fun DataSink<Binary>.monitorFiles( io: IOPlugin, name: Name, @@ -174,13 +167,22 @@ public fun DataSink<Binary>.monitorFiles( @DFExperimental public fun DataSink<Binary>.resources( io: IOPlugin, - vararg resources: String, + resource: String, + vararg otherResources: String, classLoader: ClassLoader = Thread.currentThread().contextClassLoader, ) { - resources.forEach { resource -> - val path = classLoader.getResource(resource)?.toURI()?.toPath() ?: error( - "Resource with name $resource is not resolved" + //create a file system if necessary + val uri = Thread.currentThread().contextClassLoader.getResource("common")!!.toURI() + try { + uri.toPath() + } catch (e: FileSystemNotFoundException) { + FileSystems.newFileSystem(uri, mapOf("create" to "true")) + } + + listOf(resource,*otherResources).forEach { r -> + val path = classLoader.getResource(r)?.toURI()?.toPath() ?: error( + "Resource with name $r is not resolved" ) - files(io, resource.asName(), path) + files(io, r.asName(), path) } } diff --git a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/CachingWorkspaceTest.kt b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/CachingWorkspaceTest.kt index e5c2c230..7a6a8202 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/CachingWorkspaceTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/CachingWorkspaceTest.kt @@ -3,7 +3,7 @@ package space.kscience.dataforge.workspace import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test -import space.kscience.dataforge.data.wrap +import space.kscience.dataforge.data.putValue import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.get @@ -22,7 +22,7 @@ internal class CachingWorkspaceTest { data { //statically initialize data repeat(5) { - wrap("myData[$it]", it) + putValue("myData[$it]", it) } } diff --git a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/DataPropagationTest.kt b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/DataPropagationTest.kt index d611b1c8..cd38f809 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/DataPropagationTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/DataPropagationTest.kt @@ -47,7 +47,7 @@ class DataPropagationTest { } data { repeat(100) { - wrap("myData[$it]", it) + putValue("myData[$it]", it) } } } diff --git a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileDataTest.kt b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileDataTest.kt index 10a1c268..5466da76 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileDataTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileDataTest.kt @@ -23,12 +23,12 @@ import kotlin.test.assertEquals class FileDataTest { val dataNode = DataTree<String> { - branch("dir") { - wrap("a", "Some string") { + putAll("dir") { + putValue("a", "Some string") { "content" put "Some string" } } - wrap("b", "root data") + putValue("b", "root data") // meta { // "content" put "This is root meta node" // } diff --git a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCacheTest.kt b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCacheTest.kt index 0f16b1c8..0cf4f401 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCacheTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/FileWorkspaceCacheTest.kt @@ -3,11 +3,11 @@ package space.kscience.dataforge.workspace import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Test -import space.kscience.dataforge.data.wrap +import space.kscience.dataforge.data.putValue import space.kscience.dataforge.misc.DFExperimental import java.nio.file.Files -@OptIn(ExperimentalCoroutinesApi::class,DFExperimental::class) +@OptIn(ExperimentalCoroutinesApi::class, DFExperimental::class) class FileWorkspaceCacheTest { @Test @@ -16,7 +16,7 @@ class FileWorkspaceCacheTest { data { //statically initialize data repeat(5) { - wrap("myData[$it]", it) + putValue("myData[$it]", it) } } fileCache(Files.createTempDirectory("dataforge-temporary-cache")) diff --git a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/SimpleWorkspaceTest.kt b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/SimpleWorkspaceTest.kt index b49b9d54..39837c15 100644 --- a/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/SimpleWorkspaceTest.kt +++ b/dataforge-workspace/src/jvmTest/kotlin/space/kscience/dataforge/workspace/SimpleWorkspaceTest.kt @@ -6,7 +6,6 @@ package space.kscience.dataforge.workspace import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Timeout import space.kscience.dataforge.context.* import space.kscience.dataforge.data.* import space.kscience.dataforge.meta.* @@ -16,6 +15,7 @@ import space.kscience.dataforge.names.plus import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue +import kotlin.time.Duration.Companion.milliseconds /** @@ -62,7 +62,7 @@ internal class SimpleWorkspaceTest { data { //statically initialize data repeat(100) { - wrap("myData[$it]", it) + putValue("myData[$it]", it) } } @@ -148,18 +148,16 @@ internal class SimpleWorkspaceTest { } @Test - @Timeout(1) - fun testWorkspace() = runTest { + fun testWorkspace() = runTest(timeout = 100.milliseconds) { val node = workspace.produce("sum") val res = node.asSequence().single() assertEquals(328350, res.await()) } @Test - @Timeout(1) - fun testMetaPropagation() = runTest { + fun testMetaPropagation() = runTest(timeout = 100.milliseconds) { val node = workspace.produce("sum") { "testFlag" put true } - val res = node.single().await() + val res = node["sum"]!!.await() } @Test @@ -188,7 +186,7 @@ internal class SimpleWorkspaceTest { val node = workspace.produce("filterOne") { "name" put "myData[12]" } - assertEquals(12, node.single().await()) + assertEquals(12, node.asSequence().first().await()) } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 3734d13e..ffc318d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,9 @@ +kotlin.code.style=official + org.gradle.parallel=true org.gradle.jvmargs=-Xmx4096m -kotlin.code.style=official kotlin.mpp.stability.nowarn=true -kotlin.incremental.js.ir=true kotlin.native.ignoreDisabledTargets=true -toolsVersion=0.15.2-kotlin-1.9.21 -#kotlin.experimental.tryK2=true \ No newline at end of file +toolsVersion=0.15.4-kotlin-2.0.0 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e411586a..17655d0e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists