Merge pull request #82 from SciProgCentre/dev

0.9.0
This commit is contained in:
SPC-code 2024-06-10 12:05:54 +03:00 committed by GitHub
commit d80846d5fb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
90 changed files with 1729 additions and 1133 deletions
CHANGELOG.mdbuild.gradle.kts
dataforge-context
README.md
api
src
commonMain/kotlin/space/kscience/dataforge
jvmMain/kotlin/space/kscience/dataforge/descriptors
jvmTest/kotlin/space/kscience/dataforge/descriptors
dataforge-data
dataforge-io
README.md
dataforge-io-yaml
src
commonMain/kotlin/space/kscience/dataforge/io
jvmMain/kotlin/space/kscience/dataforge/io
dataforge-meta
dataforge-scripting
dataforge-workspace
gradle.properties
gradle/wrapper

@ -14,6 +14,41 @@
### Security ### 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 ## 0.8.0 - 2024-02-03
### Added ### Added

@ -3,20 +3,21 @@ import space.kscience.gradle.useApache2Licence
import space.kscience.gradle.useSPCTeam import space.kscience.gradle.useSPCTeam
plugins { plugins {
id("space.kscience.gradle.project") alias(spclibs.plugins.kscience.project)
alias(spclibs.plugins.kotlinx.kover)
} }
allprojects { allprojects {
group = "space.kscience" group = "space.kscience"
version = "0.8.0" version = "0.9.0"
} }
subprojects { subprojects {
apply(plugin = "maven-publish") apply(plugin = "maven-publish")
tasks.withType<KotlinCompile> { tasks.withType<KotlinCompile> {
kotlinOptions { compilerOptions {
freeCompilerArgs = freeCompilerArgs + "-Xcontext-receivers" freeCompilerArgs.add("-Xcontext-receivers")
} }
} }
} }
@ -30,7 +31,7 @@ ksciencePublish {
useApache2Licence() useApache2Licence()
useSPCTeam() useSPCTeam()
} }
repository("spc","https://maven.sciprog.center/kscience") repository("spc", "https://maven.sciprog.center/kscience")
sonatype("https://oss.sonatype.org") sonatype("https://oss.sonatype.org")
} }

@ -6,7 +6,7 @@ Context and provider definitions
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-context:0.8.0") implementation("space.kscience:dataforge-context:0.9.0-dev-1")
} }
``` ```

@ -57,6 +57,7 @@ public abstract interface class space/kscience/dataforge/context/ContextAware {
public final class space/kscience/dataforge/context/ContextBuilder { public final class space/kscience/dataforge/context/ContextBuilder {
public final fun build ()Lspace/kscience/dataforge/context/Context; 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 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 (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public final fun plugin (Lspace/kscience/dataforge/context/Plugin;)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 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 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 static final field Companion Lspace/kscience/dataforge/context/DefaultLogManager$Companion;
public fun <init> ()V 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 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 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 synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/context/PluginTag; public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/context/PluginTag;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V 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; 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 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 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 Companion Lspace/kscience/dataforge/provider/Path$Companion;
public static final field PATH_SEGMENT_SEPARATOR Ljava/lang/String; public static final field PATH_SEGMENT_SEPARATOR Ljava/lang/String;

@ -10,6 +10,7 @@ import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.provider.Provider import space.kscience.dataforge.provider.Provider
import kotlin.coroutines.CoroutineContext 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. * 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?, public val parent: Context?,
plugins: Set<Plugin>, // set of unattached plugins plugins: Set<Plugin>, // set of unattached plugins
meta: Meta, meta: Meta,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
) : Named, MetaRepr, Provider, CoroutineScope { ) : Named, MetaRepr, Provider, CoroutineScope {
/** /**
@ -65,7 +67,7 @@ public open class Context internal constructor(
override val coroutineContext: CoroutineContext by lazy { override val coroutineContext: CoroutineContext by lazy {
(parent ?: Global).coroutineContext.let { parenContext -> (parent ?: Global).coroutineContext.let { parenContext ->
parenContext + SupervisorJob(parenContext[Job]) parenContext + coroutineContext + SupervisorJob(parenContext[Job])
} }
} }

@ -13,6 +13,8 @@ import space.kscience.dataforge.names.plus
import kotlin.collections.component1 import kotlin.collections.component1
import kotlin.collections.component2 import kotlin.collections.component2
import kotlin.collections.set import kotlin.collections.set
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/** /**
* A convenience builder for context * A convenience builder for context
@ -59,8 +61,15 @@ public class ContextBuilder internal constructor(
plugin(DeFactoPluginFactory(plugin)) plugin(DeFactoPluginFactory(plugin))
} }
private var coroutineContext: CoroutineContext = EmptyCoroutineContext
public fun coroutineContext(coroutineContext: CoroutineContext) {
this.coroutineContext = coroutineContext
}
public fun build(): Context { 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>() val plugins = HashMap<PluginTag, Plugin>()
fun addPlugin(factory: PluginFactory<*>, meta: Meta) { fun addPlugin(factory: PluginFactory<*>, meta: Meta) {
@ -86,7 +95,7 @@ public class ContextBuilder internal constructor(
addPlugin(factory, meta) addPlugin(factory, meta)
} }
return Context(contextName, parent, plugins.values.toSet(), meta.seal()) return Context(contextName, parent, plugins.values.toSet(), meta.seal(), coroutineContext)
} }
} }

@ -10,7 +10,7 @@ import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
@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){ onChange(this){
trySend(converter.read(this)) trySend(converter.read(this))
} }

@ -4,18 +4,12 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.decodeFromStream
import org.slf4j.LoggerFactory 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.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder 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 java.net.URL
import kotlin.reflect.KClass import kotlin.reflect.KAnnotatedElement
import kotlin.reflect.full.isSubclassOf import kotlin.reflect.KProperty
import kotlin.reflect.full.memberProperties
import kotlin.reflect.typeOf
/** /**
* Description text for meta property, node or whole object * Description text for meta property, node or whole object
@ -58,19 +52,9 @@ private fun MetaDescriptorBuilder.loadDescriptorFromResource(resource: Descripto
} }
} }
@DFExperimental
public fun <T : Any> MetaDescriptor.Companion.forClass( public fun MetaDescriptorBuilder.forAnnotatedElement(element: KAnnotatedElement) {
kClass: KClass<T>, element.annotations.forEach {
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 {
when (it) { when (it) {
is Description -> description = it.value is Description -> description = it.value
@ -79,46 +63,70 @@ public fun <T : Any> MetaDescriptor.Companion.forClass(
is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url)) 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") @DFExperimental
public inline fun <reified T : Scheme> SchemeSpec<T>.autoDescriptor( noinline mod: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptor = public fun MetaDescriptorBuilder.forProperty(property: KProperty<*>) {
MetaDescriptor.forClass(typeOf<T>().classifier as KClass<T>, mod) 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)

@ -1,31 +1,29 @@
@file:OptIn(DFExperimental::class)
package space.kscience.dataforge.descriptors package space.kscience.dataforge.descriptors
import kotlinx.serialization.encodeToString import space.kscience.dataforge.misc.DFExperimental
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
private class TestScheme: Scheme(){ //
//class TestScheme : Scheme() {
@Description("A") //
val a by string() // @Description("A")
// val a by string()
@Description("B") //
val b by int() // @Description("B")
// val b by int()
companion object: SchemeSpec<TestScheme>(::TestScheme){ //
override val descriptor: MetaDescriptor = autoDescriptor() // val c by int()
} //
} // companion object : SchemeSpec<TestScheme>(::TestScheme) {
// override val descriptor: MetaDescriptor = autoDescriptor()
class TestAutoDescriptors { // }
@Test //}
fun autoDescriptor(){ //
val autoDescriptor = MetaDescriptor.forClass(TestScheme::class) //class TestAutoDescriptors {
println(Json{prettyPrint = true}.encodeToString(autoDescriptor)) // @Test
} // fun autoDescriptor() {
} // val autoDescriptor = MetaDescriptor.forScheme(TestScheme)
// println(Json { prettyPrint = true }.encodeToString(autoDescriptor))
// }
//}

@ -6,7 +6,7 @@
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-data:0.8.0") implementation("space.kscience:dataforge-data:0.9.0-dev-1")
} }
``` ```

@ -1,11 +1,14 @@
package space.kscience.dataforge.actions 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.flow.onEach
import kotlinx.coroutines.launch import space.kscience.dataforge.data.DataSink
import space.kscience.dataforge.data.* 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.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.Name
import space.kscience.dataforge.names.startsWith import space.kscience.dataforge.names.startsWith
import kotlin.reflect.KType 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 * 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, public val outputType: KType,
) : Action<T, R> { ) : Action<T, R> {
@ -29,7 +32,7 @@ public abstract class AbstractAction<T : Any, R : Any>(
* Generate initial content of the output * Generate initial content of the output
*/ */
protected abstract fun DataSink<R>.generate( protected abstract fun DataSink<R>.generate(
data: DataTree<T>, source: DataTree<T>,
meta: Meta, meta: Meta,
) )
@ -37,36 +40,31 @@ public abstract class AbstractAction<T : Any, R : Any>(
* Update part of the data set using provided data * 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 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>, source: DataTree<T>,
meta: Meta, meta: Meta,
namedData: NamedData<T>, updatedData: DataUpdate<T>,
){ ) {
//by default regenerate the whole data set //by default regenerate the whole data set
generate(source,meta) generate(source, meta)
} }
@OptIn(DFInternal::class) @OptIn(UnsafeKType::class)
override fun execute( override fun execute(
dataSet: DataTree<T>, source: DataTree<T>,
meta: Meta, meta: Meta,
): DataTree<R> = if(dataSet.isObservable()) { updatesScope: CoroutineScope
MutableDataTree<R>(outputType, dataSet.updatesScope).apply { ): DataTree<R> = DataTree(outputType) {
generate(dataSet, meta) generate(source, meta)
dataSet.updates().onEach { //propagate updates
update(dataSet, meta, it) launchUpdate(updatesScope) {
}.launchIn(updatesScope) source.updates.onEach { update ->
update(source, meta, update)
//close updates when the source is closed }.collect()
updatesScope.launch {
dataSet.awaitClose()
close()
}
}
} else{
DataTree(outputType){
generate(dataSet, meta)
} }
} }
} }

@ -1,5 +1,8 @@
package space.kscience.dataforge.actions 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.data.DataTree
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental 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 * 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. * 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 public companion object
} }
@ -21,23 +24,27 @@ public fun interface Action<T, R> {
/** /**
* A convenience method to transform data using given [action] * A convenience method to transform data using given [action]
*/ */
@OptIn(DelicateCoroutinesApi::class)
public fun <T, R> DataTree<T>.transform( public fun <T, R> DataTree<T>.transform(
action: Action<T, R>, action: Action<T, R>,
meta: Meta = Meta.EMPTY, 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 * 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 -> 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), meta) action.execute(this@then.execute(dataSet, meta, scope), meta, scope)
} }
@DFExperimental @DFExperimental
@OptIn(DelicateCoroutinesApi::class)
public operator fun <T, R> Action<T, R>.invoke( public operator fun <T, R> Action<T, R>.invoke(
dataSet: DataTree<T>, dataSet: DataTree<T>,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
): DataTree<R> = execute(dataSet, meta) updateScope: CoroutineScope = GlobalScope,
): DataTree<R> = execute(dataSet, meta, updateScope)

@ -6,8 +6,7 @@ import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.seal import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.meta.toMutableMeta import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf 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) public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(T) -> R1): Unit = result(typeOf<R1>(), f)
} }
@PublishedApi @UnsafeKType
internal class MapAction<T : Any, R : Any>( public class MapAction<T, R>(
outputType: KType, outputType: KType,
private val block: MapActionBuilder<T, R>.() -> Unit, private val block: MapActionBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) { ) : 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 // Creating a new environment for action using **old** name, old meta and task meta
val env = ActionEnv(name, data.meta, meta) val env = ActionEnv(name, data.meta, meta)
@ -74,7 +78,6 @@ internal class MapAction<T : Any, R : Any>(
//getting new meta //getting new meta
val newMeta = builder.meta.seal() val newMeta = builder.meta.seal()
@OptIn(DFInternal::class)
val newData = Data(builder.outputType, newMeta, dependencies = listOf(data)) { val newData = Data(builder.outputType, newMeta, dependencies = listOf(data)) {
builder.result(env, data.await()) builder.result(env, data.await())
} }
@ -82,12 +85,18 @@ internal class MapAction<T : Any, R : Any>(
put(newName, newData) put(newName, newData)
} }
override fun DataSink<R>.generate(data: DataTree<T>, meta: Meta) { override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
data.forEach { mapOne(it.name, it.data, 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 * 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, noinline builder: MapActionBuilder<T, R>.() -> Unit,
): Action<T, R> = MapAction(typeOf<R>(), builder) ): Action<T, R> = MapAction(typeOf<R>(), builder)

@ -4,15 +4,14 @@ import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
public class JoinGroup<T : Any, R : Any>( public class JoinGroup<T, R>(
public var name: String, public var name: String,
internal val set: DataTree<T>, internal val set: DataTree<T>,
@PublishedApi internal var outputType: KType, @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 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.outputType = outputType
this.result = f; 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>() outputType = typeOf<R1>()
this.result = f; this.result = f;
} }
@ -35,7 +34,7 @@ public class JoinGroup<T : Any, R : Any>(
} }
@DFBuilder @DFBuilder
public class ReduceGroupBuilder<T : Any, R : Any>( public class ReduceGroupBuilder<T, R>(
public val actionMeta: Meta, public val actionMeta: Meta,
private val outputType: KType, private val outputType: KType,
) { ) {
@ -67,7 +66,7 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
/** /**
* Apply transformation to the whole node * 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 -> groupRules += { node ->
listOf(JoinGroup<T, R>(resultName, node, outputType).apply { result(outputType, f) }) listOf(JoinGroup<T, R>(resultName, node, outputType).apply { result(outputType, f) })
} }
@ -79,14 +78,14 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
} }
@PublishedApi @PublishedApi
internal class ReduceAction<T : Any, R : Any>( internal class ReduceAction<T, R>(
outputType: KType, outputType: KType,
private val action: ReduceGroupBuilder<T, R>.() -> Unit, private val action: ReduceGroupBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) { ) : AbstractAction<T, R>(outputType) {
//TODO optimize reduction. Currently, the whole action recalculates on push //TODO optimize reduction. Currently, the whole action recalculates on push
override fun DataSink<R>.generate(data: DataTree<T>, meta: Meta) { override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(data).forEach { group -> ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(source).forEach { group ->
val dataFlow: Map<Name, Data<T>> = group.set.asSequence().fold(HashMap()) { acc, value -> val dataFlow: Map<Name, Data<T>> = group.set.asSequence().fold(HashMap()) { acc, value ->
acc.apply { acc.apply {
acc[value.name] = value.data acc[value.name] = value.data
@ -98,7 +97,7 @@ internal class ReduceAction<T : Any, R : Any>(
val groupMeta = group.meta val groupMeta = group.meta
val env = ActionEnv(groupName.parseAsName(), groupMeta, 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, group.outputType,
meta = groupMeta meta = groupMeta
) { group.result.invoke(env, it) } ) { group.result.invoke(env, it) }
@ -111,7 +110,6 @@ internal class ReduceAction<T : Any, R : Any>(
/** /**
* A one-to-one mapping action * A one-to-one mapping action
*/ */
@DFExperimental public inline fun <reified T, reified R> Action.Companion.reducing(
public inline fun <reified T : Any, reified R : Any> Action.Companion.reducing(
noinline builder: ReduceGroupBuilder<T, R>.() -> Unit, noinline builder: ReduceGroupBuilder<T, R>.() -> Unit,
): Action<T, R> = ReduceAction(typeOf<R>(), builder) ): Action<T, R> = ReduceAction(typeOf<R>(), builder)

@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.Laminate
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.toMutableMeta import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName import space.kscience.dataforge.names.parseAsName
import kotlin.collections.set import kotlin.collections.set
@ -13,9 +12,9 @@ import kotlin.reflect.KType
import kotlin.reflect.typeOf 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 val name: Name,
public var meta: MutableMeta, public var meta: MutableMeta,
@PublishedApi internal var outputType: KType, @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 * Action that splits each incoming element into a number of fragments defined in builder
*/ */
@PublishedApi @PublishedApi
internal class SplitAction<T : Any, R : Any>( internal class SplitAction<T, R>(
outputType: KType, outputType: KType,
private val action: SplitBuilder<T, R>.() -> Unit, private val action: SplitBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) { ) : AbstractAction<T, R>(outputType) {
private fun DataSink<R>.splitOne(name: Name, data: Data<T>, meta: Meta) { private fun DataSink<R>.splitOne(name: Name, data: Data<T>?, meta: Meta) {
val laminate = Laminate(data.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 // apply individual fragment rules to result
@ -64,28 +63,36 @@ internal class SplitAction<T : Any, R : Any>(
).apply(rule) ).apply(rule)
//data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName) //data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
put( if (data == null) {
fragmentName, put(fragmentName, null)
@Suppress("OPT_IN_USAGE") Data(outputType, meta = env.meta, dependencies = listOf(data)) { } else {
env.result(data.await()) 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) { override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
data.forEach { splitOne(it.name, it.data, meta) } source.forEach { splitOne(it.name, it.data, meta) }
} }
override fun DataSink<R>.update(source: DataTree<T>, meta: Meta, namedData: NamedData<T>) { override suspend fun DataSink<R>.update(
splitOne(namedData.name, namedData.data, namedData.meta) 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 * 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, noinline builder: SplitBuilder<T, R>.() -> Unit,
): Action<T, R> = SplitAction(typeOf<R>(), builder) ): Action<T, R> = SplitAction(typeOf<R>(), builder)

@ -4,8 +4,8 @@ import kotlinx.coroutines.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.DfType import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.misc.UnsafeKType
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType import kotlin.reflect.KType
@ -41,7 +41,7 @@ public interface Data<out T> : Goal<T>, MetaRepr {
*/ */
internal val TYPE_OF_NOTHING: KType = typeOf<Unit>() internal val TYPE_OF_NOTHING: KType = typeOf<Unit>()
public inline fun <reified T> static( public inline fun <reified T> wrapValue(
value: T, value: T,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
): Data<T> = StaticData(typeOf<T>(), value, meta) ): 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 * An empty data containing only meta
*/ */
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> { public fun buildEmpty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
override val type: KType = TYPE_OF_NOTHING override val type: KType get() = TYPE_OF_NOTHING
override val meta: Meta = meta override val meta: Meta = meta
override val dependencies: Collection<Goal<*>> = emptyList() override val dependencies: Collection<Goal<*>> get() = emptyList()
override val deferred: Deferred<Nothing> override val deferred: Deferred<Nothing>
get() = GlobalScope.async(start = CoroutineStart.LAZY) { get() = GlobalScope.async(start = CoroutineStart.LAZY) {
error("The Data is empty and could not be computed") 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 async(coroutineScope: CoroutineScope): Deferred<Nothing> = deferred
override fun reset() {} 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> = public inline fun <reified T> Data(value: T, meta: Meta = Meta.EMPTY): StaticData<T> =
StaticData(typeOf<T>(), value, meta) StaticData(typeOf<T>(), value, meta)
@DFInternal @UnsafeKType
public fun <T> Data( public fun <T> Data(
type: KType, type: KType,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
@ -96,7 +98,7 @@ public fun <T> Data(
block: suspend () -> T, block: suspend () -> T,
): Data<T> = LazyData(type, meta, context, dependencies, block) ): Data<T> = LazyData(type, meta, context, dependencies, block)
@OptIn(DFInternal::class) @OptIn(UnsafeKType::class)
public inline fun <reified T> Data( public inline fun <reified T> Data(
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext, context: CoroutineContext = EmptyCoroutineContext,

@ -1,28 +1,30 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus
import kotlin.reflect.KType import kotlin.reflect.KType
public fun interface DataFilter { 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 companion object {
public val EMPTY: DataFilter = DataFilter { _, _, _ -> true } 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) 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) predicate.accepts(data)
} }
@ -41,7 +43,8 @@ public fun <T> DataSource<T>.filterData(
public fun <T> ObservableDataSource<T>.filterData( public fun <T> ObservableDataSource<T>.filterData(
predicate: DataFilter, predicate: DataFilter,
): ObservableDataSource<T> = object : ObservableDataSource<T> { ): 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 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) } this@filterData.read(name)?.takeIf { predicate.accepts(name, it.meta, it.type) }
} }
public fun <T> GenericDataTree<T, *>.filterData( internal class FilteredDataTree<T>(
predicate: DataFilter, val source: DataTree<T>,
): DataTree<T> = asSequence().filterData(predicate).toTree(dataType) val filter: DataFilter,
val branch: Name,
override val dataType: KType = source.dataType,
) : DataTree<T> {
public fun <T> GenericObservableDataTree<T, *>.filterData( override val data: Data<T>?
scope: CoroutineScope, 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, predicate: DataFilter,
): ObservableDataTree<T> = asSequence().filterData(predicate).toObservableTree(dataType, scope, updates().filterData(predicate)) ): DataTree<T> = FilteredDataTree(this, predicate, Name.EMPTY)
///** ///**

@ -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() }

@ -1,9 +1,8 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import kotlinx.coroutines.* import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.emptyFlow
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.reflect.KType import kotlin.reflect.KType
@ -33,46 +32,42 @@ public interface ObservableDataSource<out T> : DataSource<T> {
/** /**
* Flow updates made to the data * 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 * A tree like structure for data holding
*/ */
public interface GenericDataTree<out T, out TR : GenericDataTree<T, TR>> : DataSource<T> { public interface DataTree<out T> : ObservableDataSource<T> {
public val self: TR
public val data: Data<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) { override fun read(name: Name): Data<T>? = when (name.length) {
0 -> data 0 -> data
else -> items[name.first()]?.read(name.cutFirst()) else -> items[name.first()]?.read(name.cutFirst())
} }
/**
* Flow updates made to the data
*/
override val updates: Flow<DataUpdate<T>>
public companion object { public companion object {
private object EmptyDataTree : GenericDataTree<Nothing, EmptyDataTree> { private object EmptyDataTree :
override val self: EmptyDataTree get() = this DataTree<Nothing> {
override val data: Data<Nothing>? = null override val data: Data<Nothing>? = null
override val items: Map<NameToken, EmptyDataTree> = emptyMap() override val items: Map<NameToken, EmptyDataTree> = emptyMap()
override val dataType: KType = typeOf<Unit>() override val dataType: KType = typeOf<Unit>()
override fun read(name: Name): Data<Nothing>? = null 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 * 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 public val DataTree<*>.meta: Meta? get() = data?.meta
/** /**
* Provide subtree if it exists * 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) { when (name.length) {
0 -> self 0 -> this
1 -> items[name.first()] 1 -> items[name.first()]
else -> items[name.first()]?.branch(name.cutFirst()) 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()) branch(name.parseAsName())
public fun GenericDataTree<*, *>.isEmpty(): Boolean = data == null && items.isEmpty() public fun DataTree<*>.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, *>>
/** /**
* Check if the [DataTree] is observable * Check if the [DataTree] is observable
*/ */
public fun <T> DataTree<T>.isObservable(): Boolean { public fun <T> DataSource<T>.isObservable(): Boolean {
contract { 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)
}

@ -17,10 +17,10 @@ package space.kscience.dataforge.data
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.UnsafeKType
public interface GroupRule { 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 { public companion object {
/** /**
@ -31,24 +31,24 @@ public interface GroupRule {
* @param defaultTagValue * @param defaultTagValue
* @return * @return
*/ */
@OptIn(DFInternal::class) @OptIn(UnsafeKType::class)
public fun byMetaValue( public fun byMetaValue(
key: String, key: String,
defaultTagValue: String, defaultTagValue: String,
): GroupRule = object : GroupRule { ): GroupRule = object : GroupRule {
override fun <T : Any> gather( override fun <T> gather(
set: DataTree<T>, set: DataTree<T>,
): Map<String, DataTree<T>> { ): Map<String, DataTree<T>> {
val map = HashMap<String, DataTreeBuilder<T>>() val map = HashMap<String, MutableDataTree<T>>()
set.forEach { data -> set.forEach { data ->
val tagValue: String = data.meta[key]?.string ?: defaultTagValue 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
} }
} }
} }

@ -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 * Create a new [Data] with the same computation, but different meta. The meta is created by applying [block] to
* the existing data meta. * the existing data meta.
*/ */
public inline fun <T> Data<T>.mapMeta(block: MutableMeta.() -> Unit): Data<T> = withMeta(meta.copy(block)) public inline fun <T> Data<T>.withMeta(block: MutableMeta.() -> Unit): Data<T> = withMeta(meta.copy(block))

@ -3,14 +3,34 @@ package space.kscience.dataforge.data
import space.kscience.dataforge.meta.isEmpty import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.misc.Named import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import kotlin.reflect.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 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 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>( private class NamedDataImpl<T>(
override val name: Name, 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) NamedDataImpl(name, this.data)
} else { } else {
NamedDataImpl(name, this) NamedDataImpl(name, this)
} }
public fun <T> NamedData(name: Name, data: Data<T>): NamedData<T> = data.named(name)

@ -1,62 +1,64 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.names.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.plus
public fun <T> DataSink<T>.put(value: NamedData<T>) { public fun <T> DataSink<T>.put(value: NamedData<T>) {
put(value.name, value.data) put(value.name, value.data)
} }
public fun <T> DataSink<T>.branch(dataTree: DataTree<T>) { public inline fun <T> DataSink<T>.putAll(
putAll(dataTree.asSequence())
}
public inline fun <T> DataSink<T>.branch(
prefix: Name, prefix: Name,
block: DataSink<T>.() -> Unit, block: DataSink<T>.() -> Unit,
) { ) {
if (prefix.isEmpty()) { if (prefix.isEmpty()) {
apply(block) apply(block)
} else { } else {
val proxyDataSink = DataSink { nameWithoutPrefix, data -> val proxyDataSink = object :DataSink<T>{
this.put(prefix + nameWithoutPrefix, data) 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) proxyDataSink.apply(block)
} }
} }
public inline fun <T> DataSink<T>.branch(
public inline fun <T> DataSink<T>.putAll(
prefix: String, prefix: String,
block: DataSink<T>.() -> Unit, 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>) { public fun <T> DataSink<T>.put(name: String, value: Data<T>) {
put(Name.parse(name), value) put(Name.parse(name), value)
} }
public fun <T> DataSink<T>.branch(name: Name, set: DataTree<T>) { public fun <T> DataSink<T>.putAll(name: Name, tree: DataTree<T>) {
branch(name) { putAll(set.asSequence()) } 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] * 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, name: String,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T, noinline producer: suspend () -> T,
@ -65,7 +67,7 @@ public inline fun <reified T> DataSink<T>.put(
put(name, data) put(name, data)
} }
public inline fun <reified T> DataSink<T>.put( public inline fun <reified T> DataSink<T>.putValue(
name: Name, name: Name,
meta: Meta = Meta.EMPTY, meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T, noinline producer: suspend () -> T,
@ -77,24 +79,35 @@ public inline fun <reified T> DataSink<T>.put(
/** /**
* Emit static data with the fixed value * Emit static data with the fixed value
*/ */
public inline fun <reified T> DataSink<T>.wrap( public inline fun <reified T> DataSink<T>.putValue(
name: String,
data: T,
meta: Meta = Meta.EMPTY,
): Unit = put(name, Data.static(data, meta))
public inline fun <reified T> DataSink<T>.wrap(
name: Name, name: Name,
data: T, value: T,
meta: Meta = Meta.EMPTY, 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, name: String,
data: T, value: T,
mutableMeta: MutableMeta.() -> Unit, meta: Meta = Meta.EMPTY,
): Unit = put(Name.parse(name), Data.static(data, Meta(mutableMeta))) ): 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>>) { public fun <T> DataSink<T>.putAll(sequence: Sequence<NamedData<T>>) {
sequence.forEach { 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>) { public fun <T> DataSink<T>.putAll(tree: DataTree<T>) {
this.putAll(tree.asSequence()) 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)
}
} }
/** /**
* Copy given data set and mirror its changes to this [DataSink] in [this@setAndObserve]. Returns an update [Job] * 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( public fun <T : Any> DataSink<T>.putAllAndWatch(
name: Name, scope: CoroutineScope,
dataSet: ObservableDataTree<T>, branchName: Name = Name.EMPTY,
source: DataTree<T>,
): Job { ): Job {
branch(name, dataSet) putAll(branchName, source)
return dataSet.updates().onEach { return source.updates.onEach {
put(name + it.name, it.data) update(branchName + it.name, it.data)
}.launchIn(dataSet.updatesScope) }.launchIn(scope)
} }

@ -1,7 +1,7 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import space.kscience.dataforge.meta.* 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.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import kotlin.coroutines.CoroutineContext 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> = public suspend fun <T> NamedData<T>.awaitWithMeta(): NamedValueWithMeta<T> =
NamedValueWithMeta(name, await(), meta) 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). * 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( public fun <K, T, R> Map<K, Data<T>>.reduceToData(
outputType: KType, outputType: KType,
meta: Meta = joinMeta(), meta: Meta = joinMeta(),
@ -103,7 +121,7 @@ public inline fun <K, T, reified R> Map<K, Data<T>>.reduceToData(
//Iterable operations //Iterable operations
@DFInternal @UnsafeKType
public inline fun <T, R> Iterable<Data<T>>.reduceToData( public inline fun <T, R> Iterable<Data<T>>.reduceToData(
outputType: KType, outputType: KType,
meta: Meta = joinMeta(), meta: Meta = joinMeta(),
@ -118,7 +136,7 @@ public inline fun <T, R> Iterable<Data<T>>.reduceToData(
transformation(map { it.awaitWithMeta() }) transformation(map { it.awaitWithMeta() })
} }
@OptIn(DFInternal::class) @OptIn(UnsafeKType::class)
public inline fun <T, reified R> Iterable<Data<T>>.reduceToData( public inline fun <T, reified R> Iterable<Data<T>>.reduceToData(
meta: Meta = joinMeta(), meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext, 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]. * Transform an [Iterable] of [NamedData] to a single [Data].
*/ */
@DFInternal @UnsafeKType
public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData( public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData(
outputType: KType, outputType: KType,
meta: Meta = joinMeta(), meta: Meta = joinMeta(),
@ -156,7 +174,7 @@ public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData(
transformation(map { it.awaitWithMeta() }) transformation(map { it.awaitWithMeta() })
} }
@OptIn(DFInternal::class) @OptIn(UnsafeKType::class)
public inline fun <T, reified R> Iterable<NamedData<T>>.reduceNamedToData( public inline fun <T, reified R> Iterable<NamedData<T>>.reduceNamedToData(
meta: Meta = joinMeta(), meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,
@ -181,7 +199,8 @@ public inline fun <T, reified R> Iterable<NamedData<T>>.foldNamedToData(
//DataSet operations //DataSet operations
@DFInternal
@UnsafeKType
public suspend fun <T, R> DataTree<T>.transform( public suspend fun <T, R> DataTree<T>.transform(
outputType: KType, outputType: KType,
metaTransform: MutableMeta.() -> Unit = {}, 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( public suspend inline fun <T, reified R> DataTree<T>.transform(
noinline metaTransform: MutableMeta.() -> Unit = {}, noinline metaTransform: MutableMeta.() -> Unit = {},
coroutineContext: CoroutineContext = EmptyCoroutineContext, coroutineContext: CoroutineContext = EmptyCoroutineContext,

@ -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>())

@ -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()
}
}

@ -1,6 +1,5 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.DFInternal
@ -25,32 +24,40 @@ private fun <R> Data<*>.castOrNull(type: KType): Data<R>? =
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@DFInternal @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>> filter { it.type.isSubtypeOf(type) } as Sequence<NamedData<R>>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@DFInternal @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>> filter { it.type.isSubtypeOf(type) } as Flow<NamedData<R>>
/** /**
* Select all data matching given type and filters. Does not modify paths * 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 @DFInternal
public fun <R> DataTree<*>.filterByType( public fun <R> DataTree<*>.filterByType(
type: KType, type: KType,
predicate: DataFilter = DataFilter.EMPTY, branch: Name = Name.EMPTY,
): DataTree<R> = asSequence().filterByDataType<R>(type).filterData(predicate).toTree(type) 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 * Select a single datum of the appropriate type
*/ */
@OptIn(DFInternal::class) @OptIn(DFInternal::class)
public inline fun <reified R : Any> DataTree<*>.filterByType( public inline fun <reified R : Any> DataTree<*>.filterByType(
predicate: DataFilter = DataFilter.EMPTY, branch: Name = Name.EMPTY,
): DataTree<R> = filterByType(typeOf<R>(), predicate) filter: DataFilter = DataFilter.EMPTY,
): DataTree<R> = filterByType(typeOf<R>(), branch, filter = filter)
/** /**
* Select a single datum if it is present and of given [type] * 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>? = public inline fun <reified R : Any> DataTree<*>.getByType(name: String): NamedData<R>? =
this@getByType.getByType(typeOf<R>(), Name.parse(name)) 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)

@ -14,14 +14,14 @@ public infix fun <T : Any> String.put(data: Data<T>): Unit =
* Append node * Append node
*/ */
context(DataSink<T>) context(DataSink<T>)
public infix fun <T : Any> String.put(dataSet: DataTree<T>): Unit = public infix fun <T : Any> String.putAll(dataSet: DataTree<T>): Unit =
branch(this, dataSet) putAll(this, dataSet)
/** /**
* Build and append node * Build and append node
*/ */
context(DataSink<T>) context(DataSink<T>)
public infix fun <T : Any> String.put( public infix fun <T : Any> String.putAll(
block: DataSink<T>.() -> Unit, block: DataSink<T>.() -> Unit,
): Unit = branch(Name.parse(this), block) ): Unit = putAll(Name.parse(this), block)

@ -1,22 +1,24 @@
package space.kscience.dataforge.data package space.kscience.dataforge.data
import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.actions.invoke import space.kscience.dataforge.actions.invoke
import space.kscience.dataforge.actions.mapping import space.kscience.dataforge.actions.mapping
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.time.Duration.Companion.milliseconds
@OptIn(DFExperimental::class) @OptIn(DFExperimental::class)
internal class ActionsTest { internal class ActionsTest {
@Test @Test
fun testStaticMapAction() = runTest { fun testStaticMapAction() = runTest(timeout = 500.milliseconds) {
val data: DataTree<Int> = DataTree { val data: DataTree<Int> = DataTree {
repeat(10) { repeat(10) {
wrap(it.toString(), it) putValue(it.toString(), it)
} }
} }
@ -28,7 +30,7 @@ internal class ActionsTest {
} }
@Test @Test
fun testDynamicMapAction() = runBlocking { fun testDynamicMapAction() = runTest(timeout = 500.milliseconds) {
val source: MutableDataTree<Int> = MutableDataTree() val source: MutableDataTree<Int> = MutableDataTree()
val plusOne = Action.mapping<Int, Int> { val plusOne = Action.mapping<Int, Int> {
@ -39,13 +41,10 @@ internal class ActionsTest {
repeat(10) { repeat(10) {
source.wrap(it.toString(), it) source.updateValue(it.toString(), it)
} }
delay(10) result.updates.take(10).onEach { println(it.name) }.collect()
source.close()
result.awaitClose()
assertEquals(2, result["1"]?.await()) assertEquals(2, result["1"]?.await())
} }

@ -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())
}
}

@ -6,7 +6,7 @@ IO module
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-io:0.8.0") implementation("space.kscience:dataforge-io:0.9.0-dev-1")
} }
``` ```

@ -6,7 +6,7 @@ YAML meta IO
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-io-yaml:0.8.0") implementation("space.kscience:dataforge-io-yaml:0.9.0-dev-1")
} }
``` ```

@ -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.io.PartDescriptor.Companion.SEPARATOR_KEY
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.getIndexedList
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
private class PartDescriptor : Scheme() { private class PartDescriptor : Scheme() {
@ -84,7 +85,7 @@ public fun EnvelopeBuilder.envelopes(
public fun Envelope.parts(): EnvelopeParts { public fun Envelope.parts(): EnvelopeParts {
if (data == null) return emptyList() if (data == null) return emptyList()
//TODO add zip folder reader //TODO add zip folder reader
val parts = meta.getIndexed(PARTS_KEY).values.map { val parts = meta.getIndexedList(PARTS_KEY).map {
PartDescriptor.read(it) PartDescriptor.read(it)
} }
return if (parts.isEmpty()) { return if (parts.isEmpty()) {

@ -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.io.MetaFormatFactory.Companion.META_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.string 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 space.kscience.dataforge.names.Name
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -19,11 +19,11 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@DFInternal @UnsafeKType
public fun <T> resolveIOFormat(type: KType, meta: Meta): IOFormat<T>? = public fun <T> resolveIOFormat(type: KType, meta: Meta): IOFormat<T>? =
ioFormatFactories.singleOrNull { it.type == type }?.build(context, meta) as? 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>? = public inline fun <reified T> resolveIOFormat(meta: Meta = Meta.EMPTY): IOFormat<T>? =
resolveIOFormat(typeOf<T>(), meta) resolveIOFormat(typeOf<T>(), meta)

@ -5,7 +5,6 @@ import kotlinx.io.bytestring.ByteString
import kotlinx.io.bytestring.decodeToString import kotlinx.io.bytestring.decodeToString
import kotlinx.io.bytestring.encodeToByteString import kotlinx.io.bytestring.encodeToByteString
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import kotlin.math.min import kotlin.math.min
/** /**
@ -52,7 +51,6 @@ public fun IOPlugin.peekBinaryEnvelopeFormat(binary: Binary): EnvelopeFormat? {
/** /**
* A zero-copy read from * A zero-copy read from
*/ */
@DFExperimental
public fun IOPlugin.readEnvelope( public fun IOPlugin.readEnvelope(
binary: Binary, binary: Binary,
readNonEnvelopes: Boolean = false, readNonEnvelopes: Boolean = false,
@ -62,7 +60,6 @@ public fun IOPlugin.readEnvelope(
Envelope(Meta.EMPTY, binary) Envelope(Meta.EMPTY, binary)
} else error("Can't infer format for $binary") } else error("Can't infer format for $binary")
@DFExperimental
public fun IOPlugin.readEnvelope( public fun IOPlugin.readEnvelope(
string: String, string: String,
readNonEnvelopes: Boolean = false, readNonEnvelopes: Boolean = false,

@ -77,14 +77,12 @@ public fun Path.rewrite(block: Sink.() -> Unit): Unit {
stream.asSink().buffered().use(block) stream.asSink().buffered().use(block)
} }
@DFExperimental
public fun EnvelopeFormat.readFile(path: Path): Envelope = readFrom(path.asBinary()) public fun EnvelopeFormat.readFile(path: Path): Envelope = readFrom(path.asBinary())
/** /**
* Resolve IOFormat based on type * Resolve IOFormat based on type
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@DFExperimental
public inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? = public inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? =
ioFormatFactories.find { it.type.isSupertypeOf(typeOf<T>()) } as 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. * Return null otherwise.
*/ */
@DFExperimental
public fun IOPlugin.readEnvelopeFile( public fun IOPlugin.readEnvelopeFile(
path: Path, path: Path,
readNonEnvelopes: Boolean = false, readNonEnvelopes: Boolean = false,

@ -6,7 +6,7 @@ Meta definition and basic operations on meta
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-meta:0.8.0") implementation("space.kscience:dataforge-meta:0.9.0-dev-1")
} }
``` ```

@ -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 interface class space/kscience/dataforge/meta/Configurable {
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta; 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 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 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; 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 synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMeta;
public fun getItems ()Ljava/util/Map; public fun getItems ()Ljava/util/Map;
public final fun getLayers ()Ljava/util/List; 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 getValue ()Lspace/kscience/dataforge/meta/Value;
public fun hashCode ()I public fun hashCode ()I
public final fun merge ()Lspace/kscience/dataforge/meta/SealedMeta; 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 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 static final field Companion Lspace/kscience/dataforge/meta/MetaConverter$Companion;
public abstract fun convert (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta; public abstract fun convert (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; 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 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 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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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;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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)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;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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;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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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/MetaSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty; 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/MetaSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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/MetaSpec;)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;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/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/MetaSpec;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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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;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;)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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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 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/MetaSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)Lkotlin/properties/ReadOnlyProperty; 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;)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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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;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;)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;)Lspace/kscience/dataforge/meta/MetaDelegate;
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;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;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty; 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;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; 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;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; 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 { 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 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 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 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 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 getString (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/String;
public static final fun getStringList (Lspace/kscience/dataforge/meta/Meta;)Ljava/util/List; 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 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 interface class space/kscience/dataforge/meta/MetaRepr {
public abstract fun toMeta ()Lspace/kscience/dataforge/meta/Meta; 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 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 final class space/kscience/dataforge/meta/MetaTransformation {
public static final field Companion Lspace/kscience/dataforge/meta/MetaTransformation$Companion; 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; 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/MetaRepr;)V
public fun put (Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)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;Z)V
public fun put (Ljava/lang/String;[B)V
public fun put (Ljava/lang/String;[D)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/Enum;)V
public fun put (Lspace/kscience/dataforge/names/Name;Ljava/lang/Number;)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 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 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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;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;)Lkotlin/properties/ReadWriteProperty; 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;)Lkotlin/properties/ReadWriteProperty; 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;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;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;)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;)Lkotlin/properties/ReadWriteProperty; 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;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;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;)Lkotlin/properties/ReadWriteProperty; 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;)Lkotlin/properties/ReadWriteProperty; 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;)Lkotlin/properties/ReadWriteProperty; 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 doubleArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)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;)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;)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;)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;)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;)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;)Lkotlin/properties/ReadWriteProperty; public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;)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;)Lkotlin/properties/ReadWriteProperty; public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/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;Lspace/kscience/dataforge/meta/MetaConverter;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)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;)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;)Lkotlin/properties/ReadWriteProperty; 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 synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; 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 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;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)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;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; 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 number$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 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 numberList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; 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 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;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)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;)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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty; public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)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;)Lkotlin/properties/ReadWriteProperty; 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 final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;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;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;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/jvm/functions/Function1;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)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;)Lkotlin/properties/ReadWriteProperty; 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 final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty; 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 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;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
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 final class space/kscience/dataforge/meta/MutableMetaKt { public final class space/kscience/dataforge/meta/MutableMetaKt {
public static final fun ObservableMutableMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta; 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 (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 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/Meta;)V
public static final fun append (Lspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)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 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;Ljava/lang/String;)V
public static final fun remove (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)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;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;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 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 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 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 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 { 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 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> ()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 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 fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMeta;
public final fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; 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 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 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 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/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 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; 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 <init> (Lspace/kscience/dataforge/meta/Value;Ljava/util/Map;)V
public fun equals (Ljava/lang/Object;)Z public fun equals (Ljava/lang/Object;)Z
public fun getItems ()Ljava/util/Map; 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 getValue ()Lspace/kscience/dataforge/meta/Value;
public fun hashCode ()I public fun hashCode ()I
public fun toString ()Ljava/lang/String; 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 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 synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/SealedMeta; public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/SealedMeta;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V 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; 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 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 fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/TypedMeta;
public abstract fun getItems ()Ljava/util/Map; public abstract fun getItems ()Ljava/util/Map;
public abstract fun getSelf ()Lspace/kscience/dataforge/meta/TypedMeta;
public fun toMeta ()Lspace/kscience/dataforge/meta/Meta; 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 final class space/kscience/dataforge/meta/ValueExtensionsKt {
public static final fun getBoolean (Lspace/kscience/dataforge/meta/Value;)Z 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 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 getFloat (Lspace/kscience/dataforge/meta/Value;)F
public static final fun getInt (Lspace/kscience/dataforge/meta/Value;)I public static final fun getInt (Lspace/kscience/dataforge/meta/Value;)I
public static final fun getLong (Lspace/kscience/dataforge/meta/Value;)J 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/Number;)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue (Ljava/lang/String;)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 (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 ([F)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([I)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; 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 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 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 synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor; public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V 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; 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 getDefault ()Lspace/kscience/dataforge/meta/Value;
public final fun getDescription ()Ljava/lang/String; public final fun getDescription ()Ljava/lang/String;
public final fun getIndexKey ()Ljava/lang/String; public final fun getIndexKey ()Ljava/lang/String;
public final fun getInfo ()Ljava/lang/String;
public final fun getMultiple ()Z public final fun getMultiple ()Z
public final fun getValueRestriction ()Lspace/kscience/dataforge/meta/descriptors/ValueRestriction; public final fun getValueRestriction ()Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public final fun getValueTypes ()Ljava/util/List; 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 setAllowedValues (Ljava/util/List;)V
public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V
public final fun setChildren (Ljava/util/Map;)V public final fun setChildren (Ljava/util/Map;)V
public final fun setDefault (Lspace/kscience/dataforge/meta/Value;)V public final fun setDefault (Lspace/kscience/dataforge/meta/Value;)V
public final fun setDescription (Ljava/lang/String;)V public final fun setDescription (Ljava/lang/String;)V
public final fun setIndexKey (Ljava/lang/String;)V public final fun setIndexKey (Ljava/lang/String;)V
public final fun setInfo (Ljava/lang/String;)V
public final fun setMultiple (Z)V public final fun setMultiple (Z)V
public final fun setValueRestriction (Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;)V public final fun setValueRestriction (Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;)V
public final fun setValueTypes (Ljava/util/List;)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 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 { 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 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 final class space/kscience/dataforge/names/Name {
public static final field Companion Lspace/kscience/dataforge/names/Name$Companion; public static final field Companion Lspace/kscience/dataforge/names/Name$Companion;
public static final field NAME_SEPARATOR Ljava/lang/String; 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 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 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 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; public static final fun appendLeft (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name;

@ -9,6 +9,8 @@ import space.kscience.dataforge.names.NameToken
*/ */
public class Laminate internal constructor(public val layers: List<Meta>) : TypedMeta<Laminate> { 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 value: Value? = layers.firstNotNullOfOrNull { it.value }
override val items: Map<NameToken, Laminate> by lazy { override val items: Map<NameToken, Laminate> by lazy {

@ -3,7 +3,6 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import space.kscience.dataforge.misc.DfType import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.misc.unsafeCast
import space.kscience.dataforge.names.* import space.kscience.dataforge.names.*
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
@ -151,6 +150,8 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta {
override val items: Map<NameToken, M> override val items: Map<NameToken, M>
public val self: M
override fun get(name: Name): M? { override fun get(name: Name): M? {
tailrec fun M.find(name: Name): M? = if (name.isEmpty()) { tailrec fun M.find(name: Name): M? = if (name.isEmpty()) {
this this
@ -164,11 +165,6 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta {
override fun toMeta(): Meta = this 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 typealias Meta = TypedMeta<*>
public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token) public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token)

@ -11,7 +11,7 @@ import space.kscience.dataforge.misc.DFExperimental
/** /**
* A converter of generic object to and from [Meta] * 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 * A descriptor for resulting meta
@ -135,16 +135,17 @@ public interface MetaConverter<T>: MetaSpec<T> {
@DFExperimental @DFExperimental
public inline fun <reified T> serializable( public inline fun <reified T> serializable(
descriptor: MetaDescriptor? = null, descriptor: MetaDescriptor? = null,
jsonEncoder: Json = Json,
): MetaConverter<T> = object : MetaConverter<T> { ): MetaConverter<T> = object : MetaConverter<T> {
private val serializer: KSerializer<T> = serializer() private val serializer: KSerializer<T> = serializer()
override fun readOrNull(source: Meta): T? { override fun readOrNull(source: Meta): T? {
val json = source.toJson(descriptor) val json = source.toJson(descriptor)
return Json.decodeFromJsonElement(serializer, json) return jsonEncoder.decodeFromJsonElement(serializer, json)
} }
override fun convert(obj: T): Meta { override fun convert(obj: T): Meta {
val json = Json.encodeToJsonElement(obj) val json = jsonEncoder.encodeToJsonElement(obj)
return json.toMeta(descriptor) return json.toMeta(descriptor)
} }

@ -1,25 +1,41 @@
package space.kscience.dataforge.meta 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.MetaDescriptor
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
/* Meta delegates */ /* Meta delegates */
public fun MetaProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = ReadOnlyProperty { _, property -> public interface MetaDelegate<T> : ReadOnlyProperty<Any?, T>, Described
get(key ?: property.name.asName())
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( public fun <T> MetaProvider.spec(
metaSpec: MetaSpec<T>, metaReader: MetaReader<T>,
key: Name? = null, key: Name? = null,
): ReadOnlyProperty<Any?, T?> = ReadOnlyProperty { _, property -> ): MetaDelegate<T?> = object : MetaDelegate<T?> {
get(key ?: property.name.asName())?.let { metaSpec.read(it) } 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 @DFExperimental
public inline fun <reified T> MetaProvider.serializable( public inline fun <reified T> MetaProvider.serializable(
descriptor: MetaDescriptor? = null,
key: Name? = 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)")) @Deprecated("Use convertable", ReplaceWith("convertable(converter, key)"))
public fun <T> MetaProvider.node( public fun <T> MetaProvider.node(
key: Name? = null, key: Name? = null,
converter: MetaSpec<T>, converter: MetaReader<T>,
): ReadOnlyProperty<Any?, T?> = spec(converter, key) ): ReadOnlyProperty<Any?, T?> = spec(converter, key)
/** /**
* Use [converter] to convert a list of same name siblings meta to object * Use [converter] to convert a list of same name siblings meta to object
*/ */
public fun <T> Meta.listOfSpec( public fun <T> Meta.listOfSpec(
converter: MetaSpec<T>, converter: MetaReader<T>,
key: Name? = null, key: Name? = null,
): ReadOnlyProperty<Any?, List<T>> = ReadOnlyProperty{_, property -> ): MetaDelegate<List<T>> = object : MetaDelegate<List<T>> {
val name = key ?: property.name.asName() override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
getIndexed(name).values.map { converter.read(it) } val name = key ?: property.name.asName()
return getIndexed(name).values.map { converter.read(it) }
}
override val descriptor: MetaDescriptor? = converter.descriptor?.copy(multiple = true)
} }
@DFExperimental @DFExperimental
public inline fun <reified T> Meta.listOfSerializable( public inline fun <reified T> Meta.listOfSerializable(
descriptor: MetaDescriptor? = null,
key: Name? = 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 * A property delegate that uses custom key
*/ */
public fun MetaProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = ReadOnlyProperty { _, property -> public fun MetaProvider.value(
get(key ?: property.name.asName())?.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( public fun <R> MetaProvider.value(
key: Name? = null, key: Name? = null,
descriptor: MetaDescriptor? = null,
reader: (Value?) -> R, reader: (Value?) -> R,
): ReadOnlyProperty<Any?, R> = ReadOnlyProperty { _, property -> ): MetaDelegate<R> = object : MetaDelegate<R> {
reader(get(key ?: property.name.asName())?.value) 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 //TODO add caching for sealed nodes
/* Read-only delegates for [Meta] */ /* 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> = public fun MetaProvider.string(default: String, key: Name? = null): MetaDelegate<String> =
value(key) { it?.string ?: default } value(key = key) { it?.string ?: default }
public fun MetaProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> = public fun MetaProvider.boolean(default: Boolean, key: Name? = null): MetaDelegate<Boolean> =
value(key) { it?.boolean ?: default } value(key = key) { it?.boolean ?: default }
public fun MetaProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> = public fun MetaProvider.number(default: Number, key: Name? = null): MetaDelegate<Number> =
value(key) { it?.numberOrNull ?: default } value(key = key) { it?.numberOrNull ?: default }
public fun MetaProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> = public fun MetaProvider.double(default: Double, key: Name? = null): MetaDelegate<Double> =
value(key) { it?.double ?: default } value(key = key) { it?.double ?: default }
public fun MetaProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> = public fun MetaProvider.float(default: Float, key: Name? = null): MetaDelegate<Float> =
value(key) { it?.float ?: default } value(key = key) { it?.float ?: default }
public fun MetaProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> = public fun MetaProvider.int(default: Int, key: Name? = null): MetaDelegate<Int> =
value(key) { it?.int ?: default } value(key = key) { it?.int ?: default }
public fun MetaProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> = public fun MetaProvider.long(default: Long, key: Name? = null): MetaDelegate<Long> =
value(key) { it?.long ?: default } value(key = key) { it?.long ?: default }
public inline fun <reified E : Enum<E>> MetaProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> = public inline fun <reified E : Enum<E>> MetaProvider.enum(default: E, key: Name? = null): MetaDelegate<E> =
value<E>(key) { it?.enum<E>() ?: default } value<E>(key = key) { it?.enum<E>() ?: default }
public fun MetaProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> = public fun MetaProvider.string(key: Name? = null, default: () -> String): MetaDelegate<String> =
value(key) { it?.string ?: default() } value(key = key) { it?.string ?: default() }
public fun MetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> = public fun MetaProvider.boolean(key: Name? = null, default: () -> Boolean): MetaDelegate<Boolean> =
value(key) { it?.boolean ?: default() } value(key = key) { it?.boolean ?: default() }
public fun MetaProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> = public fun MetaProvider.number(key: Name? = null, default: () -> Number): MetaDelegate<Number> =
value(key) { it?.numberOrNull ?: default() } value(key = key) { it?.numberOrNull ?: default() }

@ -2,7 +2,7 @@ package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.descriptors.Described 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 * 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? 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. * 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 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 : Any> MetaReader<T>.readNullable(item: Meta?): T? = item?.let { read(it) }
public fun <T> MetaSpec<T>.readValue(value: Value): T? = read(Meta(value)) public fun <T> MetaReader<T>.readValue(value: Value): T? = read(Meta(value))

@ -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()
}
}
}

@ -19,6 +19,10 @@ public annotation class MetaBuilderMarker
public interface MutableMetaProvider : MetaProvider, MutableValueProvider { public interface MutableMetaProvider : MetaProvider, MutableValueProvider {
override fun get(name: Name): MutableMeta? override fun get(name: Name): MutableMeta?
public operator fun set(name: Name, node: Meta?) 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?) override fun setValue(name: Name, value: Value?)
} }
@ -48,11 +52,13 @@ public interface MutableMeta : Meta, MutableMetaProvider {
} }
override fun setValue(name: Name, value: Value?) { 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 public fun getOrCreate(name: Name): MutableMeta
@ -122,6 +128,10 @@ public interface MutableMeta : Meta, MutableMetaProvider {
setValue(Name.parse(this), array.asValue()) 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) { public infix fun String.put(repr: MetaRepr) {
set(Name.parse(this), repr.toMeta()) 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: * Update the existing mutable node with another node.
* * value replaces anything * Values that are present in the current provider and are missing in [meta] are kept.
* * 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
*/ */
public fun MutableMetaProvider.update(meta: Meta) { public fun MutableMetaProvider.update(meta: Meta) {
meta.valueSequence().forEach { (name, value) -> meta.valueSequence().forEach { (name, value) ->
@ -222,7 +230,7 @@ public fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.edit(name: Name, builde
getOrCreate(name).apply(builder) 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?) { public operator fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.set(name: Name, value: Value?) {
edit(name) { edit(name) {
@ -245,6 +253,9 @@ private class MutableMetaImpl(
value: Value?, value: Value?,
children: Map<NameToken, Meta> = emptyMap(), children: Map<NameToken, Meta> = emptyMap(),
) : AbstractObservableMeta(), ObservableMutableMeta { ) : AbstractObservableMeta(), ObservableMutableMeta {
override val self get() = this
override var value = value override var value = value
@ThreadSafe set(value) { @ThreadSafe set(value) {
val oldValue = field 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) 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 * 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") @JsName("newObservableMutableMeta")
public fun ObservableMutableMeta(): ObservableMutableMeta = MutableMetaImpl(null) 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 * Build a [MutableMeta] using given transformation
*/ */

@ -1,26 +1,36 @@
package space.kscience.dataforge.meta 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.MetaDescriptor
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.getIndexedList
import kotlin.properties.ReadWriteProperty import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
/* Read-write delegates */ /* Read-write delegates */
public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = public interface MutableMetaDelegate<T> : ReadWriteProperty<Any?, T>, Described
object : ReadWriteProperty<Any?, Meta?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? {
return get(key ?: property.name.asName())
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) { public fun MutableMetaProvider.node(
val name = key ?: property.name.asName() key: Name? = null,
set(name, value) 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. * Use [converter] to transform an object to Meta and back.
* Note that mutation of the object does not change Meta. * 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( public fun <T> MutableMetaProvider.convertable(
converter: MetaConverter<T>, converter: MetaConverter<T>,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, T?> = ): MutableMetaDelegate<T?> = object : MutableMetaDelegate<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) }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { override val descriptor: MetaDescriptor? get() = converter.descriptor
val name = key ?: property.name.asName()
set(name, value?.let { converter.convert(it) })
} 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)")) @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) convertable(converter, key)
/** /**
@ -53,7 +66,7 @@ public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConver
public inline fun <reified T> MutableMetaProvider.serializable( public inline fun <reified T> MutableMetaProvider.serializable(
descriptor: MetaDescriptor? = null, descriptor: MetaDescriptor? = null,
key: Name? = 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. * 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( public fun <T> MutableMeta.listOfConvertable(
converter: MetaConverter<T>, converter: MetaConverter<T>,
key: Name? = null, 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> { override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
val name = key ?: property.name.asName() 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>) { override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) {
@ -76,26 +91,33 @@ public fun <T> MutableMeta.listOfConvertable(
@DFExperimental @DFExperimental
public inline fun <reified T> MutableMeta.listOfSerializable( public inline fun <reified T> MutableMeta.listOfSerializable(
descriptor: MetaDescriptor? = null,
key: Name? = 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?> = public fun MutableMetaProvider.value(
object : ReadWriteProperty<Any?, Value?> { key: Name? = null,
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? = descriptor: MetaDescriptor? = null,
get(key ?: property.name.asName())?.value ): MutableMetaDelegate<Value?> = object : MutableMetaDelegate<Value?> {
override val descriptor: MetaDescriptor? = descriptor
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) { override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
setValue(key ?: property.name.asName(), 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( public fun <T> MutableMetaProvider.value(
key: Name? = null, key: Name? = null,
writer: (T) -> Value? = { Value.of(it) }, writer: (T) -> Value? = { Value.of(it) },
descriptor: MetaDescriptor? = null,
reader: (Value?) -> T, 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 = override fun getValue(thisRef: Any?, property: KProperty<*>): T =
reader(get(key ?: property.name.asName())?.value) reader(get(key ?: property.name.asName())?.value)
@ -106,65 +128,65 @@ public fun <T> MutableMetaProvider.value(
/* Read-write delegates for [MutableItemProvider] */ /* 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 } 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 } 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 } 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 } 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 } 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 } 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() } 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() } 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() } value(key) { it?.number ?: default() }
public inline fun <reified E : Enum<E>> MutableMetaProvider.enum( public inline fun <reified E : Enum<E>> MutableMetaProvider.enum(
default: E, default: E,
key: Name? = null, 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 */ /* 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 } 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 } 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 } 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 } value(key) { it?.float }
/* Safe number delegates*/ /* 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 } 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 } 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 } 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 } value(key) { it?.float ?: default }
@ -173,7 +195,7 @@ public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWri
public fun MutableMetaProvider.stringList( public fun MutableMetaProvider.stringList(
vararg default: String, vararg default: String,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, List<String>> = value( ): MutableMetaDelegate<List<String>> = value(
key, key,
writer = { list -> list.map { str -> str.asValue() }.asValue() }, writer = { list -> list.map { str -> str.asValue() }.asValue() },
reader = { it?.stringList ?: listOf(*default) }, reader = { it?.stringList ?: listOf(*default) },
@ -181,7 +203,7 @@ public fun MutableMetaProvider.stringList(
public fun MutableMetaProvider.stringList( public fun MutableMetaProvider.stringList(
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, List<String>?> = value( ): MutableMetaDelegate<List<String>?> = value(
key, key,
writer = { it -> it?.map { str -> str.asValue() }?.asValue() }, writer = { it -> it?.map { str -> str.asValue() }?.asValue() },
reader = { it?.stringList }, reader = { it?.stringList },
@ -190,29 +212,18 @@ public fun MutableMetaProvider.stringList(
public fun MutableMetaProvider.numberList( public fun MutableMetaProvider.numberList(
vararg default: Number, vararg default: Number,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, List<Number>> = value( ): MutableMetaDelegate<List<Number>> = value(
key, key,
writer = { it.map { num -> num.asValue() }.asValue() }, writer = { it.map { num -> num.asValue() }.asValue() },
reader = { it?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) }, 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( public fun <T> MutableMetaProvider.listValue(
key: Name? = null, key: Name? = null,
writer: (T) -> Value = { Value.of(it) }, writer: (T) -> Value = { Value.of(it) },
reader: (Value) -> T, reader: (Value) -> T,
): ReadWriteProperty<Any?, List<T>?> = value( ): MutableMetaDelegate<List<T>?> = value(
key, key,
writer = { it?.map(writer)?.asValue() }, writer = { it?.map(writer)?.asValue() },
reader = { it?.list?.map(reader) } reader = { it?.list?.map(reader) }

@ -39,6 +39,9 @@ public interface ObservableMeta : Meta {
* A [Meta] which is both observable and mutable * A [Meta] which is both observable and mutable
*/ */
public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> { public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> {
override val self: ObservableMutableMeta get() = this
override fun getOrCreate(name: Name): ObservableMutableMeta override fun getOrCreate(name: Name): ObservableMutableMeta
override fun get(name: Name): ObservableMutableMeta? { override fun get(name: Name): ObservableMutableMeta? {

@ -14,10 +14,13 @@ private class ObservableMetaWrapper(
val nodeName: Name, val nodeName: Name,
val listeners: MutableSet<MetaListener>, val listeners: MutableSet<MetaListener>,
) : ObservableMutableMeta { ) : ObservableMutableMeta {
override val self get() = this
override val items: Map<NameToken, ObservableMutableMeta> override val items: Map<NameToken, ObservableMutableMeta>
get() = root.items.keys.associateWith { get() = root[nodeName]?.items?.keys?.associateWith {
ObservableMetaWrapper(root, nodeName + it, listeners) ObservableMetaWrapper(root, nodeName + it, listeners)
} } ?: emptyMap()
override fun get(name: Name): ObservableMutableMeta? = if (root[nodeName + name] == null) { override fun get(name: Name): ObservableMutableMeta? = if (root[nodeName + name] == null) {
null null

@ -12,33 +12,29 @@ import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
/** /**
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaSpec]. * A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaReader].
* Default item provider and [MetaDescriptor] are optional *
* @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 * Meta to be mutated by this scheme
*/ */
private var target: MutableMeta? = null internal var target: MutableMeta = MutableMeta()
get() {
// automatic initialization of target if it is missing
if (field == null) {
field = MutableMeta()
}
return field
}
/** /**
* 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 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 * 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() override fun toString(): String = meta.toString()
private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta { private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta {
override val self get() = this
override var value: Value? override var value: Value?
get() = target[pathName]?.value get() = target[pathName]?.value
?: prototype?.get(pathName)?.value ?: prototype?.get(pathName)?.value
?: descriptor?.get(pathName)?.defaultValue ?: descriptor?.get(pathName)?.defaultValue
set(value) { set(value) {
val oldValue = target[pathName]?.value val oldValue = target[pathName]?.value
target!![pathName] = value target[pathName] = value
if (oldValue != value) { if (oldValue != value) {
invalidate(Name.EMPTY) invalidate(Name.EMPTY)
} }
@ -126,7 +125,7 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
override fun hashCode(): Int = Meta.hashCode(this) override fun hashCode(): Int = Meta.hashCode(this)
override fun set(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
target!![name] = node target[pathName + name] = node
invalidate(name) invalidate(name)
} }
@ -176,18 +175,22 @@ public open class SchemeSpec<T : Scheme>(
it.initialize(MutableMeta(), source, descriptor) 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 { public fun write(target: MutableMeta): T = empty().also {
target.update(it.meta)
it.initialize(target, Meta.EMPTY, descriptor) 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 { 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 * A convenience method to use specifications in builders
@ -197,7 +200,6 @@ public open class SchemeSpec<T : Scheme>(
} }
/** /**
* Update a [MutableMeta] using given specification * 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( public fun <T : Scheme> MutableMeta.scheme(
spec: SchemeSpec<T>, spec: SchemeSpec<T>,
@ -240,7 +242,7 @@ public fun <T : Scheme> Scheme.scheme(
): ReadWriteProperty<Any?, T> = meta.scheme(spec, key) ): 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. * Returns null if meta with given name does not exist.
*/ */
public fun <T : Scheme> MutableMeta.schemeOrNull( public fun <T : Scheme> MutableMeta.schemeOrNull(
@ -265,18 +267,17 @@ public fun <T : Scheme> Scheme.schemeOrNull(
): ReadWriteProperty<Any?, T?> = meta.schemeOrNull(spec, key) ): 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. * 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. * 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( public fun <T : Scheme> MutableMeta.listOfScheme(
spec: SchemeSpec<T>, spec: SchemeSpec<T>,
key: Name? = null, key: Name? = null,
): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> { ): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> { override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
val name = key ?: property.name.asName() 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>) { 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( public fun <T : Scheme> Scheme.listOfScheme(
spec: SchemeSpec<T>, spec: SchemeSpec<T>,
key: Name? = null, key: Name? = null,

@ -13,6 +13,9 @@ public class SealedMeta(
override val value: Value?, override val value: Value?,
override val items: Map<NameToken, SealedMeta>, override val items: Map<NameToken, SealedMeta>,
) : TypedMeta<SealedMeta> { ) : TypedMeta<SealedMeta> {
override val self: SealedMeta get() = this
override fun toString(): String = Meta.toString(this) override fun toString(): String = Meta.toString(this)
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta) override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
@ -76,6 +79,8 @@ internal class MetaBuilder(
override fun set(name: Name, node: Meta?) { override fun set(name: Name, node: Meta?) {
//skip setting if value has not changed
if(node == get(name)) return
when (name.length) { when (name.length) {
0 -> error("Can't set a meta with empty name") 0 -> error("Can't set a meta with empty name")
1 -> { 1 -> {
@ -89,7 +94,7 @@ internal class MetaBuilder(
} }
else -> { else -> {
getOrCreate(name.first().asName()).set(name.cutFirst(), node) getOrCreate(name.first().asName())[name.cutFirst()] = node
} }
} }
} }

@ -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 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) public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this)

@ -11,9 +11,6 @@ import kotlin.collections.set
public class MetaDescriptorBuilder @PublishedApi internal constructor() { public class MetaDescriptorBuilder @PublishedApi internal constructor() {
public var description: String? = null public var description: String? = null
@Deprecated("Replace by description", ReplaceWith("description"))
public var info: String? by ::description
public var children: MutableMap<String, MetaDescriptorBuilder> = linkedMapOf() public var children: MutableMap<String, MetaDescriptorBuilder> = linkedMapOf()
public var multiple: Boolean = false public var multiple: Boolean = false
public var valueRestriction: ValueRestriction = ValueRestriction.NONE public var valueRestriction: ValueRestriction = ValueRestriction.NONE
@ -50,6 +47,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
): Unit { ): Unit {
when (name.length) { when (name.length) {
0 -> error("Can't set descriptor to root") 0 -> error("Can't set descriptor to root")
1 -> { 1 -> {
children[name.first().body] = descriptorBuilder children[name.first().body] = descriptorBuilder
} }
@ -60,7 +58,7 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
} }
} }
internal fun node( public fun node(
name: Name, name: Name,
descriptorBuilder: MetaDescriptor, descriptorBuilder: MetaDescriptor,
): Unit { ): Unit {

@ -3,11 +3,12 @@ package space.kscience.dataforge.meta.descriptors
import space.kscience.dataforge.meta.Scheme import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.meta.SchemeSpec import space.kscience.dataforge.meta.SchemeSpec
import space.kscience.dataforge.meta.ValueType import space.kscience.dataforge.meta.ValueType
import space.kscience.dataforge.misc.DFExperimental
import kotlin.reflect.KProperty1 import kotlin.reflect.KProperty1
import kotlin.reflect.typeOf 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( public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
property: KProperty1<S, T>, property: KProperty1<S, T>,
noinline block: MetaDescriptorBuilder.() -> Unit = {}, noinline block: MetaDescriptorBuilder.() -> Unit = {},
@ -39,7 +40,9 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
else -> node(property.name, block) else -> node(property.name, block)
} }
@DFExperimental /**
* Add a schem-based branch to a [MetaDescriptor]
*/
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme( public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
property: KProperty1<S, T>, property: KProperty1<S, T>,
spec: SchemeSpec<T>, spec: SchemeSpec<T>,

@ -1,5 +1,9 @@
package space.kscience.dataforge.meta 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 * 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 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) },
)

@ -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.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) public fun Value.toMeta(): Meta = Meta(this)

@ -18,4 +18,11 @@ public annotation class DFExperimental
*/ */
@RequiresOptIn(level = RequiresOptIn.Level.WARNING) @RequiresOptIn(level = RequiresOptIn.Level.WARNING)
@Retention(AnnotationRetention.BINARY) @Retention(AnnotationRetention.BINARY)
public annotation class DFInternal 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

@ -1,3 +0,0 @@
package space.kscience.dataforge.misc
public expect inline fun <T> Any?.unsafeCast(): T

@ -58,7 +58,7 @@ public class Name(public val tokens: List<NameToken>) {
*/ */
public fun parse(string: String): Name { public fun parse(string: String): Name {
if (string.isBlank()) return EMPTY if (string.isBlank()) return EMPTY
val tokens = sequence { val tokens = buildList<NameToken> {
var bodyBuilder = StringBuilder() var bodyBuilder = StringBuilder()
var queryBuilder = StringBuilder() var queryBuilder = StringBuilder()
var bracketCount = 0 var bracketCount = 0
@ -91,7 +91,7 @@ public class Name(public val tokens: List<NameToken>) {
else -> when (it) { else -> when (it) {
'.' -> { '.' -> {
val query = if (queryBuilder.isEmpty()) null else queryBuilder.toString() val query = if (queryBuilder.isEmpty()) null else queryBuilder.toString()
yield(NameToken(bodyBuilder.toString(), query)) add(NameToken(bodyBuilder.toString(), query))
bodyBuilder = StringBuilder() bodyBuilder = StringBuilder()
queryBuilder = StringBuilder() queryBuilder = StringBuilder()
} }
@ -106,9 +106,9 @@ public class Name(public val tokens: List<NameToken>) {
} }
} }
val query = if (queryBuilder.isEmpty()) null else queryBuilder.toString() 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)
} }
} }
} }

@ -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}

@ -69,7 +69,7 @@ public class NameToken(public val body: String, public val index: String? = null
public fun parse(string: String): NameToken { public fun parse(string: String): NameToken {
val body = string.substringBefore('[') val body = string.substringBefore('[')
val index = string.substringAfter('[', "") 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("]")) return NameToken(body, index.removeSuffix("]"))
} }
} }

@ -61,4 +61,33 @@ class MetaTest {
assertEquals(null, indexed["8"]) assertEquals(null, indexed["8"])
assertEquals(12, indexed["12"].int) 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())
}
} }

@ -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)
}
}

@ -1,7 +1,17 @@
package space.kscience.dataforge.meta package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals 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() { internal class TestScheme : Scheme() {
var list by numberList(1, 2, 3) var list by numberList(1, 2, 3)
@ -11,9 +21,23 @@ internal class TestScheme : Scheme() {
var v by value() var v by value()
var sub by scheme(SubScheme)
companion object : SchemeSpec<TestScheme>(::TestScheme) companion object : SchemeSpec<TestScheme>(::TestScheme)
} }
private class SchemeWithInit: Scheme(){
init {
set("initial", "initialValue")
}
var initial by string()
companion object: SchemeSpec<SchemeWithInit>(::SchemeWithInit)
}
class SpecificationTest { class SpecificationTest {
// @Test // @Test
@ -71,4 +95,64 @@ class SpecificationTest {
assertEquals(22, config["child.a"].int) assertEquals(22, config["child.a"].int)
assertEquals("test", config["child.b"].string) 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)
}
} }

@ -1,9 +1,6 @@
package space.kscience.dataforge.names package space.kscience.dataforge.names
import kotlin.test.Test import kotlin.test.*
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class NameTest { class NameTest {
@Test @Test
@ -50,4 +47,19 @@ class NameTest {
val name = Name.parse("a.b.c") val name = Name.parse("a.b.c")
assertEquals("a.b".parseAsName(), name.cutLast()) 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")
}
}
} }

@ -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))
}
}

@ -31,6 +31,9 @@ public fun Meta.toDynamic(): dynamic {
} }
public class DynamicMeta(internal val obj: dynamic) : TypedMeta<DynamicMeta> { 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 keys(): Array<String> = js("Object").keys(obj) as Array<String>
private fun isArray(obj: dynamic): Boolean = private fun isArray(obj: dynamic): Boolean =

@ -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>()

@ -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

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

@ -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

@ -6,7 +6,7 @@
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-scripting:0.8.0") implementation("space.kscience:dataforge-scripting:0.9.0-dev-1")
} }
``` ```

@ -6,7 +6,7 @@
## Artifact: ## 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:** **Gradle Kotlin DSL:**
```kotlin ```kotlin
@ -16,6 +16,6 @@ repositories {
} }
dependencies { dependencies {
implementation("space.kscience:dataforge-workspace:0.8.0") implementation("space.kscience:dataforge-workspace:0.9.0-dev-1")
} }
``` ```

@ -5,11 +5,12 @@ import space.kscience.dataforge.data.DataSink
import space.kscience.dataforge.data.GoalExecutionRestriction import space.kscience.dataforge.data.GoalExecutionRestriction
import space.kscience.dataforge.data.MutableDataTree import space.kscience.dataforge.data.MutableDataTree
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaReader
import space.kscience.dataforge.meta.MetaRepr 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.Described
import space.kscience.dataforge.meta.descriptors.MetaDescriptor import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.DfType import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.workspace.Task.Companion.TYPE import space.kscience.dataforge.workspace.Task.Companion.TYPE
import kotlin.reflect.KType import kotlin.reflect.KType
@ -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 interface TaskWithSpec<T, C : Any> : Task<T> {
public val spec: MetaSpec<C> public val spec: MetaReader<C>
override val descriptor: MetaDescriptor? get() = spec.descriptor override val descriptor: MetaDescriptor? get() = spec.descriptor
public suspend fun execute(workspace: Workspace, taskName: Name, configuration: C): TaskResult<T> public suspend fun execute(workspace: Workspace, taskName: Name, configuration: C): TaskResult<T>
@ -90,7 +91,8 @@ public fun <T : Any> Task(
taskMeta: Meta, taskMeta: Meta,
): TaskResult<T> { ): TaskResult<T> {
//TODO use safe builder and check for external data on add and detects cycles //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 { TaskResultBuilder(workspace, taskName, taskMeta, this).apply {
withContext(GoalExecutionRestriction() + workspace.goalLogger) { withContext(GoalExecutionRestriction() + workspace.goalLogger) {
builder() builder()
@ -98,7 +100,6 @@ public fun <T : Any> Task(
} }
} }
return workspace.wrapResult(dataset, taskName, taskMeta) return workspace.wrapResult(dataset, taskName, taskMeta)
} }
} }
@ -117,13 +118,14 @@ public inline fun <reified T : Any> Task(
* @param builder for resulting data set * @param builder for resulting data set
*/ */
@Suppress("FunctionName") @Suppress("FunctionName")
public fun <T : Any, C : MetaRepr> Task( public fun <T : Any, C : MetaRepr> Task(
resultType: KType, resultType: KType,
specification: MetaSpec<C>, specification: MetaReader<C>,
builder: suspend TaskResultBuilder<T>.(C) -> Unit, builder: suspend TaskResultBuilder<T>.(C) -> Unit,
): TaskWithSpec<T, C> = object : TaskWithSpec<T, C> { ): TaskWithSpec<T, C> = object : TaskWithSpec<T, C> {
override val spec: MetaSpec<C> = specification override val spec: MetaReader<C> = specification
override suspend fun execute( override suspend fun execute(
workspace: Workspace, workspace: Workspace,
@ -132,7 +134,8 @@ public fun <T : Any, C : MetaRepr> Task(
): TaskResult<T> = withContext(GoalExecutionRestriction() + workspace.goalLogger) { ): TaskResult<T> = withContext(GoalExecutionRestriction() + workspace.goalLogger) {
//TODO use safe builder and check for external data on add and detects cycles //TODO use safe builder and check for external data on add and detects cycles
val taskMeta = configuration.toMeta() 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) } TaskResultBuilder(workspace, taskName, taskMeta, this).apply { builder(configuration) }
} }
workspace.wrapResult(dataset, taskName, taskMeta) 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( public inline fun <reified T : Any, C : MetaRepr> Task(
specification: MetaSpec<C>, specification: MetaReader<C>,
noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit, noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit,
): Task<T> = Task(typeOf<T>(), specification, builder) ): Task<T> = Task(typeOf<T>(), specification, builder)

@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.joinAll import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch 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.asSequence
import space.kscience.dataforge.data.launch import space.kscience.dataforge.data.launch
import space.kscience.dataforge.meta.Meta 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 * @param taskMeta The configuration of the task that produced the result
*/ */
public data class TaskResult<T>( public data class TaskResult<T>(
public val content: ObservableDataTree<T>, public val content: DataTree<T>,
public val workspace: Workspace, public val workspace: Workspace,
public val taskName: Name, public val taskName: Name,
public val taskMeta: Meta, public val taskMeta: Meta,
) : ObservableDataTree<T> by content ) : DataTree<T> by content
/** /**
* Wrap data into [TaskResult] * 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) TaskResult(data, this, taskName, taskMeta)
/** /**

@ -2,7 +2,10 @@ package space.kscience.dataforge.workspace
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import space.kscience.dataforge.context.ContextAware 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.Meta
import space.kscience.dataforge.meta.MutableMeta import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DfType import space.kscience.dataforge.misc.DfType
@ -11,7 +14,7 @@ import space.kscience.dataforge.provider.Provider
import kotlin.coroutines.CoroutineContext 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> 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 * The whole data node for current workspace
*/ */
public val data: ObservableDataTree<*> public val data: DataTree<*>
/** /**
* All targets associated with the workspace * All targets associated with the workspace

@ -1,6 +1,5 @@
package space.kscience.dataforge.workspace package space.kscience.dataforge.workspace
import kotlinx.coroutines.CoroutineScope
import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.ContextBuilder 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.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
import space.kscience.dataforge.misc.DFBuilder import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import kotlin.collections.set 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( public inline fun <reified T : Any, C : MetaRepr> TaskContainer.task(
specification: MetaSpec<C>, specification: MetaReader<C>,
noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit, noinline builder: suspend TaskResultBuilder<T>.(C) -> Unit,
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<T>>> = PropertyDelegateProvider { _, property -> ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<T>>> = PropertyDelegateProvider { _, property ->
val taskName = Name.parse(property.name) 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( public inline fun <T : Any, reified R : Any> TaskContainer.action(
selector: DataSelector<T>, selector: DataSelector<T>,
action: Action<T, R>, action: Action<T, R>,
noinline metaTransform: MutableMeta.()-> Unit = {}, noinline metaTransform: MutableMeta.() -> Unit = {},
noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {}, noinline descriptorBuilder: MetaDescriptorBuilder.() -> Unit = {},
): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<R>>> = ): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, TaskReference<R>>> =
task(MetaDescriptor(descriptorBuilder)) { task(MetaDescriptor(descriptorBuilder)) {
result(action.execute(from(selector), taskMeta.copy(metaTransform))) result(action.execute(from(selector), taskMeta.copy(metaTransform), workspace))
} }
public class WorkspaceBuilder( public class WorkspaceBuilder(
private val parentContext: Context = Global, private val parentContext: Context = Global,
private val coroutineScope: CoroutineScope = parentContext,
) : TaskContainer { ) : TaskContainer {
private var context: Context? = null 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 targets: HashMap<String, Meta> = HashMap()
private val tasks = HashMap<Name, Task<*>>() private val tasks = HashMap<Name, Task<*>>()
private var cache: WorkspaceCache? = null private var cache: WorkspaceCache? = null

@ -2,14 +2,14 @@ package space.kscience.dataforge.workspace
import space.kscience.dataforge.context.Context import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.gather 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.meta.Meta
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
internal class WorkspaceImpl internal constructor( internal class WorkspaceImpl internal constructor(
override val context: Context, override val context: Context,
override val data: ObservableDataTree<*>, override val data: DataTree<*>,
override val targets: Map<String, Meta>, override val targets: Map<String, Meta>,
tasks: Map<Name, Task<*>>, tasks: Map<Name, Task<*>>,
private val postProcess: suspend (TaskResult<*>) -> TaskResult<*>, private val postProcess: suspend (TaskResult<*>) -> TaskResult<*>,

@ -3,14 +3,14 @@ package space.kscience.dataforge.workspace
import space.kscience.dataforge.data.Data import space.kscience.dataforge.data.Data
import space.kscience.dataforge.data.await import space.kscience.dataforge.data.await
import space.kscience.dataforge.io.* import space.kscience.dataforge.io.*
import space.kscience.dataforge.misc.DFInternal import space.kscience.dataforge.misc.UnsafeKType
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
/** /**
* Convert an [Envelope] to a data via given format. The actual parsing is done lazily. * 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) { 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") data?.readWith(format) ?: error("Can't convert envelope without data to Data")
} }

@ -3,8 +3,8 @@ package space.kscience.dataforge.workspace
import space.kscience.dataforge.actions.Action import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.context.PluginFactory import space.kscience.dataforge.context.PluginFactory
import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.branch
import space.kscience.dataforge.data.forEach import space.kscience.dataforge.data.forEach
import space.kscience.dataforge.data.putAll
import space.kscience.dataforge.data.transform import space.kscience.dataforge.data.transform
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.DFExperimental 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. * Set given [dataSet] as a task result.
*/ */
public fun <T> TaskResultBuilder<T>.result(dataSet: DataTree<T>) { 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>, action: Action<T, R>,
dependencyMeta: Meta = defaultDependencyMeta, dependencyMeta: Meta = defaultDependencyMeta,
) { ) {
branch(action.execute(from(selector, dependencyMeta), dependencyMeta)) putAll(action.execute(from(selector, dependencyMeta), dependencyMeta, workspace))
} }

@ -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))
}
}

@ -1,19 +1,22 @@
package space.kscience.dataforge.workspace package space.kscience.dataforge.workspace
import kotlinx.coroutines.flow.map
import kotlinx.io.* import kotlinx.io.*
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoBuf
import kotlinx.serialization.serializer 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.error
import space.kscience.dataforge.context.logger import space.kscience.dataforge.context.logger
import space.kscience.dataforge.context.request 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.io.*
import space.kscience.dataforge.misc.DFExperimental 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 space.kscience.dataforge.names.withIndex
import java.nio.file.Path import java.nio.file.Path
import kotlin.io.path.deleteIfExists 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> // 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> { override suspend fun <T> cache(result: TaskResult<T>): TaskResult<T> {
val io = result.workspace.context.request(IOPlugin) val io = result.workspace.context.request(IOPlugin)
@ -59,8 +63,8 @@ public class FileWorkspaceCache(public val cacheDirectory: Path) : WorkspaceCach
?: ProtobufIOFormat(result.dataType) ?: ProtobufIOFormat(result.dataType)
?: error("Can't resolve IOFormat for ${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 / val path = cacheDirectory /
result.taskName.withIndex(result.taskMeta.hashCode().toString(16)).toString() / result.taskName.withIndex(result.taskMeta.hashCode().toString(16)).toString() /
data.name.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 -> return@Data data.await().also { result ->
val envelope = Envelope { val envelope = Envelope {
meta = data.meta 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 = cachingAction(result)
val cachedTree = result.asSequence().map { cacheOne(it) }
.toObservableTree(result.dataType, result.workspace, result.updates().map { cacheOne(it) })
return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta) return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta)
} }

@ -1,8 +1,11 @@
package space.kscience.dataforge.workspace package space.kscience.dataforge.workspace
import kotlinx.coroutines.flow.map import space.kscience.dataforge.actions.Action
import space.kscience.dataforge.data.* 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.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import kotlin.reflect.KType import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf import kotlin.reflect.full.isSubtypeOf
@ -19,19 +22,18 @@ public class InMemoryWorkspaceCache : WorkspaceCache {
if (type.isSubtypeOf(taskType)) this as Data<T> if (type.isSubtypeOf(taskType)) this as Data<T>
else error("Cached data type mismatch: expected $taskType but got $type") else error("Cached data type mismatch: expected $taskType but got $type")
@OptIn(DFExperimental::class)
override suspend fun <T> cache(result: TaskResult<T>): TaskResult<T> { 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)){ val cachedData = cache.getOrPut(TaskResultId(result.taskName, result.taskMeta)){
HashMap() HashMap()
}.getOrPut(data.name){ }.getOrPut(data.name){
data.data data.data
} }
return cachedData.checkType<T>(result.dataType).named(data.name) cachedData.checkType<T>(result.dataType).named(data.name)
} }
val cachedTree = cachingAction(result)
val cachedTree = result.asSequence().map { cacheOne(it) }
.toObservableTree(result.dataType, result.workspace, result.updates().map { cacheOne(it) })
return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta) return result.workspace.wrapResult(cachedTree, result.taskName, result.taskMeta)
} }

@ -8,15 +8,11 @@ import space.kscience.dataforge.io.*
import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.copy import space.kscience.dataforge.meta.copy
import space.kscience.dataforge.misc.DFExperimental import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.asName import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus import space.kscience.dataforge.names.plus
import java.nio.file.Files import java.nio.file.*
import java.nio.file.Path
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.attribute.BasicFileAttributes import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.spi.FileSystemProvider import java.nio.file.spi.FileSystemProvider
import kotlin.io.path.* 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. * 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 * 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( public fun IOPlugin.readFileData(
path: Path, path: Path,
): Data<Binary> { ): Data<Binary> {
@ -127,8 +122,6 @@ public fun DataSink<Binary>.files(
private fun Path.toName() = Name(map { NameToken.parse(it.nameWithoutExtension) }) private fun Path.toName() = Name(map { NameToken.parse(it.nameWithoutExtension) })
@DFInternal
@DFExperimental
public fun DataSink<Binary>.monitorFiles( public fun DataSink<Binary>.monitorFiles(
io: IOPlugin, io: IOPlugin,
name: Name, name: Name,
@ -174,13 +167,22 @@ public fun DataSink<Binary>.monitorFiles(
@DFExperimental @DFExperimental
public fun DataSink<Binary>.resources( public fun DataSink<Binary>.resources(
io: IOPlugin, io: IOPlugin,
vararg resources: String, resource: String,
vararg otherResources: String,
classLoader: ClassLoader = Thread.currentThread().contextClassLoader, classLoader: ClassLoader = Thread.currentThread().contextClassLoader,
) { ) {
resources.forEach { resource -> //create a file system if necessary
val path = classLoader.getResource(resource)?.toURI()?.toPath() ?: error( val uri = Thread.currentThread().contextClassLoader.getResource("common")!!.toURI()
"Resource with name $resource is not resolved" 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)
} }
} }

@ -3,7 +3,7 @@ package space.kscience.dataforge.workspace
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test 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.Meta
import space.kscience.dataforge.meta.boolean import space.kscience.dataforge.meta.boolean
import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.get
@ -22,7 +22,7 @@ internal class CachingWorkspaceTest {
data { data {
//statically initialize data //statically initialize data
repeat(5) { repeat(5) {
wrap("myData[$it]", it) putValue("myData[$it]", it)
} }
} }

@ -47,7 +47,7 @@ class DataPropagationTest {
} }
data { data {
repeat(100) { repeat(100) {
wrap("myData[$it]", it) putValue("myData[$it]", it)
} }
} }
} }

@ -23,12 +23,12 @@ import kotlin.test.assertEquals
class FileDataTest { class FileDataTest {
val dataNode = DataTree<String> { val dataNode = DataTree<String> {
branch("dir") { putAll("dir") {
wrap("a", "Some string") { putValue("a", "Some string") {
"content" put "Some string" "content" put "Some string"
} }
} }
wrap("b", "root data") putValue("b", "root data")
// meta { // meta {
// "content" put "This is root meta node" // "content" put "This is root meta node"
// } // }

@ -3,11 +3,11 @@ package space.kscience.dataforge.workspace
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test 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 space.kscience.dataforge.misc.DFExperimental
import java.nio.file.Files import java.nio.file.Files
@OptIn(ExperimentalCoroutinesApi::class,DFExperimental::class) @OptIn(ExperimentalCoroutinesApi::class, DFExperimental::class)
class FileWorkspaceCacheTest { class FileWorkspaceCacheTest {
@Test @Test
@ -16,7 +16,7 @@ class FileWorkspaceCacheTest {
data { data {
//statically initialize data //statically initialize data
repeat(5) { repeat(5) {
wrap("myData[$it]", it) putValue("myData[$it]", it)
} }
} }
fileCache(Files.createTempDirectory("dataforge-temporary-cache")) fileCache(Files.createTempDirectory("dataforge-temporary-cache"))

@ -6,7 +6,6 @@ package space.kscience.dataforge.workspace
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Timeout
import space.kscience.dataforge.context.* import space.kscience.dataforge.context.*
import space.kscience.dataforge.data.* import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.* import space.kscience.dataforge.meta.*
@ -16,6 +15,7 @@ import space.kscience.dataforge.names.plus
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.milliseconds
/** /**
@ -62,7 +62,7 @@ internal class SimpleWorkspaceTest {
data { data {
//statically initialize data //statically initialize data
repeat(100) { repeat(100) {
wrap("myData[$it]", it) putValue("myData[$it]", it)
} }
} }
@ -148,18 +148,16 @@ internal class SimpleWorkspaceTest {
} }
@Test @Test
@Timeout(1) fun testWorkspace() = runTest(timeout = 100.milliseconds) {
fun testWorkspace() = runTest {
val node = workspace.produce("sum") val node = workspace.produce("sum")
val res = node.asSequence().single() val res = node.asSequence().single()
assertEquals(328350, res.await()) assertEquals(328350, res.await())
} }
@Test @Test
@Timeout(1) fun testMetaPropagation() = runTest(timeout = 100.milliseconds) {
fun testMetaPropagation() = runTest {
val node = workspace.produce("sum") { "testFlag" put true } val node = workspace.produce("sum") { "testFlag" put true }
val res = node.single().await() val res = node["sum"]!!.await()
} }
@Test @Test
@ -188,7 +186,7 @@ internal class SimpleWorkspaceTest {
val node = workspace.produce("filterOne") { val node = workspace.produce("filterOne") {
"name" put "myData[12]" "name" put "myData[12]"
} }
assertEquals(12, node.single().await()) assertEquals(12, node.asSequence().first().await())
} }
} }

@ -1,10 +1,9 @@
kotlin.code.style=official
org.gradle.parallel=true org.gradle.parallel=true
org.gradle.jvmargs=-Xmx4096m org.gradle.jvmargs=-Xmx4096m
kotlin.code.style=official
kotlin.mpp.stability.nowarn=true kotlin.mpp.stability.nowarn=true
kotlin.incremental.js.ir=true
kotlin.native.ignoreDisabledTargets=true kotlin.native.ignoreDisabledTargets=true
toolsVersion=0.15.2-kotlin-1.9.21 toolsVersion=0.15.4-kotlin-2.0.0
#kotlin.experimental.tryK2=true

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists