Compare commits

...

47 Commits
master ... 0.9

Author SHA1 Message Date
5a75b05acd 0.9-RC 2024-06-04 17:44:44 +03:00
3de5691c84 Add custom coroutine context during new Context creation 2024-05-25 21:19:06 +03:00
2cd1885420 Update readme and changelog 2024-04-27 10:01:36 +03:00
f840ffb473 Move data tests to jvm to avoid random failings on native 2024-04-27 09:47:08 +03:00
28f4beb348 Fix all tests 2024-04-23 18:59:12 +03:00
a720b63d70 Add ByteArrayValue 2024-04-16 15:35:59 +03:00
1c60453244 Fix NameToken.parse 2024-04-16 15:35:21 +03:00
e7db1cc763 Refactor of data trees filtering 2024-04-02 10:04:46 +03:00
104111f62d Add byte array value. Refactor exotic values 2024-04-02 10:03:18 +03:00
9fe3deac33 Fix scheme set method 2024-04-02 10:01:41 +03:00
db938e1ad8 add custom json encoder to serializerable meta converter 2024-03-14 17:07:32 +03:00
0e72b4b63c Add depth-first walk for data tree 2024-02-24 15:01:27 +03:00
b2593d308e Add depth-first walk for data tree 2024-02-24 11:26:28 +03:00
facf7c3c7e Remove some experimental flags 2024-02-19 20:10:15 +03:00
db2da2027d Replace branch data builder with putAll 2024-02-19 14:26:33 +03:00
b575801983 Replace branch data builder with putAll 2024-02-19 11:42:04 +03:00
aa88f05688 Replace branch data builder with putAll 2024-02-19 11:41:27 +03:00
f95e278b2d Replace branch data builder with putAll 2024-02-18 20:11:53 +03:00
aa4c745819 remove unnecessary type limitations in actions 2024-02-18 18:43:33 +03:00
e850ca4145 minor refactoring 2024-02-18 18:34:26 +03:00
4197b4bb61 Add ordering to name indices 2024-02-06 14:36:20 +03:00
0e5a31db9f Hot fix for observable meta wrapper 2024-02-06 10:21:05 +03:00
78641f6f87 Roll-back version 2024-02-04 13:54:44 +03:00
66ce15ae6d Hot-fix for scheme initialization 2024-02-04 13:54:08 +03:00
196b394278 Update API 2024-02-03 19:34:01 +03:00
297847663b Update documentation 2024-02-03 19:16:18 +03:00
6524c6c691 Add .kotlin to gitignore 2024-02-03 17:36:49 +03:00
a6a4a8120f Merge remote-tracking branch 'spc/master' into dev 2024-02-03 17:35:32 +03:00
6e209ab5cd Data tree refactored to a uniform tree instead of sealed class. 2024-02-03 17:34:19 +03:00
466e460989 Data tree refactored to a uniform tree instead of sealed class. 2024-02-03 17:25:49 +03:00
90999f424f [WIP] change data structure 2024-01-29 22:10:06 +03:00
5fec0518d4 [WIP] change data structure 2024-01-19 22:23:02 +03:00
5e3de70737 Add action delegate for task creation 2024-01-05 13:02:11 +03:00
8f3c2f3950 refactoring of data transformations 2024-01-04 18:59:57 +03:00
6ba189fa34 Remove second invalidate on meta node remove 2023-12-31 19:57:57 +03:00
25281d0f6d Replace properties with flows 2023-12-31 17:55:25 +03:00
991f77c45a Merge MetaConverter and MetaSpec 2023-12-31 13:08:30 +03:00
fd1d98aa87 Merge MetaConverter and MetaSpec 2023-12-31 12:54:38 +03:00
282b43a05a Clean up scheme and descriptor logic 2023-12-31 11:57:54 +03:00
6e20fc3929 fix valueSequence 2023-12-28 22:14:15 +03:00
f9e7d0098f Add convertable and serializable extensions to Meta delegates 2023-12-20 11:07:30 +03:00
f7dec52438 Add automatic MetaConverter for serializeable objects 2023-12-19 18:21:42 +03:00
4de9e1865c Add listOfSpec delegate to Scheme 2023-12-19 17:53:17 +03:00
a32cbe95dc Add listOfSpec delegate to Scheme 2023-12-19 17:53:01 +03:00
946ac88480 Partially fixed a bug with MutableMeta observable wrappers. 2023-12-05 15:13:50 +03:00
5461a83417 Name refactoring.
Meta.stringList accepts nullable receiver.
2023-12-04 09:55:04 +03:00
0a23245117 fix sonatype deploy address 2023-11-26 12:02:54 +03:00
135 changed files with 3553 additions and 3252 deletions

2
.gitignore vendored
View File

@ -5,5 +5,7 @@ out/
.gradle
build/
.kotlin
!gradle-wrapper.jar

View File

@ -3,17 +3,66 @@
## Unreleased
### 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.
### Deprecated
### Removed
- Automatic descriptors for schema. It is not possible to implement them without heavy reflection.
### Fixed
### Security
## 0.8.2 - 2024-04-27
### Added
- Name index comparator
- Specialized ByteArrayValue
### Changed
- DataSink `branch` is replaced with `putAll` to avoid confusion with DataTree methods
- Meta delegate now uses a specific class that has a descriptor
### Fixed
- `listOfScheme` and `listOfConvertable` delegates provides correct items order.
- Scheme meta setter works with proper sub-branch.
- NameToken.parse improper work with indices.
- Proper data handling for cache.
## 0.8.0 - 2024-02-03
### Added
- Wasm artifacts
- Add automatic MetaConverter for serializeable objects
- Add Meta and MutableMeta delegates for convertable and serializeable
- Meta mapping for data.
### Changed
- Descriptor `children` renamed to `nodes`
- `MetaConverter` now inherits `MetaSpec` (former `Specifiction`). So `MetaConverter` could be used more universally.
- Meta copy and modification now use lightweight non-observable meta builders.
- Full refactor of Data API. DataTree now works similar to Meta: contains optional anonymous root element and data items. Updates are available for `ObservaleDataSource` and `ObservableDataTree` variants.
### Deprecated
- `node(key,converter)` in favor of `serializable` delegate
### Fixed
- Partially fixed a bug with `MutableMeta` observable wrappers.
- `valueSequence` now include root value. So `meta.update` works properly.
## 0.7.0 - 2023-11-26
### Added

View File

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

View File

@ -6,18 +6,16 @@ Context and provider definitions
## Artifact:
The Maven coordinates of this project are `space.kscience:dataforge-context:0.7.0`.
The Maven coordinates of this project are `space.kscience:dataforge-context:0.8.2`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
//uncomment to access development builds
//maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
mavenCentral()
}
dependencies {
implementation("space.kscience:dataforge-context:0.7.0")
implementation("space.kscience:dataforge-context:0.8.2")
}
```

View File

@ -249,10 +249,25 @@ public final class space/kscience/dataforge/context/SlfLogManager$Companion : sp
public fun getTag ()Lspace/kscience/dataforge/context/PluginTag;
}
public final class space/kscience/dataforge/properties/PropertyKt {
public abstract interface annotation class space/kscience/dataforge/descriptors/Description : java/lang/annotation/Annotation {
public abstract fun value ()Ljava/lang/String;
}
public final class space/kscience/dataforge/properties/SchemePropertyKt {
public abstract interface annotation class space/kscience/dataforge/descriptors/DescriptorResource : java/lang/annotation/Annotation {
public abstract fun resourceName ()Ljava/lang/String;
}
public abstract interface annotation class space/kscience/dataforge/descriptors/DescriptorUrl : java/lang/annotation/Annotation {
public abstract fun url ()Ljava/lang/String;
}
public abstract interface annotation class space/kscience/dataforge/descriptors/Multiple : java/lang/annotation/Annotation {
}
public final class space/kscience/dataforge/descriptors/ReflectiveDescriptorsKt {
}
public final class space/kscience/dataforge/properties/MetaAsFlowKt {
}
public final class space/kscience/dataforge/provider/DfTypeKt {

View File

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

View File

@ -10,6 +10,7 @@ import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.provider.Provider
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/**
* The local environment for anything being done in DataForge framework. Contexts are organized into tree structure with [Global] at the top.
@ -26,6 +27,7 @@ public open class Context internal constructor(
public val parent: Context?,
plugins: Set<Plugin>, // set of unattached plugins
meta: Meta,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
) : Named, MetaRepr, Provider, CoroutineScope {
/**
@ -65,7 +67,7 @@ public open class Context internal constructor(
override val coroutineContext: CoroutineContext by lazy {
(parent ?: Global).coroutineContext.let { parenContext ->
parenContext + SupervisorJob(parenContext[Job])
parenContext + coroutineContext + SupervisorJob(parenContext[Job])
}
}

View File

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

View File

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

View File

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

View File

@ -1,35 +0,0 @@
package space.kscience.dataforge.properties
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.ObservableMutableMeta
import space.kscience.dataforge.meta.transformations.MetaConverter
import space.kscience.dataforge.meta.transformations.nullableMetaToObject
import space.kscience.dataforge.meta.transformations.nullableObjectToMeta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith
@DFExperimental
public class MetaProperty<T : Any>(
public val meta: ObservableMutableMeta,
public val name: Name,
public val converter: MetaConverter<T>,
) : Property<T?> {
override var value: T?
get() = converter.nullableMetaToObject(meta[name])
set(value) {
meta[name] = converter.nullableObjectToMeta(value) ?: Meta.EMPTY
}
override fun onChange(owner: Any?, callback: (T?) -> Unit) {
meta.onChange(owner) { name ->
if (name.startsWith(this@MetaProperty.name)) callback(converter.nullableMetaToObject(this[name]))
}
}
override fun removeChangeListener(owner: Any?) {
meta.removeListener(owner)
}
}

View File

@ -1,47 +0,0 @@
package space.kscience.dataforge.properties
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import space.kscience.dataforge.misc.DFExperimental
@DFExperimental
public interface Property<T> {
public var value: T
public fun onChange(owner: Any? = null, callback: (T) -> Unit)
public fun removeChangeListener(owner: Any? = null)
}
@DFExperimental
@OptIn(ExperimentalCoroutinesApi::class)
public fun <T> Property<T>.toFlow(): StateFlow<T> = MutableStateFlow(value).also { stateFlow ->
onChange {
stateFlow.value = it
}
}
/**
* Reflect all changes in the [source] property onto this property. Does not reflect changes back.
*
* @return a mirroring job
*/
@DFExperimental
public fun <T> Property<T>.mirror(source: Property<T>) {
source.onChange(this) {
this.value = it
}
}
/**
* Bi-directional connection between properties
*/
@DFExperimental
public fun <T> Property<T>.bind(other: Property<T>) {
onChange(other) {
other.value = it
}
other.onChange {
this.value = it
}
}

View File

@ -0,0 +1,51 @@
package space.kscience.dataforge.properties
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.DFExperimental
@DFExperimental
public fun <T> ObservableMeta.asFlow(converter: MetaReader<T>): Flow<T> = callbackFlow {
onChange(this){
trySend(converter.read(this))
}
awaitClose{
removeListener(this)
}
}
@DFExperimental
public fun <T> MutableMeta.listenTo(
scope: CoroutineScope,
converter: MetaConverter<T>,
flow: Flow<T>,
): Job = flow.onEach {
update(converter.convert(it))
}.launchIn(scope)
@DFExperimental
public fun <T> ObservableMutableMeta.bind(
scope: CoroutineScope,
converter: MetaConverter<T>,
flow: MutableSharedFlow<T>,
): Job = scope.launch{
listenTo(this, converter,flow)
onChange(flow){
launch {
flow.emit(converter.read(this@onChange))
}
}
flow.onCompletion {
removeListener(flow)
}
}.also {
it.invokeOnCompletion {
removeListener(flow)
}
}

View File

@ -1,31 +0,0 @@
package space.kscience.dataforge.properties
import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.parseAsName
import space.kscience.dataforge.names.startsWith
import kotlin.reflect.KMutableProperty1
@DFExperimental
public fun <S : Scheme, T : Any> S.property(property: KMutableProperty1<S, T?>): Property<T?> =
object : Property<T?> {
override var value: T?
get() = property.get(this@property)
set(value) {
property.set(this@property, value)
}
override fun onChange(owner: Any?, callback: (T?) -> Unit) {
this@property.meta.onChange(this) { name ->
if (name.startsWith(property.name.parseAsName(true))) {
callback(property.get(this@property))
}
}
}
override fun removeChangeListener(owner: Any?) {
this@property.meta.removeListener(this@property)
}
}

View File

@ -1,28 +0,0 @@
package space.kscience.dataforge.properties
import space.kscience.dataforge.meta.Scheme
import space.kscience.dataforge.meta.SchemeSpec
import space.kscience.dataforge.meta.int
import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.Test
import kotlin.test.assertEquals
internal class TestScheme : Scheme() {
var a by int()
var b by int()
companion object : SchemeSpec<TestScheme>(::TestScheme)
}
@DFExperimental
class MetaPropertiesTest {
@Test
fun testBinding() {
val scheme = TestScheme.empty()
val a = scheme.property(TestScheme::a)
val b = scheme.property(TestScheme::b)
a.bind(b)
scheme.a = 2
assertEquals(2, scheme.b)
assertEquals(2, b.value)
}
}

View File

@ -1,32 +0,0 @@
package space.kscience.dataforge.properties
import org.w3c.dom.HTMLInputElement
import space.kscience.dataforge.misc.DFExperimental
@DFExperimental
public fun HTMLInputElement.bindValue(property: Property<String>) {
if (this.onchange != null) error("Input element already bound")
this.onchange = {
property.value = this.value
Unit
}
property.onChange(this) {
if (value != it) {
value = it
}
}
}
@DFExperimental
public fun HTMLInputElement.bindChecked(property: Property<Boolean>) {
if (this.onchange != null) error("Input element already bound")
this.onchange = {
property.value = this.checked
Unit
}
property.onChange(this) {
if (checked != it) {
checked = it
}
}
}

View File

@ -1,126 +0,0 @@
/*
* Copyright 2018 Alexander Nozik.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package space.kscience.dataforge.descriptors
//@MustBeDocumented
//annotation class Attribute(
// val key: String,
// val value: String
//)
//
//@MustBeDocumented
//annotation class Attributes(
// val attrs: Array<Attribute>
//)
//
//@MustBeDocumented
//annotation class ItemDef(
// val info: String = "",
// val multiple: Boolean = false,
// val required: Boolean = false
//)
//
//@Target(AnnotationTarget.PROPERTY)
//@MustBeDocumented
//annotation class ValueDef(
// val type: Array<ValueType> = [ValueType.STRING],
// val def: String = "",
// val allowed: Array<String> = [],
// val enumeration: KClass<*> = Any::class
//)
///**
// * Description text for meta property, node or whole object
// */
//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class Description(val value: String)
//
///**
// * Annotation for value property which states that lists are expected
// */
//@Target(AnnotationTarget.PROPERTY)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class Multiple
//
///**
// * Descriptor target
// * The DataForge path to the resource containing the description. Following targets are supported:
// * 1. resource
// * 1. file
// * 1. class
// * 1. method
// * 1. property
// *
// *
// * Does not work if [type] is provided
// */
//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class Descriptor(val value: String)
//
//
///**
// * Aggregator class for descriptor nodes
// */
//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class DescriptorNodes(vararg val nodes: NodeDef)
//
///**
// * Aggregator class for descriptor values
// */
//@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.VALUE_PARAMETER)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class DescriptorValues(vararg val nodes: ValueDef)
//
///**
// * Alternative name for property descriptor declaration
// */
//@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class DescriptorName(val name: String)
//
//@Target(AnnotationTarget.PROPERTY)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class DescriptorValue(val def: ValueDef)
////TODO enter fields directly?
//
//@Target(AnnotationTarget.PROPERTY)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class ValueProperty(
// val name: String = "",
// val type: Array<ValueType> = arrayOf(ValueType.STRING),
// val multiple: Boolean = false,
// val def: String = "",
// val enumeration: KClass<*> = Any::class,
// val tags: Array<String> = emptyArray()
//)
//
//
//@Target(AnnotationTarget.PROPERTY)
//@Retention(AnnotationRetention.RUNTIME)
//@MustBeDocumented
//annotation class NodeProperty(val name: String = "")

View File

@ -1,53 +1,132 @@
package space.kscience.dataforge.descriptors
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.slf4j.LoggerFactory
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.MetaDescriptorBuilder
import space.kscience.dataforge.misc.DFExperimental
import java.net.URL
import kotlin.reflect.KAnnotatedElement
import kotlin.reflect.KProperty
//inline fun <reified T : Scheme> T.buildDescriptor(): NodeDescriptor = NodeDescriptor {
// T::class.apply {
// findAnnotation<ItemDef>()?.let { def ->
// info = def.info
// required = def.required
// multiple = def.multiple
// }
// findAnnotation<Attribute>()?.let { attr ->
// attributes {
// this[attr.key] = attr.value.parseValue()
// }
// }
// findAnnotation<Attributes>()?.attrs?.forEach { attr ->
// attributes {
// this[attr.key] = attr.value.parseValue()
// }
// }
// }
// T::class.memberProperties.forEach { property ->
// val delegate = property.getDelegate(this@buildDescriptor)
/**
* Description text for meta property, node or whole object
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
public annotation class Description(val value: String)
@Target(AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
public annotation class Multiple()
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
public annotation class DescriptorResource(val resourceName: String)
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
public annotation class DescriptorUrl(val url: String)
@OptIn(ExperimentalSerializationApi::class)
private fun MetaDescriptorBuilder.loadDescriptorFromUrl(url: URL) {
url.openStream().use {
from(Json.decodeFromStream(MetaDescriptor.serializer(), it))
}
}
private fun MetaDescriptorBuilder.loadDescriptorFromResource(resource: DescriptorResource) {
val url = {}.javaClass.getResource(resource.resourceName)
if (url != null) {
loadDescriptorFromUrl(url)
} else {
LoggerFactory.getLogger("System")
.error("Can't find descriptor resource with name ${resource.resourceName}")
}
}
@DFExperimental
public fun MetaDescriptorBuilder.forAnnotatedElement(element: KAnnotatedElement) {
element.annotations.forEach {
when (it) {
is Description -> description = it.value
is DescriptorResource -> loadDescriptorFromResource(it)
is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url))
}
}
}
@DFExperimental
public fun MetaDescriptorBuilder.forProperty(property: KProperty<*>) {
property.annotations.forEach {
when (it) {
is Description -> description = it.value
is DescriptorResource -> loadDescriptorFromResource(it)
is DescriptorUrl -> loadDescriptorFromUrl(URL(it.url))
}
}
}
//
// val descriptor: ItemDescriptor = when (delegate) {
// is ConfigurableDelegate -> buildPropertyDescriptor(property, delegate)
// is ReadWriteDelegateWrapper<*, *> -> {
// if (delegate.delegate is ConfigurableDelegate) {
// buildPropertyDescriptor(property, delegate.delegate as ConfigurableDelegate)
// } else {
// return@forEach
//@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))
// }
// }
// }
// else -> return@forEach
// }
// defineItem(property.name, descriptor)
// }
//}
//inline fun <T : Scheme, reified V : Any?> buildPropertyDescriptor(
// property: KProperty1<T, V>,
// delegate: ConfigurableDelegate
//): ItemDescriptor {
// when {
// V::class.isSubclassOf(Scheme::class) -> NodeDescriptor {
// default = delegate.default.node
// }
// V::class.isSubclassOf(Meta::class) -> NodeDescriptor {
// default = delegate.default.node
// }
//
// }
// mod()
//}
//
//@DFExperimental
//public inline fun <reified T : Scheme> SchemeSpec<T>.autoDescriptor(
// noinline mod: MetaDescriptorBuilder.() -> Unit = {},
//): MetaDescriptor = MetaDescriptor.forScheme(this, mod)

View File

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

View File

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

View File

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

View File

@ -6,18 +6,16 @@
## Artifact:
The Maven coordinates of this project are `space.kscience:dataforge-data:0.7.0`.
The Maven coordinates of this project are `space.kscience:dataforge-data:0.8.2`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
//uncomment to access development builds
//maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
mavenCentral()
}
dependencies {
implementation("space.kscience:dataforge-data:0.7.0")
implementation("space.kscience:dataforge-data:0.8.2")
}
```

View File

@ -6,9 +6,12 @@ kscience{
jvm()
js()
native()
wasm()
useCoroutines()
dependencies {
api(project(":dataforge-meta"))
api(spclibs.atomicfu)
api(projects.dataforgeMeta)
//Remove after subtype moved to stdlib
api(kotlin("reflect"))
}
}

View File

@ -1,9 +1,14 @@
package space.kscience.dataforge.actions
import kotlinx.coroutines.launch
import space.kscience.dataforge.data.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.data.DataSink
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.data.DataUpdate
import space.kscience.dataforge.data.launchUpdate
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.startsWith
import kotlin.reflect.KType
@ -19,47 +24,47 @@ internal fun MutableMap<Name, *>.removeWhatStartsWith(name: Name) {
/**
* An action that caches results on-demand and recalculates them on source push
*/
public abstract class AbstractAction<in T : Any, R : Any>(
public abstract class AbstractAction<T, R>(
public val outputType: KType,
) : Action<T, R> {
/**
* Generate initial content of the output
*/
protected abstract fun DataSetBuilder<R>.generate(
data: DataSet<T>,
protected abstract fun DataSink<R>.generate(
source: DataTree<T>,
meta: Meta,
)
/**
* Update part of the data set when given [updateKey] is triggered by the source
* Update part of the data set using provided data
*
* @param source the source data tree in case we need several data items to update
* @param meta the metadata used for the whole data tree
* @param updatedData an updated item
*/
protected open fun DataSourceBuilder<R>.update(
dataSet: DataSet<T>,
protected open suspend fun DataSink<R>.update(
source: DataTree<T>,
meta: Meta,
updateKey: Name,
updatedData: DataUpdate<T>,
) {
// By default, recalculate the whole dataset
generate(dataSet, meta)
//by default regenerate the whole data set
generate(source, meta)
}
@OptIn(DFInternal::class)
@OptIn(UnsafeKType::class)
override fun execute(
dataSet: DataSet<T>,
source: DataTree<T>,
meta: Meta,
): DataSet<R> = if (dataSet is DataSource) {
DataSource(outputType, dataSet){
generate(dataSet, meta)
launch {
dataSet.updates.collect { name ->
update(dataSet, meta, name)
}
}
}
} else {
DataTree<R>(outputType) {
generate(dataSet, meta)
updatesScope: CoroutineScope
): DataTree<R> = DataTree(outputType) {
generate(source, meta)
//propagate updates
launchUpdate(updatesScope) {
source.updates.onEach { update ->
update(source, meta, update)
}.collect()
}
}
}

View File

@ -1,40 +1,50 @@
package space.kscience.dataforge.actions
import space.kscience.dataforge.data.DataSet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import space.kscience.dataforge.data.DataTree
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
/**
* A simple data transformation on a data node. Actions should avoid doing actual dependency evaluation in [execute].
*/
public interface Action<in T : Any, out R : Any> {
public fun interface Action<T, R> {
/**
* Transform the data in the node, producing a new node. By default, it is assumed that all calculations are lazy
* so not actual computation is started at this moment.
*/
public fun execute(dataSet: DataSet<T>, meta: Meta = Meta.EMPTY): DataSet<R>
public fun execute(source: DataTree<T>, meta: Meta, updatesScope: CoroutineScope): DataTree<R>
public companion object
}
/**
* A convenience method to transform data using given [action]
*/
@OptIn(DelicateCoroutinesApi::class)
public fun <T, R> DataTree<T>.transform(
action: Action<T, R>,
meta: Meta = Meta.EMPTY,
updateScope: CoroutineScope = GlobalScope,
): DataTree<R> = action.execute(this, meta, updateScope)
/**
* Action composition. The result is terminal if one of its parts is terminal
*/
public infix fun <T : Any, I : Any, R : Any> Action<T, I>.then(action: Action<I, R>): Action<T, R> {
// TODO introduce composite action and add optimize by adding action to the list
return object : Action<T, R> {
override fun execute(
dataSet: DataSet<T>,
meta: Meta,
): DataSet<R> = action.execute(this@then.execute(dataSet, meta), meta)
}
public infix fun <T, I, R> Action<T, I>.then(action: Action<I, R>): Action<T, R> = Action { dataSet, meta, scope ->
action.execute(this@then.execute(dataSet, meta, scope), meta, scope)
}
@DFExperimental
public operator fun <T : Any, R : Any> Action<T, R>.invoke(
dataSet: DataSet<T>,
@OptIn(DelicateCoroutinesApi::class)
public operator fun <T, R> Action<T, R>.invoke(
dataSet: DataTree<T>,
meta: Meta = Meta.EMPTY,
): DataSet<R> = execute(dataSet, meta)
updateScope: CoroutineScope = GlobalScope,
): DataTree<R> = execute(dataSet, meta, updateScope)

View File

@ -6,8 +6,7 @@ import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name
import kotlin.reflect.KType
import kotlin.reflect.typeOf
@ -29,6 +28,7 @@ public class MapActionBuilder<T, R>(
public var name: Name,
public var meta: MutableMeta,
public val actionMeta: Meta,
public val dataType: KType,
@PublishedApi internal var outputType: KType,
) {
@ -45,19 +45,21 @@ public class MapActionBuilder<T, R>(
/**
* Calculate the result of goal
*/
public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(T) -> R1) {
outputType = typeOf<R1>()
result = f;
}
public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(T) -> R1): Unit = result(typeOf<R1>(), f)
}
@PublishedApi
internal class MapAction<in T : Any, R : Any>(
@UnsafeKType
public class MapAction<T, R>(
outputType: KType,
private val block: MapActionBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) {
private fun DataSetBuilder<R>.mapOne(name: Name, data: Data<T>, meta: Meta) {
private fun DataSink<R>.mapOne(name: Name, data: Data<T>?, meta: Meta) {
//fast return for null data
if (data == null) {
put(name, null)
return
}
// Creating a new environment for action using **old** name, old meta and task meta
val env = ActionEnv(name, data.meta, meta)
@ -66,6 +68,7 @@ internal class MapAction<in T : Any, R : Any>(
name,
data.meta.toMutableMeta(), // using data meta
meta,
data.type,
outputType
).apply(block)
@ -75,21 +78,25 @@ internal class MapAction<in T : Any, R : Any>(
//getting new meta
val newMeta = builder.meta.seal()
@OptIn(DFInternal::class)
val newData = Data(builder.outputType, newMeta, dependencies = listOf(data)) {
builder.result(env, data.await())
}
//setting the data node
data(newName, newData)
put(newName, newData)
}
override fun DataSetBuilder<R>.generate(data: DataSet<T>, meta: Meta) {
data.forEach { mapOne(it.name, it.data, meta) }
override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
source.forEach { mapOne(it.name, it.data, meta) }
}
override fun DataSourceBuilder<R>.update(dataSet: DataSet<T>, meta: Meta, updateKey: Name) {
remove(updateKey)
dataSet[updateKey]?.let { mapOne(updateKey, it, meta) }
override suspend fun DataSink<R>.update(
source: DataTree<T>,
meta: Meta,
updatedData: DataUpdate<T>,
) {
mapOne(updatedData.name, updatedData.data, meta)
}
}
@ -97,9 +104,9 @@ internal class MapAction<in T : Any, R : Any>(
/**
* A one-to-one mapping action
*/
@DFExperimental
@Suppress("FunctionName")
public inline fun <T : Any, reified R : Any> Action.Companion.map(
@OptIn(UnsafeKType::class)
public inline fun <T, reified R> Action.Companion.mapping(
noinline builder: MapActionBuilder<T, R>.() -> Unit,
): Action<T, R> = MapAction(typeOf<R>(), builder)

View File

@ -4,17 +4,16 @@ import space.kscience.dataforge.data.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFBuilder
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class JoinGroup<T : Any, R : Any>(
public class JoinGroup<T, R>(
public var name: String,
internal val set: DataSet<T>,
internal val set: DataTree<T>,
@PublishedApi internal var outputType: KType,
) {
@ -22,12 +21,12 @@ public class JoinGroup<T : Any, R : Any>(
public lateinit var result: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R
internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) {
internal fun <R1 : R> result(outputType: KType, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) {
this.outputType = outputType
this.result = f;
}
public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) {
public inline fun <reified R1 : R> result(noinline f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R1) {
outputType = typeOf<R1>()
this.result = f;
}
@ -35,11 +34,11 @@ public class JoinGroup<T : Any, R : Any>(
}
@DFBuilder
public class ReduceGroupBuilder<T : Any, R : Any>(
public class ReduceGroupBuilder<T, R>(
public val actionMeta: Meta,
private val outputType: KType,
) {
private val groupRules: MutableList<(DataSet<T>) -> List<JoinGroup<T, R>>> = ArrayList();
private val groupRules: MutableList<(DataTree<T>) -> List<JoinGroup<T, R>>> = ArrayList();
/**
* introduce grouping by meta value
@ -54,12 +53,12 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
public fun group(
groupName: String,
predicate: (Name, Meta) -> Boolean,
predicate: DataFilter,
action: JoinGroup<T, R>.() -> Unit,
) {
groupRules += { source ->
listOf(
JoinGroup<T, R>(groupName, source.filter(predicate), outputType).apply(action)
JoinGroup<T, R>(groupName, source.filterData(predicate), outputType).apply(action)
)
}
}
@ -67,26 +66,26 @@ public class ReduceGroupBuilder<T : Any, R : Any>(
/**
* Apply transformation to the whole node
*/
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R) {
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, ValueWithMeta<T>>) -> R) {
groupRules += { node ->
listOf(JoinGroup<T, R>(resultName, node, outputType).apply { result(outputType, f) })
}
}
internal fun buildGroups(input: DataSet<T>): List<JoinGroup<T, R>> =
internal fun buildGroups(input: DataTree<T>): List<JoinGroup<T, R>> =
groupRules.flatMap { it.invoke(input) }
}
@PublishedApi
internal class ReduceAction<T : Any, R : Any>(
internal class ReduceAction<T, R>(
outputType: KType,
private val action: ReduceGroupBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) {
//TODO optimize reduction. Currently, the whole action recalculates on push
override fun DataSetBuilder<R>.generate(data: DataSet<T>, meta: Meta) {
ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(data).forEach { group ->
override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
ReduceGroupBuilder<T, R>(meta, outputType).apply(action).buildGroups(source).forEach { group ->
val dataFlow: Map<Name, Data<T>> = group.set.asSequence().fold(HashMap()) { acc, value ->
acc.apply {
acc[value.name] = value.data
@ -98,12 +97,12 @@ internal class ReduceAction<T : Any, R : Any>(
val groupMeta = group.meta
val env = ActionEnv(groupName.parseAsName(), groupMeta, meta)
@OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData(
@OptIn(UnsafeKType::class) val res: Data<R> = dataFlow.reduceToData(
group.outputType,
meta = groupMeta
) { group.result.invoke(env, it) }
data(env.name, res)
put(env.name, res)
}
}
}
@ -111,7 +110,6 @@ internal class ReduceAction<T : Any, R : Any>(
/**
* A one-to-one mapping action
*/
@DFExperimental
public inline fun <reified T : Any, reified R : Any> Action.Companion.reduce(
public inline fun <reified T, reified R> Action.Companion.reducing(
noinline builder: ReduceGroupBuilder<T, R>.() -> Unit,
): Action<T, R> = ReduceAction(typeOf<R>(), builder)

View File

@ -5,7 +5,6 @@ import space.kscience.dataforge.meta.Laminate
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.parseAsName
import kotlin.collections.set
@ -13,9 +12,9 @@ import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) {
public class SplitBuilder<T, R>(public val name: Name, public val meta: Meta) {
public class FragmentRule<T : Any, R : Any>(
public class FragmentRule<T, R>(
public val name: Name,
public var meta: MutableMeta,
@PublishedApi internal var outputType: KType,
@ -44,15 +43,15 @@ public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val me
* Action that splits each incoming element into a number of fragments defined in builder
*/
@PublishedApi
internal class SplitAction<T : Any, R : Any>(
internal class SplitAction<T, R>(
outputType: KType,
private val action: SplitBuilder<T, R>.() -> Unit,
) : AbstractAction<T, R>(outputType) {
private fun DataSetBuilder<R>.splitOne(name: Name, data: Data<T>, meta: Meta) {
val laminate = Laminate(data.meta, meta)
private fun DataSink<R>.splitOne(name: Name, data: Data<T>?, meta: Meta) {
val laminate = Laminate(data?.meta, meta)
val split = SplitBuilder<T, R>(name, data.meta).apply(action)
val split = SplitBuilder<T, R>(name, data?.meta ?: Meta.EMPTY).apply(action)
// apply individual fragment rules to result
@ -64,29 +63,36 @@ internal class SplitAction<T : Any, R : Any>(
).apply(rule)
//data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
data(
fragmentName,
@Suppress("OPT_IN_USAGE") Data(outputType, meta = env.meta, dependencies = listOf(data)) {
env.result(data.await())
}
)
if (data == null) {
put(fragmentName, null)
} else {
put(
fragmentName,
@Suppress("OPT_IN_USAGE") Data(outputType, meta = env.meta, dependencies = listOf(data)) {
env.result(data.await())
}
)
}
}
}
override fun DataSetBuilder<R>.generate(data: DataSet<T>, meta: Meta) {
data.forEach { splitOne(it.name, it.data, meta) }
override fun DataSink<R>.generate(source: DataTree<T>, meta: Meta) {
source.forEach { splitOne(it.name, it.data, meta) }
}
override fun DataSourceBuilder<R>.update(dataSet: DataSet<T>, meta: Meta, updateKey: Name) {
remove(updateKey)
dataSet[updateKey]?.let { splitOne(updateKey, it, meta) }
override suspend fun DataSink<R>.update(
source: DataTree<T>,
meta: Meta,
updatedData: DataUpdate<T>,
) {
splitOne(updatedData.name, updatedData.data, meta)
}
}
/**
* Action that splits each incoming element into a number of fragments defined in builder
*/
@DFExperimental
public inline fun <T : Any, reified R : Any> Action.Companion.split(
public inline fun <T, reified R> Action.Companion.splitting(
noinline builder: SplitBuilder<T, R>.() -> Unit,
): Action<T, R> = SplitAction(typeOf<R>(), builder)

View File

@ -4,8 +4,8 @@ import kotlinx.coroutines.*
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MetaRepr
import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.misc.UnsafeKType
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
@ -14,7 +14,7 @@ import kotlin.reflect.typeOf
/**
* A data element characterized by its meta
*/
@DfId(Data.TYPE)
@DfType(Data.TYPE)
public interface Data<out T> : Goal<T>, MetaRepr {
/**
* Type marker for the data. The type is known before the calculation takes place so it could be checked.
@ -41,7 +41,7 @@ public interface Data<out T> : Goal<T>, MetaRepr {
*/
internal val TYPE_OF_NOTHING: KType = typeOf<Unit>()
public inline fun <reified T : Any> static(
public inline fun <reified T> wrapValue(
value: T,
meta: Meta = Meta.EMPTY,
): Data<T> = StaticData(typeOf<T>(), value, meta)
@ -50,10 +50,10 @@ public interface Data<out T> : Goal<T>, MetaRepr {
* An empty data containing only meta
*/
@OptIn(DelicateCoroutinesApi::class)
public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
override val type: KType = TYPE_OF_NOTHING
public fun buildEmpty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
override val type: KType get() = TYPE_OF_NOTHING
override val meta: Meta = meta
override val dependencies: Collection<Goal<*>> = emptyList()
override val dependencies: Collection<Goal<*>> get() = emptyList()
override val deferred: Deferred<Nothing>
get() = GlobalScope.async(start = CoroutineStart.LAZY) {
error("The Data is empty and could not be computed")
@ -62,6 +62,8 @@ public interface Data<out T> : Goal<T>, MetaRepr {
override fun async(coroutineScope: CoroutineScope): Deferred<Nothing> = deferred
override fun reset() {}
}
public val EMPTY: Data<Nothing> = buildEmpty(Meta.EMPTY)
}
}
@ -69,39 +71,37 @@ public interface Data<out T> : Goal<T>, MetaRepr {
* A lazily computed variant of [Data] based on [LazyGoal]
* One must ensure that proper [type] is used so this method should not be used
*/
private class LazyData<T : Any>(
private class LazyData<T>(
override val type: KType,
override val meta: Meta = Meta.EMPTY,
additionalContext: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Goal<*>> = emptyList(),
dependencies: Iterable<Goal<*>> = emptyList(),
block: suspend () -> T,
) : Data<T>, LazyGoal<T>(additionalContext, dependencies, block)
public class StaticData<T : Any>(
public class StaticData<T>(
override val type: KType,
value: T,
override val meta: Meta = Meta.EMPTY,
) : Data<T>, StaticGoal<T>(value)
@Suppress("FunctionName")
public inline fun <reified T : Any> 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)
@Suppress("FunctionName")
@DFInternal
public fun <T : Any> Data(
@UnsafeKType
public fun <T> Data(
type: KType,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Goal<*>> = emptyList(),
dependencies: Iterable<Goal<*>> = emptyList(),
block: suspend () -> T,
): Data<T> = LazyData(type, meta, context, dependencies, block)
@OptIn(DFInternal::class)
@Suppress("FunctionName")
public inline fun <reified T : Any> Data(
@OptIn(UnsafeKType::class)
public inline fun <reified T> Data(
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Goal<*>> = emptyList(),
dependencies: Iterable<Goal<*>> = emptyList(),
noinline block: suspend () -> T,
): Data<T> = Data(typeOf<T>(), meta, context, dependencies, block)

View File

@ -0,0 +1,110 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.names.plus
import kotlin.reflect.KType
public fun interface DataFilter {
public fun accepts(name: Name, meta: Meta?, type: KType): Boolean
public companion object {
public val EMPTY: DataFilter = DataFilter { _, _, _ -> true }
}
}
public fun DataFilter.accepts(update: DataUpdate<*>): Boolean = accepts(update.name, update.data?.meta, update.type)
public fun <T, DU : DataUpdate<T>> Sequence<DU>.filterData(predicate: DataFilter): Sequence<DU> = filter { data ->
predicate.accepts(data)
}
public fun <T, DU : DataUpdate<T>> Flow<DU>.filterData(predicate: DataFilter): Flow<DU> = filter { data ->
predicate.accepts(data)
}
public fun <T> DataSource<T>.filterData(
predicate: DataFilter,
): DataSource<T> = object : DataSource<T> {
override val dataType: KType get() = this@filterData.dataType
override fun read(name: Name): Data<T>? =
this@filterData.read(name)?.takeIf { predicate.accepts(name, it.meta, it.type) }
}
/**
* Stateless filtered [ObservableDataSource]
*/
public fun <T> ObservableDataSource<T>.filterData(
predicate: DataFilter,
): ObservableDataSource<T> = object : ObservableDataSource<T> {
override val updates: Flow<DataUpdate<T>>
get() = this@filterData.updates.filter { predicate.accepts(it) }
override val dataType: KType get() = this@filterData.dataType
override fun read(name: Name): Data<T>? =
this@filterData.read(name)?.takeIf { predicate.accepts(name, it.meta, it.type) }
}
internal class FilteredDataTree<T>(
val source: DataTree<T>,
val filter: DataFilter,
val branch: Name,
override val dataType: KType = source.dataType,
) : DataTree<T> {
override val data: Data<T>?
get() = source[branch].takeIf {
filter.accepts(Name.EMPTY, it?.meta, it?.type ?: dataType)
}
override val items: Map<NameToken, DataTree<T>>
get() = source.branch(branch)?.items
?.mapValues { FilteredDataTree(source, filter, branch + it.key) }
?.filter { !it.value.isEmpty() }
?: emptyMap()
override val updates: Flow<DataUpdate<T>>
get() = source.updates.filter { filter.accepts(it) }
}
public fun <T> DataTree<T>.filterData(
predicate: DataFilter,
): DataTree<T> = FilteredDataTree(this, predicate, Name.EMPTY)
///**
// * Generate a wrapper data set with a given name prefix appended to all names
// */
//public fun <T : Any> DataTree<T>.withNamePrefix(prefix: Name): DataSet<T> = if (prefix.isEmpty()) {
// this
//} else object : DataSource<T> {
//
// override val dataType: KType get() = this@withNamePrefix.dataType
//
// override val coroutineContext: CoroutineContext
// get() = (this@withNamePrefix as? DataSource)?.coroutineContext ?: EmptyCoroutineContext
//
// override val meta: Meta get() = this@withNamePrefix.meta
//
//
// override fun iterator(): Iterator<NamedData<T>> = iterator {
// for (d in this@withNamePrefix) {
// yield(d.data.named(prefix + d.name))
// }
// }
//
// override fun get(name: Name): Data<T>? =
// name.removeFirstOrNull(name)?.let { this@withNamePrefix.get(it) }
//
// override val updates: Flow<Name> get() = this@withNamePrefix.updates.map { prefix + it }
//}
//

View File

@ -1,124 +0,0 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.mapNotNull
import space.kscience.dataforge.data.Data.Companion.TYPE_OF_NOTHING
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.endsWith
import space.kscience.dataforge.names.parseAsName
import kotlin.reflect.KType
public interface DataSet<out T : Any> {
/**
* The minimal common ancestor to all data in the node
*/
public val dataType: KType
/**
* Meta-data associated with this node. If no meta is provided, returns [Meta.EMPTY].
*/
public val meta: Meta
/**
* Traverse this [DataSet] returning named data instances. The order is not guaranteed.
*/
public operator fun iterator(): Iterator<NamedData<T>>
/**
* Get data with given name.
*/
public operator fun get(name: Name): Data<T>?
public companion object {
public val META_KEY: Name = "@meta".asName()
/**
* An empty [DataSet] that suits all types
*/
public val EMPTY: DataSet<Nothing> = object : DataSet<Nothing> {
override val dataType: KType = TYPE_OF_NOTHING
override val meta: Meta get() = Meta.EMPTY
override fun iterator(): Iterator<NamedData<Nothing>> = emptySequence<NamedData<Nothing>>().iterator()
override fun get(name: Name): Data<Nothing>? = null
}
}
}
public fun <T : Any> DataSet<T>.asSequence(): Sequence<NamedData<T>> = object : Sequence<NamedData<T>> {
override fun iterator(): Iterator<NamedData<T>> = this@asSequence.iterator()
}
/**
* Return a single [Data] in this [DataSet]. Throw error if it is not single.
*/
public fun <T : Any> DataSet<T>.single(): NamedData<T> = asSequence().single()
public fun <T : Any> DataSet<T>.asIterable(): Iterable<NamedData<T>> = object : Iterable<NamedData<T>> {
override fun iterator(): Iterator<NamedData<T>> = this@asIterable.iterator()
}
public operator fun <T : Any> DataSet<T>.get(name: String): Data<T>? = get(name.parseAsName())
/**
* A [DataSet] with propagated updates.
*/
public interface DataSource<out T : Any> : DataSet<T>, CoroutineScope {
/**
* A flow of updated item names. Updates are propagated in a form of [Flow] of names of updated nodes.
* Those can include new data items and replacement of existing ones. The replaced items could update existing data content
* and replace it completely, so they should be pulled again.
*
*/
public val updates: Flow<Name>
/**
* Stop generating updates from this [DataSource]
*/
public fun close() {
coroutineContext[Job]?.cancel()
}
}
public val <T : Any> DataSet<T>.updates: Flow<Name> get() = if (this is DataSource) updates else emptyFlow()
//
///**
// * Flow all data nodes with names starting with [branchName]
// */
//public fun <T : Any> DataSet<T>.children(branchName: Name): Sequence<NamedData<T>> =
// this@children.asSequence().filter {
// it.name.startsWith(branchName)
// }
/**
* Start computation for all goals in data node and return a job for the whole node
*/
public fun <T : Any> DataSet<T>.startAll(coroutineScope: CoroutineScope): Job = coroutineScope.launch {
asIterable().map {
it.launch(this@launch)
}.joinAll()
}
public suspend fun <T : Any> DataSet<T>.computeAndJoinAll(): Unit = coroutineScope { startAll(this).join() }
public fun DataSet<*>.toMeta(): Meta = Meta {
forEach {
if (it.name.endsWith(DataSet.META_KEY)) {
set(it.name, it.meta)
} else {
it.name put {
"type" put it.type.toString()
"meta" put it.meta
}
}
}
}
public val <T : Any> DataSet<T>.updatesWithData: Flow<NamedData<T>> get() = updates.mapNotNull { get(it)?.named(it) }

View File

@ -1,165 +0,0 @@
package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.isEmpty
import space.kscience.dataforge.names.plus
import kotlin.reflect.KType
public interface DataSetBuilder<in T : Any> {
public val dataType: KType
/**
* Remove all data items starting with [name]
*/
public fun remove(name: Name)
public fun data(name: Name, data: Data<T>?)
/**
* Set a current state of given [dataSet] into a branch [name]. Does not propagate updates
*/
public fun node(name: Name, dataSet: DataSet<T>) {
//remove previous items
if (name != Name.EMPTY) {
remove(name)
}
//Set new items
dataSet.forEach {
data(name + it.name, it.data)
}
}
/**
* Set meta for the given node
*/
public fun meta(name: Name, meta: Meta)
}
/**
* Define meta in this [DataSet]
*/
public fun <T : Any> DataSetBuilder<T>.meta(value: Meta): Unit = meta(Name.EMPTY, value)
/**
* Define meta in this [DataSet]
*/
public fun <T : Any> DataSetBuilder<T>.meta(mutableMeta: MutableMeta.() -> Unit): Unit = meta(Meta(mutableMeta))
@PublishedApi
internal class SubSetBuilder<in T : Any>(
private val parent: DataSetBuilder<T>,
private val branch: Name,
) : DataSetBuilder<T> {
override val dataType: KType get() = parent.dataType
override fun remove(name: Name) {
parent.remove(branch + name)
}
override fun data(name: Name, data: Data<T>?) {
parent.data(branch + name, data)
}
override fun node(name: Name, dataSet: DataSet<T>) {
parent.node(branch + name, dataSet)
}
override fun meta(name: Name, meta: Meta) {
parent.meta(branch + name, meta)
}
}
public inline fun <T : Any> DataSetBuilder<T>.node(
name: Name,
crossinline block: DataSetBuilder<T>.() -> Unit,
) {
if (name.isEmpty()) block() else SubSetBuilder(this, name).block()
}
public fun <T : Any> DataSetBuilder<T>.data(name: String, value: Data<T>) {
data(Name.parse(name), value)
}
public fun <T : Any> DataSetBuilder<T>.node(name: String, set: DataSet<T>) {
node(Name.parse(name), set)
}
public inline fun <T : Any> DataSetBuilder<T>.node(
name: String,
crossinline block: DataSetBuilder<T>.() -> Unit,
): Unit = node(Name.parse(name), block)
public fun <T : Any> DataSetBuilder<T>.set(value: NamedData<T>) {
data(value.name, value.data)
}
/**
* Produce lazy [Data] and emit it into the [DataSetBuilder]
*/
public inline fun <reified T : Any> DataSetBuilder<T>.produce(
name: String,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
data(name, data)
}
public inline fun <reified T : Any> DataSetBuilder<T>.produce(
name: Name,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
data(name, data)
}
/**
* Emit a static data with the fixed value
*/
public inline fun <reified T : Any> DataSetBuilder<T>.static(
name: String,
data: T,
meta: Meta = Meta.EMPTY,
): Unit = data(name, Data.static(data, meta))
public inline fun <reified T : Any> DataSetBuilder<T>.static(
name: Name,
data: T,
meta: Meta = Meta.EMPTY,
): Unit = data(name, Data.static(data, meta))
public inline fun <reified T : Any> DataSetBuilder<T>.static(
name: String,
data: T,
mutableMeta: MutableMeta.() -> Unit,
): Unit = data(Name.parse(name), Data.static(data, Meta(mutableMeta)))
/**
* Update data with given node data and meta with node meta.
*/
@DFExperimental
public fun <T : Any> DataSetBuilder<T>.populateFrom(tree: DataSet<T>): Unit {
tree.forEach {
//TODO check if the place is occupied
data(it.name, it.data)
}
}
//public fun <T : Any> DataSetBuilder<T>.populateFrom(flow: Flow<NamedData<T>>) {
// flow.collect {
// data(it.name, it.data)
// }
//}
public fun <T : Any> DataSetBuilder<T>.populateFrom(sequence: Sequence<NamedData<T>>) {
sequence.forEach {
data(it.name, it.data)
}
}

View File

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

View File

@ -0,0 +1,131 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.names.*
import kotlin.contracts.contract
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A generic data provider
*/
public interface DataSource<out T> {
/**
* The minimal common ancestor to all data in the node
*/
public val dataType: KType
/**
* Get data with given name. Or null if it is not present
*/
public fun read(name: Name): Data<T>?
}
/**
* A data provider with possible dynamic updates
*/
public interface ObservableDataSource<out T> : DataSource<T> {
/**
* Flow updates made to the data
*/
public val updates: Flow<DataUpdate<T>>
}
/**
* A tree like structure for data holding
*/
public interface DataTree<out T> : ObservableDataSource<T> {
public val data: Data<T>?
public val items: Map<NameToken, DataTree<T>>
override fun read(name: Name): Data<T>? = when (name.length) {
0 -> data
else -> items[name.first()]?.read(name.cutFirst())
}
/**
* Flow updates made to the data
*/
override val updates: Flow<DataUpdate<T>>
public companion object {
private object EmptyDataTree :
DataTree<Nothing> {
override val data: Data<Nothing>? = null
override val items: Map<NameToken, EmptyDataTree> = emptyMap()
override val dataType: KType = typeOf<Unit>()
override fun read(name: Name): Data<Nothing>? = null
override val updates: Flow<DataUpdate<Nothing>> get() = emptyFlow()
}
public val EMPTY: DataTree<Nothing> = EmptyDataTree
}
}
/**
* An alias for easier access to tree values
*/
public operator fun <T> DataTree<T>.get(name: Name): Data<T>? = read(name)
public operator fun <T> DataTree<T>.get(name: String): Data<T>? = read(name.parseAsName())
/**
* Return a sequence of all data items in this tree.
* This method does not take updates into account.
*/
public fun <T> DataTree<T>.asSequence(
namePrefix: Name = Name.EMPTY,
): Sequence<NamedData<T>> = sequence {
data?.let { yield(it.named(namePrefix)) }
items.forEach { (token, tree) ->
yieldAll(tree.asSequence(namePrefix + token))
}
}
/**
* Walk the data tree depth-first.
*
* @return a [Sequence] of pairs [Name]-[DataTree] for all nodes including the root one.
*/
public fun <T> DataTree<T>.walk(
namePrefix: Name = Name.EMPTY,
): Sequence<Pair<Name, DataTree<T>>> = sequence {
yield(namePrefix to this@walk)
items.forEach { (token, tree) ->
yieldAll(tree.walk(namePrefix + token))
}
}
public val DataTree<*>.meta: Meta? get() = data?.meta
/**
* Provide subtree if it exists
*/
public tailrec fun <T> DataTree<T>.branch(name: Name): DataTree<T>? =
when (name.length) {
0 -> this
1 -> items[name.first()]
else -> items[name.first()]?.branch(name.cutFirst())
}
public fun <T> DataTree<T>.branch(name: String): DataTree<T>? =
branch(name.parseAsName())
public fun DataTree<*>.isEmpty(): Boolean = data == null && items.isEmpty()
/**
* Check if the [DataTree] is observable
*/
public fun <T> DataSource<T>.isObservable(): Boolean {
contract {
returns(true) implies (this@isObservable is ObservableDataSource<T>)
}
return this is ObservableDataSource<T>
}

View File

@ -1,119 +0,0 @@
package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.names.*
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public sealed class DataTreeItem<out T : Any> {
public abstract val meta: Meta
public class Node<out T : Any>(public val tree: DataTree<T>) : DataTreeItem<T>() {
override val meta: Meta get() = tree.meta
}
public class Leaf<out T : Any>(public val data: Data<T>) : DataTreeItem<T>() {
override val meta: Meta get() = data.meta
}
}
public val <T : Any> DataTreeItem<T>.type: KType
get() = when (this) {
is DataTreeItem.Node -> tree.dataType
is DataTreeItem.Leaf -> data.type
}
/**
* A tree-like [DataSet] grouped into the node. All data inside the node must inherit its type
*/
@DfId(DataTree.TYPE)
public interface DataTree<out T : Any> : DataSet<T> {
/**
* Top-level children items of this [DataTree]
*/
public val items: Map<NameToken, DataTreeItem<T>>
override val meta: Meta get() = items[META_ITEM_NAME_TOKEN]?.meta ?: Meta.EMPTY
override fun iterator(): Iterator<NamedData<T>> = iterator {
items.forEach { (token, childItem: DataTreeItem<T>) ->
if (!token.body.startsWith("@")) {
when (childItem) {
is DataTreeItem.Leaf -> yield(childItem.data.named(token.asName()))
is DataTreeItem.Node -> yieldAll(childItem.tree.asSequence().map { it.named(token + it.name) })
}
}
}
}
override fun get(name: Name): Data<T>? = when (name.length) {
0 -> null
1 -> items[name.firstOrNull()!!].data
else -> items[name.firstOrNull()!!].tree?.get(name.cutFirst())
}
public companion object {
public const val TYPE: String = "dataTree"
/**
* A name token used to designate tree node meta
*/
public val META_ITEM_NAME_TOKEN: NameToken = NameToken("@meta")
@DFInternal
public fun <T : Any> emptyWithType(type: KType, meta: Meta = Meta.EMPTY): DataTree<T> = object : DataTree<T> {
override val items: Map<NameToken, DataTreeItem<T>> get() = emptyMap()
override val dataType: KType get() = type
override val meta: Meta get() = meta
}
@OptIn(DFInternal::class)
public inline fun <reified T : Any> empty(meta: Meta = Meta.EMPTY): DataTree<T> =
emptyWithType<T>(typeOf<T>(), meta)
}
}
public fun <T : Any> DataTree<T>.listChildren(prefix: Name): List<Name> =
getItem(prefix).tree?.items?.keys?.map { prefix + it } ?: emptyList()
/**
* Get a [DataTreeItem] with given [name] or null if the item does not exist
*/
public tailrec fun <T : Any> DataTree<T>.getItem(name: Name): DataTreeItem<T>? = when (name.length) {
0 -> DataTreeItem.Node(this)
1 -> items[name.firstOrNull()]
else -> items[name.firstOrNull()!!].tree?.getItem(name.cutFirst())
}
public val <T : Any> DataTreeItem<T>?.tree: DataTree<T>? get() = (this as? DataTreeItem.Node<T>)?.tree
public val <T : Any> DataTreeItem<T>?.data: Data<T>? get() = (this as? DataTreeItem.Leaf<T>)?.data
/**
* A [Sequence] of all children including nodes
*/
public fun <T : Any> DataTree<T>.traverseItems(): Sequence<Pair<Name, DataTreeItem<T>>> = sequence {
items.forEach { (head, item) ->
yield(head.asName() to item)
if (item is DataTreeItem.Node) {
val subSequence = item.tree.traverseItems()
.map { (name, data) -> (head.asName() + name) to data }
yieldAll(subSequence)
}
}
}
/**
* Get a branch of this [DataTree] with a given [branchName].
* The difference from similar method for [DataSet] is that internal logic is more simple and the return value is a [DataTree]
*/
@OptIn(DFInternal::class)
public fun <T : Any> DataTree<T>.branch(branchName: Name): DataTree<T> =
getItem(branchName)?.tree ?: DataTree.emptyWithType(dataType)
public fun <T : Any> DataTree<T>.branch(branchName: String): DataTree<T> = branch(branchName.parseAsName())

View File

@ -1,127 +0,0 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.*
import kotlin.collections.set
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public interface DataSourceBuilder<T : Any> : DataSetBuilder<T>, DataSource<T> {
override val updates: MutableSharedFlow<Name>
}
/**
* A mutable [DataTree] that propagates updates
*/
public class DataTreeBuilder<T : Any>(
override val dataType: KType,
coroutineContext: CoroutineContext,
) : DataTree<T>, DataSourceBuilder<T> {
override val coroutineContext: CoroutineContext =
coroutineContext + Job(coroutineContext[Job]) + GoalExecutionRestriction()
private val treeItems = HashMap<NameToken, DataTreeItem<T>>()
override val items: Map<NameToken, DataTreeItem<T>>
get() = treeItems.filter { !it.key.body.startsWith("@") }
override val updates: MutableSharedFlow<Name> = MutableSharedFlow<Name>()
@ThreadSafe
private fun remove(token: NameToken) {
if (treeItems.remove(token) != null) {
launch {
updates.emit(token.asName())
}
}
}
override fun remove(name: Name) {
if (name.isEmpty()) error("Can't remove the root node")
(getItem(name.cutLast()).tree as? DataTreeBuilder)?.remove(name.lastOrNull()!!)
}
@ThreadSafe
private fun set(token: NameToken, data: Data<T>) {
treeItems[token] = DataTreeItem.Leaf(data)
}
@ThreadSafe
private fun set(token: NameToken, node: DataTree<T>) {
treeItems[token] = DataTreeItem.Node(node)
}
private fun getOrCreateNode(token: NameToken): DataTreeBuilder<T> =
(treeItems[token] as? DataTreeItem.Node<T>)?.tree as? DataTreeBuilder<T>
?: DataTreeBuilder<T>(dataType, coroutineContext).also { set(token, it) }
private fun getOrCreateNode(name: Name): DataTreeBuilder<T> = when (name.length) {
0 -> this
1 -> getOrCreateNode(name.firstOrNull()!!)
else -> getOrCreateNode(name.firstOrNull()!!).getOrCreateNode(name.cutFirst())
}
override fun data(name: Name, data: Data<T>?) {
if (data == null) {
remove(name)
} else {
when (name.length) {
0 -> error("Can't add data with empty name")
1 -> set(name.firstOrNull()!!, data)
2 -> getOrCreateNode(name.cutLast()).set(name.lastOrNull()!!, data)
}
}
launch {
updates.emit(name)
}
}
override fun meta(name: Name, meta: Meta) {
val item = getItem(name)
if (item is DataTreeItem.Leaf) error("TODO: Can't change meta of existing leaf item.")
data(name + DataTree.META_ITEM_NAME_TOKEN, Data.empty(meta))
}
}
/**
* Create a dynamic [DataSource]. Initial data is placed synchronously.
*/
@DFInternal
@Suppress("FunctionName")
public fun <T : Any> DataSource(
type: KType,
parent: CoroutineScope,
block: DataSourceBuilder<T>.() -> Unit,
): DataTreeBuilder<T> = DataTreeBuilder<T>(type, parent.coroutineContext).apply(block)
@Suppress("OPT_IN_USAGE", "FunctionName")
public inline fun <reified T : Any> DataSource(
parent: CoroutineScope,
crossinline block: DataSourceBuilder<T>.() -> Unit,
): DataTreeBuilder<T> = DataSource(typeOf<T>(), parent) { block() }
@Suppress("FunctionName")
public suspend inline fun <reified T : Any> DataSource(
crossinline block: DataSourceBuilder<T>.() -> Unit = {},
): DataTreeBuilder<T> = DataTreeBuilder<T>(typeOf<T>(), coroutineContext).apply { block() }
public inline fun <reified T : Any> DataSourceBuilder<T>.emit(
name: Name,
parent: CoroutineScope,
noinline block: DataSourceBuilder<T>.() -> Unit,
): Unit = node(name, DataSource(parent, block))
public inline fun <reified T : Any> DataSourceBuilder<T>.emit(
name: String,
parent: CoroutineScope,
noinline block: DataSourceBuilder<T>.() -> Unit,
): Unit = node(Name.parse(name), DataSource(parent, block))

View File

@ -9,7 +9,7 @@ import kotlin.coroutines.EmptyCoroutineContext
* Lazy computation result with its dependencies to allowing to stat computing dependencies ahead of time
*/
public interface Goal<out T> {
public val dependencies: Collection<Goal<*>>
public val dependencies: Iterable<Goal<*>>
/**
* Returns current running coroutine if the goal is started. Null if the computation is not started.
@ -54,7 +54,7 @@ public open class StaticGoal<T>(public val value: T) : Goal<T> {
*/
public open class LazyGoal<T>(
private val coroutineContext: CoroutineContext = EmptyCoroutineContext,
override val dependencies: Collection<Goal<*>> = emptyList(),
override val dependencies: Iterable<Goal<*>> = emptyList(),
public val block: suspend () -> T,
) : Goal<T> {
@ -82,8 +82,8 @@ public open class LazyGoal<T>(
}
log?.emit { "Starting dependencies computation for ${this@LazyGoal}" }
val startedDependencies = this.dependencies.map { goal ->
goal.run { async(coroutineScope) }
val startedDependencies = dependencies.map { goal ->
goal.async(coroutineScope)
}
return deferred ?: coroutineScope.async(
coroutineContext

View File

@ -15,13 +15,12 @@
*/
package space.kscience.dataforge.data
import kotlinx.coroutines.launch
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.UnsafeKType
public interface GroupRule {
public fun <T : Any> gather(set: DataSet<T>): Map<String, DataSet<T>>
public fun <T> gather(set: DataTree<T>): Map<String, DataTree<T>>
public companion object {
/**
@ -32,42 +31,20 @@ public interface GroupRule {
* @param defaultTagValue
* @return
*/
@OptIn(DFInternal::class)
@OptIn(UnsafeKType::class)
public fun byMetaValue(
key: String,
defaultTagValue: String,
): GroupRule = object : GroupRule {
override fun <T : Any> gather(
set: DataSet<T>,
): Map<String, DataSet<T>> {
val map = HashMap<String, DataSet<T>>()
override fun <T> gather(
set: DataTree<T>,
): Map<String, DataTree<T>> {
val map = HashMap<String, MutableDataTree<T>>()
if (set is DataSource) {
set.forEach { data ->
val tagValue: String = data.meta[key]?.string ?: defaultTagValue
(map.getOrPut(tagValue) { DataTreeBuilder(set.dataType, set.coroutineContext) } as DataTreeBuilder<T>)
.data(data.name, data.data)
set.launch {
set.updates.collect { name ->
val dataUpdate = set[name]
val updateTagValue = dataUpdate?.meta?.get(key)?.string ?: defaultTagValue
map.getOrPut(updateTagValue) {
DataSource(set.dataType, this) {
data(name, dataUpdate)
}
}
}
}
}
} else {
set.forEach { data ->
val tagValue: String = data.meta[key]?.string ?: defaultTagValue
(map.getOrPut(tagValue) { StaticDataTree(set.dataType) } as StaticDataTree<T>)
.data(data.name, data.data)
}
set.forEach { data ->
val tagValue: String = data.meta[key]?.string ?: defaultTagValue
map.getOrPut(tagValue) { MutableDataTree(set.dataType) }.put(data.name, data.data)
}

View File

@ -0,0 +1,23 @@
package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.copy
private class MetaMaskData<T>(val origin: Data<T>, override val meta: Meta) : Data<T> by origin
/**
* A data with overriden meta. It reflects original data computed state.
*/
public fun <T> Data<T>.withMeta(newMeta: Meta): Data<T> = if (this is MetaMaskData) {
MetaMaskData(origin, newMeta)
} else {
MetaMaskData(this, newMeta)
}
/**
* Create a new [Data] with the same computation, but different meta. The meta is created by applying [block] to
* the existing data meta.
*/
public inline fun <T> Data<T>.withMeta(block: MutableMeta.() -> Unit): Data<T> = withMeta(meta.copy(block))

View File

@ -3,16 +3,36 @@ package space.kscience.dataforge.data
import space.kscience.dataforge.meta.isEmpty
import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name
import kotlin.reflect.KType
public interface NamedData<out T : Any> : Named, Data<T> {
/**
* An interface implementing a data update event.
*
* If [data] is null, then corresponding element should be removed.
*/
public interface DataUpdate<out T> : Named {
public val type: KType
override val name: Name
public val data: Data<T>
public val data: Data<T>?
}
public fun <T> DataUpdate(type: KType, name: Name, data: Data<T>?): DataUpdate<T> = object : DataUpdate<T> {
override val type: KType = type
override val name: Name = name
override val data: Data<T>? = data
}
/**
* A data coupled to a name.
*/
public interface NamedData<out T> : DataUpdate<T>, Data<T> {
override val data: Data<T>
}
public operator fun NamedData<*>.component1(): Name = name
public operator fun <T: Any> NamedData<T>.component2(): Data<T> = data
public operator fun <T> NamedData<T>.component2(): Data<T> = data
private class NamedDataImpl<out T : Any>(
private class NamedDataImpl<T>(
override val name: Name,
override val data: Data<T>,
) : Data<T> by data, NamedData<T> {
@ -28,8 +48,10 @@ private class NamedDataImpl<out T : Any>(
}
}
public fun <T : Any> Data<T>.named(name: Name): NamedData<T> = if (this is NamedData) {
public fun <T> Data<T>.named(name: Name): NamedData<T> = if (this is NamedData) {
NamedDataImpl(name, this.data)
} else {
NamedDataImpl(name, this)
}
}
public fun <T> NamedData(name: Name, data: Data<T>): NamedData<T> = data.named(name)

View File

@ -1,82 +0,0 @@
package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.*
import kotlin.reflect.KType
import kotlin.reflect.typeOf
@PublishedApi
internal class StaticDataTree<T : Any>(
override val dataType: KType,
) : DataSetBuilder<T>, DataTree<T> {
private val _items: MutableMap<NameToken, DataTreeItem<T>> = HashMap()
override val items: Map<NameToken, DataTreeItem<T>>
get() = _items.filter { !it.key.body.startsWith("@") }
override fun remove(name: Name) {
when (name.length) {
0 -> error("Can't remove root tree node")
1 -> _items.remove(name.firstOrNull()!!)
else -> (_items[name.firstOrNull()!!].tree as? StaticDataTree<T>)?.remove(name.cutFirst())
}
}
private fun getOrCreateNode(name: Name): StaticDataTree<T> = when (name.length) {
0 -> this
1 -> {
val itemName = name.firstOrNull()!!
(_items[itemName].tree as? StaticDataTree<T>) ?: StaticDataTree<T>(dataType).also {
_items[itemName] = DataTreeItem.Node(it)
}
}
else -> getOrCreateNode(name.cutLast()).getOrCreateNode(name.lastOrNull()!!.asName())
}
private fun set(name: Name, item: DataTreeItem<T>?) {
if (name.isEmpty()) error("Can't set top level tree node")
if (item == null) {
remove(name)
} else {
getOrCreateNode(name.cutLast())._items[name.lastOrNull()!!] = item
}
}
override fun data(name: Name, data: Data<T>?) {
set(name, data?.let { DataTreeItem.Leaf(it) })
}
override fun node(name: Name, dataSet: DataSet<T>) {
if (dataSet is StaticDataTree) {
set(name, DataTreeItem.Node(dataSet))
} else {
dataSet.forEach {
data(name + it.name, it.data)
}
}
}
override fun meta(name: Name, meta: Meta) {
val item = getItem(name)
if (item is DataTreeItem.Leaf) TODO("Can't change meta of existing leaf item.")
data(name + DataTree.META_ITEM_NAME_TOKEN, Data.empty(meta))
}
}
@Suppress("FunctionName")
public inline fun <T : Any> DataTree(
dataType: KType,
block: DataSetBuilder<T>.() -> Unit,
): DataTree<T> = StaticDataTree<T>(dataType).apply { block() }
@Suppress("FunctionName")
public inline fun <reified T : Any> DataTree(
noinline block: DataSetBuilder<T>.() -> Unit,
): DataTree<T> = DataTree(typeOf<T>(), block)
@OptIn(DFExperimental::class)
public fun <T : Any> DataSet<T>.seal(): DataTree<T> = DataTree(dataType) {
populateFrom(this@seal)
}

View File

@ -0,0 +1,134 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.names.*
public fun <T> DataSink<T>.put(value: NamedData<T>) {
put(value.name, value.data)
}
public inline fun <T> DataSink<T>.putAll(
prefix: Name,
block: DataSink<T>.() -> Unit,
) {
if (prefix.isEmpty()) {
apply(block)
} else {
val proxyDataSink = object :DataSink<T>{
override fun put(name: Name, data: Data<T>?) {
this@putAll.put(prefix + name, data)
}
override suspend fun update(name: Name, data: Data<T>?) {
this@putAll.update(prefix + name, data)
}
}
proxyDataSink.apply(block)
}
}
public inline fun <T> DataSink<T>.putAll(
prefix: String,
block: DataSink<T>.() -> Unit,
): Unit = putAll(prefix.asName(), block)
public fun <T> DataSink<T>.put(name: String, value: Data<T>) {
put(Name.parse(name), value)
}
public fun <T> DataSink<T>.putAll(name: Name, tree: DataTree<T>) {
putAll(name) { putAll(tree.asSequence()) }
}
public fun <T> DataSink<T>.putAll(name: String, tree: DataTree<T>) {
putAll(Name.parse(name)) { putAll(tree.asSequence()) }
}
/**
* Produce lazy [Data] and emit it into the [MutableDataTree]
*/
public inline fun <reified T> DataSink<T>.putValue(
name: String,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
put(name, data)
}
public inline fun <reified T> DataSink<T>.putValue(
name: Name,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
put(name, data)
}
/**
* Emit static data with the fixed value
*/
public inline fun <reified T> DataSink<T>.putValue(
name: Name,
value: T,
meta: Meta = Meta.EMPTY,
): Unit = put(name, Data.wrapValue(value, meta))
public inline fun <reified T> DataSink<T>.putValue(
name: String,
value: T,
meta: Meta = Meta.EMPTY,
): Unit = put(name, Data.wrapValue(value, meta))
public inline fun <reified T> DataSink<T>.putValue(
name: String,
value: T,
metaBuilder: MutableMeta.() -> Unit,
): Unit = put(Name.parse(name), Data.wrapValue(value, Meta(metaBuilder)))
public suspend inline fun <reified T> DataSink<T>.updateValue(
name: Name,
value: T,
meta: Meta = Meta.EMPTY,
): Unit = update(name, Data.wrapValue(value, meta))
public suspend inline fun <reified T> DataSink<T>.updateValue(
name: String,
value: T,
meta: Meta = Meta.EMPTY,
): Unit = update(name.parseAsName(), Data.wrapValue(value, meta))
public fun <T> DataSink<T>.putAll(sequence: Sequence<NamedData<T>>) {
sequence.forEach {
put(it.name, it.data)
}
}
public fun <T> DataSink<T>.putAll(tree: DataTree<T>) {
putAll(tree.asSequence())
}
/**
* Copy given data set and mirror its changes to this [DataSink] in [this@setAndObserve]. Returns an update [Job]
*/
public fun <T : Any> DataSink<T>.putAllAndWatch(
scope: CoroutineScope,
branchName: Name = Name.EMPTY,
source: DataTree<T>,
): Job {
putAll(branchName, source)
return source.updates.onEach {
update(branchName + it.name, it.data)
}.launchIn(scope)
}

View File

@ -1,105 +0,0 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
/**
* A stateless filtered [DataSet]
*/
public fun <T : Any> DataSet<T>.filter(
predicate: (Name, Meta) -> Boolean,
): DataSource<T> = object : DataSource<T> {
override val dataType: KType get() = this@filter.dataType
override val coroutineContext: CoroutineContext
get() = (this@filter as? DataSource)?.coroutineContext ?: EmptyCoroutineContext
override val meta: Meta get() = this@filter.meta
override fun iterator(): Iterator<NamedData<T>> = iterator {
for (d in this@filter) {
if (predicate(d.name, d.meta)) {
yield(d)
}
}
}
override fun get(name: Name): Data<T>? = this@filter.get(name)?.takeIf {
predicate(name, it.meta)
}
override val updates: Flow<Name> = this@filter.updates.filter flowFilter@{ name ->
val theData = this@filter[name] ?: return@flowFilter false
predicate(name, theData.meta)
}
}
/**
* Generate a wrapper data set with a given name prefix appended to all names
*/
public fun <T : Any> DataSet<T>.withNamePrefix(prefix: Name): DataSet<T> = if (prefix.isEmpty()) {
this
} else object : DataSource<T> {
override val dataType: KType get() = this@withNamePrefix.dataType
override val coroutineContext: CoroutineContext
get() = (this@withNamePrefix as? DataSource)?.coroutineContext ?: EmptyCoroutineContext
override val meta: Meta get() = this@withNamePrefix.meta
override fun iterator(): Iterator<NamedData<T>> = iterator {
for (d in this@withNamePrefix) {
yield(d.data.named(prefix + d.name))
}
}
override fun get(name: Name): Data<T>? =
name.removeFirstOrNull(name)?.let { this@withNamePrefix.get(it) }
override val updates: Flow<Name> get() = this@withNamePrefix.updates.map { prefix + it }
}
/**
* Get a subset of data starting with a given [branchName]
*/
public fun <T : Any> DataSet<T>.branch(branchName: Name): DataSet<T> = if (branchName.isEmpty()) {
this
} else object : DataSource<T> {
override val dataType: KType get() = this@branch.dataType
override val coroutineContext: CoroutineContext
get() = (this@branch as? DataSource)?.coroutineContext ?: EmptyCoroutineContext
override val meta: Meta get() = this@branch.meta
override fun iterator(): Iterator<NamedData<T>> = iterator {
for (d in this@branch) {
d.name.removeFirstOrNull(branchName)?.let { name ->
yield(d.data.named(name))
}
}
}
override fun get(name: Name): Data<T>? = this@branch.get(branchName + name)
override val updates: Flow<Name> get() = this@branch.updates.mapNotNull { it.removeFirstOrNull(branchName) }
}
public fun <T : Any> DataSet<T>.branch(branchName: String): DataSet<T> = this@branch.branch(branchName.parseAsName())
@DFExperimental
public suspend fun <T : Any> DataSet<T>.rootData(): Data<T>? = get(Name.EMPTY)

View File

@ -1,24 +1,40 @@
package space.kscience.dataforge.data
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.seal
import space.kscience.dataforge.meta.toMutableMeta
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.NameToken
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public data class ValueWithMeta<T>(val meta: Meta, val value: T)
public data class ValueWithMeta<T>(val value: T, val meta: Meta)
public suspend fun <T : Any> Data<T>.awaitWithMeta(): ValueWithMeta<T> = ValueWithMeta(meta, await())
public suspend fun <T> Data<T>.awaitWithMeta(): ValueWithMeta<T> = ValueWithMeta(await(), meta)
public data class NamedValueWithMeta<T>(val name: Name, val meta: Meta, val value: T)
public data class NamedValueWithMeta<T>(val name: Name, val value: T, val meta: Meta)
public suspend fun <T> NamedData<T>.awaitWithMeta(): NamedValueWithMeta<T> =
NamedValueWithMeta(name, await(), meta)
/**
* Lazily transform this data to another data. By convention [block] should not use external data (be pure).
* @param type explicit type of the resulting [Data]
* @param coroutineContext additional [CoroutineContext] elements used for data computation.
* @param meta for the resulting data. By default equals input data.
* @param block the transformation itself
*/
@UnsafeKType
public fun <T, R> Data<T>.transform(
type: KType,
meta: Meta = this.meta,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
block: suspend (T) -> R,
): Data<R> = Data(type, meta, coroutineContext, listOf(this)) {
block(await())
}
public suspend fun <T : Any> NamedData<T>.awaitWithMeta(): NamedValueWithMeta<T> =
NamedValueWithMeta(name, meta, await())
/**
@ -27,9 +43,9 @@ public suspend fun <T : Any> NamedData<T>.awaitWithMeta(): NamedValueWithMeta<T>
* @param meta for the resulting data. By default equals input data.
* @param block the transformation itself
*/
public inline fun <T : Any, reified R : Any> Data<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
public inline fun <T, reified R> Data<T>.transform(
meta: Meta = this.meta,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline block: suspend (T) -> R,
): Data<R> = Data(meta, coroutineContext, listOf(this)) {
block(await())
@ -38,10 +54,10 @@ public inline fun <T : Any, reified R : Any> Data<T>.map(
/**
* Combine this data with the other data using [block]. See [Data::map] for other details
*/
public inline fun <T1 : Any, T2 : Any, reified R : Any> Data<T1>.combine(
public inline fun <T1, T2, reified R> Data<T1>.combine(
other: Data<T2>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline block: suspend (left: T1, right: T2) -> R,
): Data<R> = Data(meta, coroutineContext, listOf(this, other)) {
block(await(), other.await())
@ -50,26 +66,31 @@ public inline fun <T1 : Any, T2 : Any, reified R : Any> Data<T1>.combine(
//data collection operations
/**
* Lazily reduce a collection of [Data] to a single data.
*/
public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (List<ValueWithMeta<T>>) -> R,
): Data<R> = Data(
meta,
coroutineContext,
this
) {
block(map { it.awaitWithMeta() })
@PublishedApi
internal fun Iterable<Data<*>>.joinMeta(): Meta = Meta {
var counter = 0
forEach { data ->
val inputIndex = (data as? NamedData)?.name?.toString() ?: (counter++).toString()
val token = NameToken("data", inputIndex)
set(token, data.meta)
}
}
@DFInternal
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduceToData(
@PublishedApi
internal fun Map<*, Data<*>>.joinMeta(): Meta = Meta {
forEach { (key, data) ->
val token = NameToken("data", key.toString())
set(token, data.meta)
}
}
@UnsafeKType
public fun <K, T, R> Map<K, Data<T>>.reduceToData(
outputType: KType,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
block: suspend (Map<K, ValueWithMeta<T>>) -> R,
): Data<R> = Data(
outputType,
@ -86,9 +107,9 @@ public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduceToData(
* @param T type of the input goal
* @param R type of the result goal
*/
public inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduceToData(
public inline fun <K, T, reified R> Map<K, Data<T>>.reduceToData(
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (Map<K, ValueWithMeta<T>>) -> R,
): Data<R> = Data(
meta,
@ -100,11 +121,11 @@ public inline fun <K, T : Any, reified R : Any> Map<K, Data<T>>.reduceToData(
//Iterable operations
@DFInternal
public inline fun <T : Any, R : Any> Iterable<Data<T>>.reduceToData(
@UnsafeKType
public inline fun <T, R> Iterable<Data<T>>.reduceToData(
outputType: KType,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline transformation: suspend (Collection<ValueWithMeta<T>>) -> R,
): Data<R> = Data(
outputType,
@ -115,22 +136,22 @@ public inline fun <T : Any, R : Any> Iterable<Data<T>>.reduceToData(
transformation(map { it.awaitWithMeta() })
}
@OptIn(DFInternal::class)
public inline fun <T : Any, reified R : Any> Iterable<Data<T>>.reduceToData(
@OptIn(UnsafeKType::class)
public inline fun <T, reified R> Iterable<Data<T>>.reduceToData(
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline transformation: suspend (Collection<ValueWithMeta<T>>) -> R,
): Data<R> = reduceToData(typeOf<R>(), coroutineContext, meta) {
): Data<R> = reduceToData(typeOf<R>(), meta, coroutineContext) {
transformation(it)
}
public inline fun <T : Any, reified R : Any> Iterable<Data<T>>.foldToData(
public inline fun <T, reified R> Iterable<Data<T>>.foldToData(
initial: R,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (result: R, data: ValueWithMeta<T>) -> R,
): Data<R> = reduceToData(
coroutineContext, meta
meta, coroutineContext
) {
it.fold(initial) { acc, t -> block(acc, t) }
}
@ -138,11 +159,11 @@ public inline fun <T : Any, reified R : Any> Iterable<Data<T>>.foldToData(
/**
* Transform an [Iterable] of [NamedData] to a single [Data].
*/
@DFInternal
public inline fun <T : Any, R : Any> Iterable<NamedData<T>>.reduceNamedToData(
@UnsafeKType
public inline fun <T, R> Iterable<NamedData<T>>.reduceNamedToData(
outputType: KType,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline transformation: suspend (Collection<NamedValueWithMeta<T>>) -> R,
): Data<R> = Data(
outputType,
@ -153,69 +174,79 @@ public inline fun <T : Any, R : Any> Iterable<NamedData<T>>.reduceNamedToData(
transformation(map { it.awaitWithMeta() })
}
@OptIn(DFInternal::class)
public inline fun <T : Any, reified R : Any> Iterable<NamedData<T>>.reduceNamedToData(
@OptIn(UnsafeKType::class)
public inline fun <T, reified R> Iterable<NamedData<T>>.reduceNamedToData(
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline transformation: suspend (Collection<NamedValueWithMeta<T>>) -> R,
): Data<R> = reduceNamedToData(typeOf<R>(), coroutineContext, meta) {
): Data<R> = reduceNamedToData(typeOf<R>(), meta, coroutineContext) {
transformation(it)
}
/**
* Fold a [Iterable] of named data into a single [Data]
*/
public inline fun <T : Any, reified R : Any> Iterable<NamedData<T>>.foldNamedToData(
public inline fun <T, reified R> Iterable<NamedData<T>>.foldNamedToData(
initial: R,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (result: R, data: NamedValueWithMeta<T>) -> R,
): Data<R> = reduceNamedToData(
coroutineContext, meta
meta, coroutineContext
) {
it.fold(initial) { acc, t -> block(acc, t) }
}
//DataSet operations
@DFInternal
public suspend fun <T : Any, R : Any> DataSet<T>.map(
@UnsafeKType
public suspend fun <T, R> DataTree<T>.transform(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
metaTransform: MutableMeta.() -> Unit = {},
coroutineContext: CoroutineContext = EmptyCoroutineContext,
block: suspend (NamedValueWithMeta<T>) -> R,
): DataTree<R> = DataTree<R>(outputType) {
forEach {
val newMeta = it.meta.toMutableMeta().apply(metaTransform).seal()
val d = Data(outputType, newMeta, coroutineContext, listOf(it)) {
block(it.awaitWithMeta())
): DataTree<R> = DataTree<R>(outputType){
//quasi-synchronous processing of elements in the tree
asSequence().forEach { namedData: NamedData<T> ->
val newMeta = namedData.meta.toMutableMeta().apply(metaTransform).seal()
val d = Data(outputType, newMeta, coroutineContext, listOf(namedData)) {
block(namedData.awaitWithMeta())
}
data(it.name, d)
put(namedData.name, d)
}
}
@OptIn(DFInternal::class)
public suspend inline fun <T : Any, reified R : Any> DataSet<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
@OptIn(UnsafeKType::class)
public suspend inline fun <T, reified R> DataTree<T>.transform(
noinline metaTransform: MutableMeta.() -> Unit = {},
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline block: suspend (NamedValueWithMeta<T>) -> R,
): DataTree<R> = map(typeOf<R>(), coroutineContext, metaTransform, block)
): DataTree<R> = this@transform.transform(typeOf<R>(), metaTransform, coroutineContext, block)
public inline fun <T : Any> DataSet<T>.forEach(block: (NamedData<T>) -> Unit) {
for (d in this) {
block(d)
public inline fun <T> DataTree<T>.forEach(block: (NamedData<T>) -> Unit) {
asSequence().forEach(block)
}
// DataSet reduction
@PublishedApi
internal fun DataTree<*>.joinMeta(): Meta = Meta {
asSequence().forEach {
val token = NameToken("data", it.name.toString())
set(token, it.meta)
}
}
public inline fun <T : Any, reified R : Any> DataSet<T>.reduceToData(
public inline fun <T, reified R> DataTree<T>.reduceToData(
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline transformation: suspend (Iterable<NamedValueWithMeta<T>>) -> R,
): Data<R> = asIterable().reduceNamedToData(coroutineContext, meta, transformation)
): Data<R> = asSequence().asIterable().reduceNamedToData(meta, coroutineContext, transformation)
public inline fun <T : Any, reified R : Any> DataSet<T>.foldToData(
public inline fun <T, reified R> DataTree<T>.foldToData(
initial: R,
meta: Meta = joinMeta(),
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
crossinline block: suspend (result: R, data: NamedValueWithMeta<T>) -> R,
): Data<R> = asIterable().foldNamedToData(initial, coroutineContext, meta, block)
): Data<R> = asSequence().asIterable().foldNamedToData(initial, meta, coroutineContext, block)

View File

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

View File

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

View File

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

View File

@ -2,11 +2,8 @@ package space.kscience.dataforge.data
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.names.Name
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf
import kotlin.reflect.typeOf
@ -16,7 +13,7 @@ import kotlin.reflect.typeOf
* Cast the node to given type if the cast is possible or return null
*/
@Suppress("UNCHECKED_CAST")
private fun <R : Any> Data<*>.castOrNull(type: KType): Data<R>? =
private fun <R> Data<*>.castOrNull(type: KType): Data<R>? =
if (!this.type.isSubtypeOf(type)) {
null
} else {
@ -25,61 +22,51 @@ private fun <R : Any> Data<*>.castOrNull(type: KType): Data<R>? =
}
}
@Suppress("UNCHECKED_CAST")
@DFInternal
public fun <R> Sequence<DataUpdate<*>>.filterByDataType(type: KType): Sequence<NamedData<R>> =
filter { it.type.isSubtypeOf(type) } as Sequence<NamedData<R>>
@Suppress("UNCHECKED_CAST")
@DFInternal
public fun <R> Flow<DataUpdate<*>>.filterByDataType(type: KType): Flow<NamedData<R>> =
filter { it.type.isSubtypeOf(type) } as Flow<NamedData<R>>
/**
* Select all data matching given type and filters. Does not modify paths
*
* @param predicate addition 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
*/
@OptIn(DFExperimental::class)
public fun <R : Any> DataSet<*>.filterByType(
@Suppress("UNCHECKED_CAST")
@DFInternal
public fun <R> DataTree<*>.filterByType(
type: KType,
predicate: (name: Name, meta: Meta) -> Boolean = { _, _ -> true },
): DataSource<R> = object : DataSource<R> {
override val dataType = type
override val coroutineContext: CoroutineContext
get() = (this@filterByType as? DataSource)?.coroutineContext ?: EmptyCoroutineContext
override val meta: Meta get() = this@filterByType.meta
private fun checkDatum(name: Name, datum: Data<*>): Boolean = datum.type.isSubtypeOf(type)
&& predicate(name, datum.meta)
override fun iterator(): Iterator<NamedData<R>> = iterator {
for(d in this@filterByType){
if(checkDatum(d.name,d.data)){
@Suppress("UNCHECKED_CAST")
yield(d as NamedData<R>)
}
}
}
override fun get(name: Name): Data<R>? = this@filterByType[name]?.let { datum ->
if (checkDatum(name, datum)) datum.castOrNull(type) else null
}
override val updates: Flow<Name> = this@filterByType.updates.filter { name ->
get(name)?.let { datum ->
checkDatum(name, datum)
} ?: false
branch: Name = Name.EMPTY,
filter: DataFilter = DataFilter.EMPTY,
): DataTree<R> {
val filterWithType = DataFilter { name, meta, dataType ->
filter.accepts(name, meta, dataType) && dataType.isSubtypeOf(type)
}
return FilteredDataTree(this, filterWithType, branch, type) as DataTree<R>
}
/**
* Select a single datum of the appropriate type
*/
public inline fun <reified R : Any> DataSet<*>.filterByType(
noinline predicate: (name: Name, meta: Meta) -> Boolean = { _, _ -> true },
): DataSet<R> = filterByType(typeOf<R>(), predicate)
@OptIn(DFInternal::class)
public inline fun <reified R : Any> DataTree<*>.filterByType(
branch: Name = Name.EMPTY,
filter: DataFilter = DataFilter.EMPTY,
): DataTree<R> = filterByType(typeOf<R>(), branch, filter = filter)
/**
* Select a single datum if it is present and of given [type]
*/
public fun <R : Any> DataSet<*>.getByType(type: KType, name: Name): NamedData<R>? =
public fun <R> DataTree<*>.getByType(type: KType, name: Name): NamedData<R>? =
get(name)?.castOrNull<R>(type)?.named(name)
public inline fun <reified R : Any> DataSet<*>.getByType(name: Name): NamedData<R>? =
public inline fun <reified R : Any> DataTree<*>.getByType(name: Name): NamedData<R>? =
this@getByType.getByType(typeOf<R>(), name)
public inline fun <reified R : Any> DataSet<*>.getByType(name: String): NamedData<R>? =
this@getByType.getByType(typeOf<R>(), Name.parse(name))
public inline fun <reified R : Any> DataTree<*>.getByType(name: String): NamedData<R>? =
this@getByType.getByType(typeOf<R>(), Name.parse(name))

View File

@ -1,40 +1,27 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.plus
/**
* Append data to node
*/
context(DataSetBuilder<T>) public infix fun <T : Any> String.put(data: Data<T>): Unit =
data(Name.parse(this), data)
context(DataSink<T>)
public infix fun <T : Any> String.put(data: Data<T>): Unit =
put(Name.parse(this), data)
/**
* Append node
*/
context(DataSetBuilder<T>) public infix fun <T : Any> String.put(dataSet: DataSet<T>): Unit =
node(Name.parse(this), dataSet)
context(DataSink<T>)
public infix fun <T : Any> String.putAll(dataSet: DataTree<T>): Unit =
putAll(this, dataSet)
/**
* Build and append node
*/
context(DataSetBuilder<T>) public infix fun <T : Any> String.put(
block: DataSetBuilder<T>.() -> Unit,
): Unit = node(Name.parse(this), block)
context(DataSink<T>)
public infix fun <T : Any> String.putAll(
block: DataSink<T>.() -> Unit,
): Unit = putAll(Name.parse(this), block)
/**
* Copy given data set and mirror its changes to this [DataTreeBuilder] in [this@setAndObserve]. Returns an update [Job]
*/
context(DataSetBuilder<T>) public fun <T : Any> CoroutineScope.setAndWatch(
name: Name,
dataSet: DataSet<T>,
): Job = launch {
node(name, dataSet)
dataSet.updates.collect { nameInBranch ->
data(name + nameInBranch, dataSet.get(nameInBranch))
}
}

View File

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

View File

@ -1,91 +0,0 @@
package space.kscience.dataforge.data
import kotlinx.coroutines.*
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() = runBlocking {
val node = DataTree<Any> {
"primary" put {
static("a", "a")
static("b", "b")
}
static("c.d", "c.d")
static("c.f", "c.f")
}
runBlocking {
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() = runBlocking {
val updateData: DataTree<Any> = DataTree {
"update" put {
"a" put Data.static("a")
"b" put Data.static("b")
}
}
val node = DataTree<Any> {
"primary" put {
static("a", "a")
static("b", "b")
}
static("root", "root")
populateFrom(updateData)
}
runBlocking {
assertEquals("a", node["update.a"]?.await())
assertEquals("a", node["primary.a"]?.await())
}
}
@Test
fun testDynamicUpdates() = runBlocking {
try {
lateinit var updateJob: Job
supervisorScope {
val subNode = DataSource<Int> {
updateJob = launch {
repeat(10) {
delay(10)
static("value", it)
}
delay(10)
}
}
launch {
subNode.updatesWithData.collect {
println(it)
}
}
val rootNode = DataSource<Int> {
setAndWatch("sub".asName(), subNode)
}
launch {
rootNode.updatesWithData.collect {
println(it)
}
}
updateJob.join()
assertEquals(9, rootNode["sub.value"]?.await())
cancel()
}
} catch (t: Throwable) {
if (t !is CancellationException) throw t
}
}
}

View File

@ -6,18 +6,16 @@ IO module
## Artifact:
The Maven coordinates of this project are `space.kscience:dataforge-io:0.7.0`.
The Maven coordinates of this project are `space.kscience:dataforge-io:0.8.2`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
//uncomment to access development builds
//maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
mavenCentral()
}
dependencies {
implementation("space.kscience:dataforge-io:0.7.0")
implementation("space.kscience:dataforge-io:0.8.2")
}
```

View File

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

View File

@ -6,18 +6,16 @@ YAML meta IO
## Artifact:
The Maven coordinates of this project are `space.kscience:dataforge-io-yaml:0.7.0`.
The Maven coordinates of this project are `space.kscience:dataforge-io-yaml:0.8.2`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
//uncomment to access development builds
//maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
mavenCentral()
}
dependencies {
implementation("space.kscience:dataforge-io-yaml:0.7.0")
implementation("space.kscience:dataforge-io-yaml:0.8.2")
}
```

View File

@ -71,6 +71,11 @@ internal class ByteArrayBinary(
override fun view(offset: Int, binarySize: Int): ByteArrayBinary =
ByteArrayBinary(array, start + offset, binarySize)
override fun toString(): String =
"ByteArrayBinary(array=$array, start=$start, size=$size)"
}
public fun ByteArray.asBinary(): Binary = ByteArrayBinary(this)

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import space.kscience.dataforge.context.Context
import space.kscience.dataforge.context.Factory
import space.kscience.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.misc.Named
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
@ -17,11 +17,7 @@ import kotlin.reflect.typeOf
/**
* Reader of a custom object from input
*/
public interface IOReader<out T> {
/**
* The type of object being read
*/
public val type: KType
public fun interface IOReader<out T> {
public fun readFrom(source: Source): T
@ -32,7 +28,6 @@ public interface IOReader<out T> {
* no-op reader for binaries.
*/
public val binary: IOReader<Binary> = object : IOReader<Binary> {
override val type: KType = typeOf<Binary>()
override fun readFrom(source: Source): Binary = source.readByteArray().asBinary()
@ -42,8 +37,6 @@ public interface IOReader<out T> {
}
public inline fun <reified T> IOReader(crossinline read: Source.() -> T): IOReader<T> = object : IOReader<T> {
override val type: KType = typeOf<T>()
override fun readFrom(source: Source): T = source.read()
}
@ -56,24 +49,24 @@ public fun interface IOWriter<in T> {
*/
public interface IOFormat<T> : IOReader<T>, IOWriter<T>
public fun <T : Any> Source.readWith(format: IOReader<T>): T = format.readFrom(this)
public fun <T> Source.readWith(format: IOReader<T>): T = format.readFrom(this)
/**
* Read given binary as an object using given format
*/
public fun <T : Any> Binary.readWith(format: IOReader<T>): T = read {
readWith(format)
public fun <T> Binary.readWith(format: IOReader<T>): T = read {
this.readWith(format)
}
/**
* Write an object to the [Sink] with given [format]
*/
public fun <T : Any> Sink.writeWith(format: IOWriter<T>, obj: T): Unit =
public fun <T> Sink.writeWith(format: IOWriter<T>, obj: T): Unit =
format.writeTo(this, obj)
@DfId(IO_FORMAT_TYPE)
public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named {
@DfType(IO_FORMAT_TYPE)
public interface IOFormatFactory<T> : Factory<IOFormat<T>>, Named {
/**
* Explicit type for dynamic type checks
*/
@ -86,7 +79,7 @@ public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named {
}
}
public fun <T : Any> Binary(obj: T, format: IOWriter<T>): Binary = Binary { format.writeTo(this, obj) }
public fun <T> Binary(obj: T, format: IOWriter<T>): Binary = Binary { format.writeTo(this, obj) }
public object FloatIOFormat : IOFormat<Float>, IOFormatFactory<Float> {
override fun build(context: Context, meta: Meta): IOFormat<Float> = this

View File

@ -5,9 +5,8 @@ import space.kscience.dataforge.io.EnvelopeFormatFactory.Companion.ENVELOPE_FORM
import space.kscience.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE
import space.kscience.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.string
import space.kscience.dataforge.misc.DFInternal
import space.kscience.dataforge.misc.UnsafeKType
import space.kscience.dataforge.names.Name
import kotlin.reflect.KType
import kotlin.reflect.typeOf
@ -20,12 +19,12 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
}
@Suppress("UNCHECKED_CAST")
@DFInternal
public fun <T : Any> resolveIOFormat(type: KType, meta: Meta): IOFormat<T>? =
@UnsafeKType
public fun <T> resolveIOFormat(type: KType, meta: Meta): IOFormat<T>? =
ioFormatFactories.singleOrNull { it.type == type }?.build(context, meta) as? IOFormat<T>
@OptIn(DFInternal::class)
public inline fun <reified T : Any> resolveIOFormat(meta: Meta = Meta.EMPTY): IOFormat<T>? =
@OptIn(UnsafeKType::class)
public inline fun <reified T> resolveIOFormat(meta: Meta = Meta.EMPTY): IOFormat<T>? =
resolveIOFormat(typeOf<T>(), meta)

View File

@ -9,7 +9,7 @@ import space.kscience.dataforge.context.Global
import space.kscience.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.plus
@ -21,8 +21,6 @@ import kotlin.reflect.typeOf
*/
public interface MetaFormat : IOFormat<Meta> {
override val type: KType get() = typeOf<Meta>()
override fun writeTo(sink: Sink, obj: Meta) {
writeMeta(sink, obj, null)
}
@ -38,7 +36,7 @@ public interface MetaFormat : IOFormat<Meta> {
public fun readMeta(source: Source, descriptor: MetaDescriptor? = null): Meta
}
@DfId(META_FORMAT_TYPE)
@DfType(META_FORMAT_TYPE)
public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
public val shortName: String

View File

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

View File

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

View File

@ -6,18 +6,16 @@ Meta definition and basic operations on meta
## Artifact:
The Maven coordinates of this project are `space.kscience:dataforge-meta:0.7.0`.
The Maven coordinates of this project are `space.kscience:dataforge-meta:0.8.2`.
**Gradle Kotlin DSL:**
```kotlin
repositories {
maven("https://repo.kotlin.link")
//uncomment to access development builds
//maven("https://maven.pkg.jetbrains.space/spc/p/sci/dev")
mavenCentral()
}
dependencies {
implementation("space.kscience:dataforge-meta:0.7.0")
implementation("space.kscience:dataforge-meta:0.8.2")
}
```

View File

@ -1,3 +1,15 @@
public final class space/kscience/dataforge/meta/ByteArrayValue : java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker, space/kscience/dataforge/meta/Value {
public fun <init> ([B)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getType ()Lspace/kscience/dataforge/meta/ValueType;
public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()[B
public fun hashCode ()I
public fun iterator ()Ljava/util/Iterator;
public fun toString ()Ljava/lang/String;
}
public abstract interface class space/kscience/dataforge/meta/Configurable {
public abstract fun getMeta ()Lspace/kscience/dataforge/meta/MutableMeta;
}
@ -30,7 +42,20 @@ public final class space/kscience/dataforge/meta/EnumValue : space/kscience/data
}
public final class space/kscience/dataforge/meta/ExoticValuesKt {
public static final fun asValue ([B)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([D)Lspace/kscience/dataforge/meta/Value;
public static final fun byteArray (Lspace/kscience/dataforge/meta/MetaProvider;[BLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun byteArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[BLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun byteArray$default (Lspace/kscience/dataforge/meta/MetaProvider;[BLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun byteArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[BLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun doubleArray (Lspace/kscience/dataforge/meta/MetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun doubleArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun getByteArray (Lspace/kscience/dataforge/meta/Meta;)[B
public static final fun getByteArray (Lspace/kscience/dataforge/meta/Value;)[B
public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Meta;)[D
public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Value;)[D
public static final fun lazyParseValue (Ljava/lang/String;)Lspace/kscience/dataforge/meta/LazyParsedValue;
}
@ -56,6 +81,20 @@ public final class space/kscience/dataforge/meta/JsonMetaKt {
public static final fun toValue (Lkotlinx/serialization/json/JsonPrimitive;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/Value;
}
public final class space/kscience/dataforge/meta/KeepTransformationRule : space/kscience/dataforge/meta/TransformationRule {
public fun <init> (Lkotlin/jvm/functions/Function1;)V
public final fun component1 ()Lkotlin/jvm/functions/Function1;
public final fun copy (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/KeepTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/KeepTransformationRule;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/KeepTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getSelector ()Lkotlin/jvm/functions/Function1;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public final class space/kscience/dataforge/meta/Laminate : space/kscience/dataforge/meta/TypedMeta {
public static final field Companion Lspace/kscience/dataforge/meta/Laminate$Companion;
public fun equals (Ljava/lang/Object;)Z
@ -159,49 +198,82 @@ public final class space/kscience/dataforge/meta/MetaBuilder : space/kscience/da
public abstract interface annotation class space/kscience/dataforge/meta/MetaBuilderMarker : java/lang/annotation/Annotation {
}
public abstract interface class space/kscience/dataforge/meta/MetaConverter : space/kscience/dataforge/meta/MetaSpec {
public static final field Companion Lspace/kscience/dataforge/meta/MetaConverter$Companion;
public abstract fun convert (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
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/MetaConverter$Companion {
public final fun getBoolean ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getDouble ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getFloat ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getInt ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getLong ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getMeta ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getNumber ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getString ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun getValue ()Lspace/kscience/dataforge/meta/MetaConverter;
public final fun valueList (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MetaConverter;
public static synthetic fun valueList$default (Lspace/kscience/dataforge/meta/MetaConverter$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaConverter;
}
public final class space/kscience/dataforge/meta/MetaConverterKt {
public static final fun convertNullable (Lspace/kscience/dataforge/meta/MetaConverter;Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
}
public abstract interface class space/kscience/dataforge/meta/MetaDelegate : kotlin/properties/ReadOnlyProperty, space/kscience/dataforge/meta/descriptors/Described {
}
public final class space/kscience/dataforge/meta/MetaDelegateKt {
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/transformations/MetaConverter;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/transformations/MetaConverter;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun boolean (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun double (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun float (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun int (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun listOfSpec (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MetaSpec;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;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun long (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun node (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/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;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;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun spec (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/meta/MetaSpec;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;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static final fun value (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MetaDelegate;
}
public final class space/kscience/dataforge/meta/MetaKt {
@ -252,6 +324,47 @@ public final class space/kscience/dataforge/meta/MetaSerializer : kotlinx/serial
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lspace/kscience/dataforge/meta/Meta;)V
}
public abstract interface class space/kscience/dataforge/meta/MetaSpec : space/kscience/dataforge/meta/descriptors/Described {
public fun read (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public abstract fun readOrNull (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
}
public final class space/kscience/dataforge/meta/MetaSpecKt {
public static final fun readNullable (Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public static final fun readValue (Lspace/kscience/dataforge/meta/MetaSpec;Lspace/kscience/dataforge/meta/Value;)Ljava/lang/Object;
}
public final class space/kscience/dataforge/meta/MetaTransformation {
public static final field Companion Lspace/kscience/dataforge/meta/MetaTransformation$Companion;
public static final fun apply-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Meta;
public static final fun bind-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/ObservableMeta;Lspace/kscience/dataforge/meta/MutableMeta;)V
public static final synthetic fun box-impl (Ljava/util/Collection;)Lspace/kscience/dataforge/meta/MetaTransformation;
public static fun constructor-impl (Ljava/util/Collection;)Ljava/util/Collection;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Ljava/util/Collection;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Ljava/util/Collection;Ljava/util/Collection;)Z
public static final fun generate-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Meta;
public fun hashCode ()I
public static fun hashCode-impl (Ljava/util/Collection;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Ljava/util/Collection;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Ljava/util/Collection;
}
public final class space/kscience/dataforge/meta/MetaTransformation$Companion {
public final fun make--mWxz5M (Lkotlin/jvm/functions/Function1;)Ljava/util/Collection;
}
public final class space/kscience/dataforge/meta/MetaTransformationBuilder {
public fun <init> ()V
public final fun build-m6Fha10 ()Ljava/util/Collection;
public final fun keep (Ljava/lang/String;)V
public final fun keep (Lkotlin/jvm/functions/Function1;)V
public final fun keep (Lspace/kscience/dataforge/names/Name;)V
public final fun move (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun move$default (Lspace/kscience/dataforge/meta/MetaTransformationBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}
public abstract interface class space/kscience/dataforge/meta/MutableMeta : space/kscience/dataforge/meta/Meta, space/kscience/dataforge/meta/MutableMetaProvider {
public static final field Companion Lspace/kscience/dataforge/meta/MutableMeta$Companion;
public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta;
@ -267,6 +380,7 @@ public abstract interface class space/kscience/dataforge/meta/MutableMeta : spac
public fun put (Ljava/lang/String;Lspace/kscience/dataforge/meta/MetaRepr;)V
public fun put (Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)V
public fun put (Ljava/lang/String;Z)V
public fun put (Ljava/lang/String;[B)V
public fun put (Ljava/lang/String;[D)V
public fun put (Lspace/kscience/dataforge/names/Name;Ljava/lang/Enum;)V
public fun put (Lspace/kscience/dataforge/names/Name;Ljava/lang/Number;)V
@ -286,64 +400,70 @@ public final class space/kscience/dataforge/meta/MutableMeta$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public abstract interface class space/kscience/dataforge/meta/MutableMetaDelegate : kotlin/properties/ReadWriteProperty, space/kscience/dataforge/meta/descriptors/Described {
}
public final class space/kscience/dataforge/meta/MutableMetaDelegateKt {
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun doubleArray (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun doubleArray$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun listValue (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun listValue$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/transformations/MetaConverter;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/transformations/MetaConverter;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun numberList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun numberList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun boolean (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun boolean$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ZLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun convertable (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun convertable$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun double (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;DLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun double$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun float (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;FLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun float$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun int (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;ILspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun int$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun listOfConvertable (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun listOfConvertable$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaConverter;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun listValue (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun listValue$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun long (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;JLspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun long$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun node (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/MetaConverter;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun number (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun number$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun numberList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun numberList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/Number;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun string (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun string$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun stringList (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun stringList$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;[Ljava/lang/String;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static final fun value (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/MutableMetaDelegate;
}
public final class space/kscience/dataforge/meta/MutableMetaKt {
public static final fun ObservableMutableMeta ()Lspace/kscience/dataforge/meta/ObservableMutableMeta;
public static final fun ObservableMutableMeta (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
public static final fun ObservableMutableMeta (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
public static synthetic fun ObservableMutableMeta$default (Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
public static final fun append (Lspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lspace/kscience/dataforge/meta/Meta;)V
public static final fun append (Lspace/kscience/dataforge/meta/MutableMeta;Ljava/lang/String;Lspace/kscience/dataforge/meta/Value;)V
@ -357,6 +477,7 @@ public final class space/kscience/dataforge/meta/MutableMetaKt {
public static final fun getOrCreate (Lspace/kscience/dataforge/meta/MutableTypedMeta;Ljava/lang/String;)Lspace/kscience/dataforge/meta/MutableTypedMeta;
public static final fun remove (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;)V
public static final fun remove (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;)V
public static final fun reset (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Meta;)V
public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Ljava/lang/Iterable;)V
public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Ljava/lang/String;Lspace/kscience/dataforge/meta/Meta;)V
public static final fun set (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Ljava/lang/Iterable;)V
@ -365,7 +486,7 @@ public final class space/kscience/dataforge/meta/MutableMetaKt {
public static final fun set (Lspace/kscience/dataforge/meta/MutableValueProvider;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Value;)V
public static final fun setIndexed (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)V
public static synthetic fun setIndexed$default (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/names/Name;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
public static final fun toMutableMeta (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
public static final fun toMutableMeta (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/MutableMeta;
public static final fun update (Lspace/kscience/dataforge/meta/MutableMetaProvider;Lspace/kscience/dataforge/meta/Meta;)V
public static final fun withDefault (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/MetaProvider;)Lspace/kscience/dataforge/meta/MutableMeta;
}
@ -419,11 +540,6 @@ public abstract interface class space/kscience/dataforge/meta/ObservableMeta : s
public abstract fun removeListener (Ljava/lang/Object;)V
}
public final class space/kscience/dataforge/meta/ObservableMetaKt {
public static final fun useProperty (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/reflect/KProperty1;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
public static synthetic fun useProperty$default (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/reflect/KProperty1;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
}
public final class space/kscience/dataforge/meta/ObservableMetaWrapperKt {
public static final fun asObservable (Lspace/kscience/dataforge/meta/MutableMeta;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
}
@ -437,14 +553,25 @@ public abstract interface class space/kscience/dataforge/meta/ObservableMutableM
public abstract fun getOrCreate (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/ObservableMutableMeta;
}
public abstract interface class space/kscience/dataforge/meta/ReadOnlySpecification : space/kscience/dataforge/meta/descriptors/Described {
public abstract fun empty ()Ljava/lang/Object;
public fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public abstract fun read (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public final class space/kscience/dataforge/meta/RegexItemTransformationRule : space/kscience/dataforge/meta/TransformationRule {
public fun <init> (Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;)V
public final fun component1 ()Lkotlin/text/Regex;
public final fun component2 ()Lkotlin/jvm/functions/Function4;
public final fun copy (Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;)Lspace/kscience/dataforge/meta/RegexItemTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/RegexItemTransformationRule;Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/RegexItemTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getFrom ()Lkotlin/text/Regex;
public final fun getTransform ()Lkotlin/jvm/functions/Function4;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public class space/kscience/dataforge/meta/Scheme : space/kscience/dataforge/meta/Configurable, space/kscience/dataforge/meta/MetaRepr, space/kscience/dataforge/meta/MutableMetaProvider, space/kscience/dataforge/meta/descriptors/Described {
public fun <init> ()V
public fun <init> (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V
public synthetic fun <init> (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/Meta;
public fun get (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/meta/MutableMeta;
public final fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
@ -454,6 +581,7 @@ public class space/kscience/dataforge/meta/Scheme : space/kscience/dataforge/met
public fun setValue (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Value;)V
public fun toMeta ()Lspace/kscience/dataforge/meta/Laminate;
public synthetic fun toMeta ()Lspace/kscience/dataforge/meta/Meta;
public fun toString ()Ljava/lang/String;
public fun validate (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
}
@ -461,20 +589,34 @@ public final class space/kscience/dataforge/meta/SchemeKt {
public static final fun copy (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/Scheme;
public static final fun invoke (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme;
public static final fun retarget (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/MutableMeta;)Lspace/kscience/dataforge/meta/Scheme;
public static final fun listOfScheme (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun listOfScheme (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun listOfScheme$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun listOfScheme$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun scheme (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun scheme (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun scheme$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun scheme$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 schemeOrNull (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun schemeOrNull (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/SchemeSpec;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun schemeOrNull$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 schemeOrNull$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 updateWith (Lspace/kscience/dataforge/meta/Configurable;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme;
public static final fun updateWith (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/SchemeSpec;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme;
public static final fun useProperty (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/reflect/KProperty1;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)V
public static synthetic fun useProperty$default (Lspace/kscience/dataforge/meta/Scheme;Lkotlin/reflect/KProperty1;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
}
public class space/kscience/dataforge/meta/SchemeSpec : space/kscience/dataforge/meta/Specification {
public class space/kscience/dataforge/meta/SchemeSpec : space/kscience/dataforge/meta/MetaConverter {
public fun <init> (Lkotlin/jvm/functions/Function0;)V
public synthetic fun empty ()Ljava/lang/Object;
public fun empty ()Lspace/kscience/dataforge/meta/Scheme;
public synthetic fun convert (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
public fun convert (Lspace/kscience/dataforge/meta/Scheme;)Lspace/kscience/dataforge/meta/Meta;
public final fun empty ()Lspace/kscience/dataforge/meta/Scheme;
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public synthetic fun invoke (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public final fun invoke (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/Scheme;
public synthetic fun read (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public fun read (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Scheme;
public synthetic fun write (Lspace/kscience/dataforge/meta/MutableMeta;)Ljava/lang/Object;
public fun write (Lspace/kscience/dataforge/meta/MutableMeta;)Lspace/kscience/dataforge/meta/Scheme;
public synthetic fun readOrNull (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public fun readOrNull (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Scheme;
public final fun write (Lspace/kscience/dataforge/meta/MutableMeta;)Lspace/kscience/dataforge/meta/Scheme;
}
public final class space/kscience/dataforge/meta/SealedMeta : space/kscience/dataforge/meta/TypedMeta {
@ -515,21 +657,20 @@ public final class space/kscience/dataforge/meta/SealedMetaKt {
public static final fun seal (Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/SealedMeta;
}
public abstract interface class space/kscience/dataforge/meta/Specification : space/kscience/dataforge/meta/ReadOnlySpecification {
public abstract fun write (Lspace/kscience/dataforge/meta/MutableMeta;)Ljava/lang/Object;
}
public final class space/kscience/dataforge/meta/SpecificationKt {
public static final fun spec (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun spec (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun spec$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun spec$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun specOrNull (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun specOrNull (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun specOrNull$default (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun specOrNull$default (Lspace/kscience/dataforge/meta/Scheme;Lspace/kscience/dataforge/meta/Specification;Lspace/kscience/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun updateWith (Lspace/kscience/dataforge/meta/Configurable;Lspace/kscience/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun updateWith (Lspace/kscience/dataforge/meta/MutableMeta;Lspace/kscience/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public final class space/kscience/dataforge/meta/SingleItemTransformationRule : space/kscience/dataforge/meta/TransformationRule {
public fun <init> (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;)V
public final fun component1 ()Lspace/kscience/dataforge/names/Name;
public final fun component2 ()Lkotlin/jvm/functions/Function3;
public final fun copy (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;)Lspace/kscience/dataforge/meta/SingleItemTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/SingleItemTransformationRule;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/SingleItemTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getFrom ()Lspace/kscience/dataforge/names/Name;
public final fun getTransform ()Lkotlin/jvm/functions/Function3;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public final class space/kscience/dataforge/meta/StringValue : space/kscience/dataforge/meta/Value {
@ -550,6 +691,12 @@ public final class space/kscience/dataforge/meta/StringValue : space/kscience/da
public final synthetic fun unbox-impl ()Ljava/lang/String;
}
public abstract interface class space/kscience/dataforge/meta/TransformationRule {
public abstract fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public abstract fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public final class space/kscience/dataforge/meta/True : space/kscience/dataforge/meta/Value {
public static final field INSTANCE Lspace/kscience/dataforge/meta/True;
public fun equals (Ljava/lang/Object;)Z
@ -587,7 +734,6 @@ public final class space/kscience/dataforge/meta/Value$Companion {
public final class space/kscience/dataforge/meta/ValueExtensionsKt {
public static final fun getBoolean (Lspace/kscience/dataforge/meta/Value;)Z
public static final fun getDouble (Lspace/kscience/dataforge/meta/Value;)D
public static final fun getDoubleArray (Lspace/kscience/dataforge/meta/Value;)[D
public static final fun getFloat (Lspace/kscience/dataforge/meta/Value;)F
public static final fun getInt (Lspace/kscience/dataforge/meta/Value;)I
public static final fun getLong (Lspace/kscience/dataforge/meta/Value;)J
@ -606,7 +752,6 @@ public final class space/kscience/dataforge/meta/ValueKt {
public static final fun asValue (Ljava/lang/Number;)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue (Ljava/lang/String;)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue (Z)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([B)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([F)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([I)Lspace/kscience/dataforge/meta/Value;
public static final fun asValue ([J)Lspace/kscience/dataforge/meta/Value;
@ -692,6 +837,7 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptor {
public final fun getDescription ()Ljava/lang/String;
public final fun getIndexKey ()Ljava/lang/String;
public final fun getMultiple ()Z
public final fun getNodes ()Ljava/util/Map;
public final fun getValueRestriction ()Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public final fun getValueTypes ()Ljava/util/List;
public fun hashCode ()I
@ -720,25 +866,22 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorBuild
public final fun attributes (Lkotlin/jvm/functions/Function1;)V
public final fun build ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public final fun default (Ljava/lang/Object;)V
public final fun from (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V
public final fun getAllowedValues ()Ljava/util/List;
public final fun getAttributes ()Lspace/kscience/dataforge/meta/MutableMeta;
public final fun getChildren ()Ljava/util/Map;
public final fun getDefault ()Lspace/kscience/dataforge/meta/Value;
public final fun getDescription ()Ljava/lang/String;
public final fun getIndexKey ()Ljava/lang/String;
public final fun getInfo ()Ljava/lang/String;
public final fun getMultiple ()Z
public final fun getValueRestriction ()Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public final fun getValueTypes ()Ljava/util/List;
public final fun item (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static synthetic fun item$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public final fun node (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public final fun setAllowedValues (Ljava/util/List;)V
public final fun setAttributes (Lspace/kscience/dataforge/meta/MutableMeta;)V
public final fun setChildren (Ljava/util/Map;)V
public final fun setDefault (Lspace/kscience/dataforge/meta/Value;)V
public final fun setDescription (Ljava/lang/String;)V
public final fun setIndexKey (Ljava/lang/String;)V
public final fun setInfo (Ljava/lang/String;)V
public final fun setMultiple (Z)V
public final fun setValueRestriction (Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;)V
public final fun setValueTypes (Ljava/util/List;)V
@ -749,16 +892,16 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorBuild
public static final fun MetaDescriptor (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public static final fun copy (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public static final fun item (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static final fun node (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
public static final fun node (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/descriptors/Described;Lkotlin/jvm/functions/Function1;)V
public static final fun node (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static final fun node (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;)V
public static final fun node (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun node$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/descriptors/Described;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun required (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;)V
public static final fun value (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static final fun value (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;
public static final fun value (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;)V
public static final fun value (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Ljava/lang/String;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun value$default (Lspace/kscience/dataforge/meta/descriptors/MetaDescriptorBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/ValueType;[Lspace/kscience/dataforge/meta/ValueType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}
public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorKt {
@ -772,6 +915,7 @@ public final class space/kscience/dataforge/meta/descriptors/MetaDescriptorKt {
public final class space/kscience/dataforge/meta/descriptors/ValueRestriction : java/lang/Enum {
public static final field ABSENT Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public static final field Companion Lspace/kscience/dataforge/meta/descriptors/ValueRestriction$Companion;
public static final field NONE Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public static final field REQUIRED Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
public static fun getEntries ()Lkotlin/enums/EnumEntries;
@ -779,115 +923,8 @@ public final class space/kscience/dataforge/meta/descriptors/ValueRestriction :
public static fun values ()[Lspace/kscience/dataforge/meta/descriptors/ValueRestriction;
}
public final class space/kscience/dataforge/meta/transformations/KeepTransformationRule : space/kscience/dataforge/meta/transformations/TransformationRule {
public fun <init> (Lkotlin/jvm/functions/Function1;)V
public final fun component1 ()Lkotlin/jvm/functions/Function1;
public final fun copy (Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/transformations/KeepTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/transformations/KeepTransformationRule;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/transformations/KeepTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getSelector ()Lkotlin/jvm/functions/Function1;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public abstract interface class space/kscience/dataforge/meta/transformations/MetaConverter {
public static final field Companion Lspace/kscience/dataforge/meta/transformations/MetaConverter$Companion;
public fun getDescriptor ()Lspace/kscience/dataforge/meta/descriptors/MetaDescriptor;
public abstract fun getType ()Lkotlin/reflect/KType;
public fun metaToObject (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public abstract fun metaToObjectOrNull (Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public abstract fun objectToMeta (Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
}
public final class space/kscience/dataforge/meta/transformations/MetaConverter$Companion {
public final fun getBoolean ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getDouble ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getFloat ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getInt ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getLong ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getMeta ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getNumber ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getString ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun getValue ()Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public final fun valueList (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/meta/transformations/MetaConverter;
public static synthetic fun valueList$default (Lspace/kscience/dataforge/meta/transformations/MetaConverter$Companion;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/transformations/MetaConverter;
}
public final class space/kscience/dataforge/meta/transformations/MetaConverterKt {
public static final fun nullableMetaToObject (Lspace/kscience/dataforge/meta/transformations/MetaConverter;Lspace/kscience/dataforge/meta/Meta;)Ljava/lang/Object;
public static final fun nullableObjectToMeta (Lspace/kscience/dataforge/meta/transformations/MetaConverter;Ljava/lang/Object;)Lspace/kscience/dataforge/meta/Meta;
public static final fun valueToObject (Lspace/kscience/dataforge/meta/transformations/MetaConverter;Lspace/kscience/dataforge/meta/Value;)Ljava/lang/Object;
}
public final class space/kscience/dataforge/meta/transformations/MetaTransformation {
public static final field Companion Lspace/kscience/dataforge/meta/transformations/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 bind-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/ObservableMeta;Lspace/kscience/dataforge/meta/MutableMeta;)V
public static final synthetic fun box-impl (Ljava/util/Collection;)Lspace/kscience/dataforge/meta/transformations/MetaTransformation;
public static fun constructor-impl (Ljava/util/Collection;)Ljava/util/Collection;
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Ljava/util/Collection;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Ljava/util/Collection;Ljava/util/Collection;)Z
public static final fun generate-impl (Ljava/util/Collection;Lspace/kscience/dataforge/meta/Meta;)Lspace/kscience/dataforge/meta/Meta;
public fun hashCode ()I
public static fun hashCode-impl (Ljava/util/Collection;)I
public fun toString ()Ljava/lang/String;
public static fun toString-impl (Ljava/util/Collection;)Ljava/lang/String;
public final synthetic fun unbox-impl ()Ljava/util/Collection;
}
public final class space/kscience/dataforge/meta/transformations/MetaTransformation$Companion {
public final fun make-XNaMui4 (Lkotlin/jvm/functions/Function1;)Ljava/util/Collection;
}
public final class space/kscience/dataforge/meta/transformations/MetaTransformationBuilder {
public fun <init> ()V
public final fun build-050menU ()Ljava/util/Collection;
public final fun keep (Ljava/lang/String;)V
public final fun keep (Lkotlin/jvm/functions/Function1;)V
public final fun keep (Lspace/kscience/dataforge/names/Name;)V
public final fun move (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun move$default (Lspace/kscience/dataforge/meta/transformations/MetaTransformationBuilder;Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}
public final class space/kscience/dataforge/meta/transformations/RegexItemTransformationRule : space/kscience/dataforge/meta/transformations/TransformationRule {
public fun <init> (Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;)V
public final fun component1 ()Lkotlin/text/Regex;
public final fun component2 ()Lkotlin/jvm/functions/Function4;
public final fun copy (Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;)Lspace/kscience/dataforge/meta/transformations/RegexItemTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/transformations/RegexItemTransformationRule;Lkotlin/text/Regex;Lkotlin/jvm/functions/Function4;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/transformations/RegexItemTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getFrom ()Lkotlin/text/Regex;
public final fun getTransform ()Lkotlin/jvm/functions/Function4;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public final class space/kscience/dataforge/meta/transformations/SingleItemTransformationRule : space/kscience/dataforge/meta/transformations/TransformationRule {
public fun <init> (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;)V
public final fun component1 ()Lspace/kscience/dataforge/names/Name;
public final fun component2 ()Lkotlin/jvm/functions/Function3;
public final fun copy (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;)Lspace/kscience/dataforge/meta/transformations/SingleItemTransformationRule;
public static synthetic fun copy$default (Lspace/kscience/dataforge/meta/transformations/SingleItemTransformationRule;Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lspace/kscience/dataforge/meta/transformations/SingleItemTransformationRule;
public fun equals (Ljava/lang/Object;)Z
public final fun getFrom ()Lspace/kscience/dataforge/names/Name;
public final fun getTransform ()Lkotlin/jvm/functions/Function3;
public fun hashCode ()I
public fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
}
public abstract interface class space/kscience/dataforge/meta/transformations/TransformationRule {
public abstract fun matches (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;)Z
public fun selectItems (Lspace/kscience/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public abstract fun transformItem (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/meta/MutableMeta;)V
public final class space/kscience/dataforge/meta/descriptors/ValueRestriction$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class space/kscience/dataforge/misc/CastJvmKt {
@ -903,7 +940,7 @@ public abstract interface annotation class space/kscience/dataforge/misc/DFExper
public abstract interface annotation class space/kscience/dataforge/misc/DFInternal : java/lang/annotation/Annotation {
}
public abstract interface annotation class space/kscience/dataforge/misc/DfId : java/lang/annotation/Annotation {
public abstract interface annotation class space/kscience/dataforge/misc/DfType : java/lang/annotation/Annotation {
public abstract fun id ()Ljava/lang/String;
}
@ -920,6 +957,9 @@ public final class space/kscience/dataforge/misc/NamedKt {
public static final fun isAnonymous (Lspace/kscience/dataforge/misc/Named;)Z
}
public abstract interface annotation class space/kscience/dataforge/misc/UnsafeKType : java/lang/annotation/Annotation {
}
public final class space/kscience/dataforge/names/Name {
public static final field Companion Lspace/kscience/dataforge/names/Name$Companion;
public static final field NAME_SEPARATOR Ljava/lang/String;
@ -937,6 +977,16 @@ public final class space/kscience/dataforge/names/Name$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class space/kscience/dataforge/names/NameIndexComparator : java/util/Comparator {
public static final field INSTANCE Lspace/kscience/dataforge/names/NameIndexComparator;
public synthetic fun compare (Ljava/lang/Object;Ljava/lang/Object;)I
public fun compare (Ljava/lang/String;Ljava/lang/String;)I
}
public final class space/kscience/dataforge/names/NameIndexComparatorKt {
public static final fun getIndexedList (Lspace/kscience/dataforge/meta/Meta;Lspace/kscience/dataforge/names/Name;)Ljava/util/List;
}
public final class space/kscience/dataforge/names/NameKt {
public static final fun appendFirst (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name;
public static final fun appendLeft (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name;
@ -944,6 +994,7 @@ public final class space/kscience/dataforge/names/NameKt {
public static final fun asName (Lspace/kscience/dataforge/names/NameToken;)Lspace/kscience/dataforge/names/Name;
public static final fun cutFirst (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun cutLast (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Z
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z
public static final fun endsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z
public static final fun first (Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/NameToken;
@ -966,8 +1017,10 @@ public final class space/kscience/dataforge/names/NameKt {
public static final fun removeHeadOrNull (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Lspace/kscience/dataforge/names/Name;
public static final fun replaceLast (Lspace/kscience/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lspace/kscience/dataforge/names/Name;
public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Z
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/Name;)Z
public static final fun startsWith (Lspace/kscience/dataforge/names/Name;Lspace/kscience/dataforge/names/NameToken;)Z
public static final fun toStringUnescaped (Lspace/kscience/dataforge/names/Name;)Ljava/lang/String;
public static final fun withIndex (Lspace/kscience/dataforge/names/Name;Ljava/lang/String;)Lspace/kscience/dataforge/names/Name;
}

View File

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

View File

@ -31,7 +31,7 @@ private fun Meta.toJsonWithIndex(descriptor: MetaDescriptor?, index: String?): J
val pairs: MutableList<Pair<String, JsonElement>> = items.entries.groupBy {
it.key.body
}.mapTo(ArrayList()) { (body, list) ->
val childDescriptor = descriptor?.children?.get(body)
val childDescriptor = descriptor?.nodes?.get(body)
if (list.size == 1) {
val (token, element) = list.first()
//do not add an empty element

View File

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

View File

@ -2,8 +2,7 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import space.kscience.dataforge.misc.DfId
import space.kscience.dataforge.misc.unsafeCast
import space.kscience.dataforge.misc.DfType
import space.kscience.dataforge.names.*
import kotlin.jvm.JvmName
@ -31,7 +30,7 @@ public fun interface MetaProvider : ValueProvider {
* TODO add documentation
* Same name siblings are supported via elements with the same [Name] but different indices.
*/
@DfId(Meta.TYPE)
@DfType(Meta.TYPE)
@Serializable(MetaSerializer::class)
public interface Meta : MetaRepr, MetaProvider {
public val value: Value?
@ -151,6 +150,8 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta {
override val items: Map<NameToken, M>
public val self: M
override fun get(name: Name): M? {
tailrec fun M.find(name: Name): M? = if (name.isEmpty()) {
this
@ -164,11 +165,6 @@ public interface TypedMeta<out M : TypedMeta<M>> : Meta {
override fun toMeta(): Meta = this
}
/**
* Access self as a recursive type instance
*/
public inline val <M : TypedMeta<M>> TypedMeta<M>.self: M get() = unsafeCast()
//public typealias Meta = TypedMeta<*>
public operator fun <M : TypedMeta<M>> TypedMeta<M>?.get(token: NameToken): M? = this?.items?.get(token)
@ -188,10 +184,12 @@ public operator fun <M : TypedMeta<M>> M?.get(key: String): M? = this?.get(key.p
/**
* Get a sequence of [Name]-[Value] pairs using top-down traversal of the tree
* Get a sequence of [Name]-[Value] pairs using top-down traversal of the tree.
* The sequence includes root value with empty name
*/
public fun Meta.valueSequence(): Sequence<Pair<Name, Value>> = sequence {
items.forEach { (key, item) ->
value?.let { yield(Name.EMPTY to it) }
item.value?.let { itemValue ->
yield(key.asName() to itemValue)
}
@ -248,7 +246,7 @@ public inline fun <reified E : Enum<E>> Meta?.enum(): E? = this?.value?.let {
}
}
public val Meta.stringList: List<String>? get() = value?.list?.map { it.string }
public val Meta?.stringList: List<String>? get() = this?.value?.list?.map { it.string }
/**
* Create a provider that uses given provider for default values if those are not found in this provider

View File

@ -0,0 +1,159 @@
package space.kscience.dataforge.meta
import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.serializer
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.DFExperimental
/**
* A converter of generic object to and from [Meta]
*/
public interface MetaConverter<T>: MetaReader<T> {
/**
* A descriptor for resulting meta
*/
override val descriptor: MetaDescriptor? get() = null
/**
* Attempt conversion of [source] to an object or return null if conversion failed
*/
override fun readOrNull(source: Meta): T?
override fun read(source: Meta): T =
readOrNull(source) ?: error("Meta $source could not be interpreted by $this")
public fun convert(obj: T): Meta
public companion object {
public val meta: MetaConverter<Meta> = object : MetaConverter<Meta> {
override fun readOrNull(source: Meta): Meta = source
override fun convert(obj: Meta): Meta = obj
}
public val value: MetaConverter<Value> = object : MetaConverter<Value> {
override fun readOrNull(source: Meta): Value? = source.value
override fun convert(obj: Value): Meta = Meta(obj)
}
public val string: MetaConverter<String> = object : MetaConverter<String> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.STRING)
}
override fun readOrNull(source: Meta): String? = source.string
override fun convert(obj: String): Meta = Meta(obj.asValue())
}
public val boolean: MetaConverter<Boolean> = object : MetaConverter<Boolean> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.BOOLEAN)
}
override fun readOrNull(source: Meta): Boolean? = source.boolean
override fun convert(obj: Boolean): Meta = Meta(obj.asValue())
}
public val number: MetaConverter<Number> = object : MetaConverter<Number> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun readOrNull(source: Meta): Number? = source.number
override fun convert(obj: Number): Meta = Meta(obj.asValue())
}
public val double: MetaConverter<Double> = object : MetaConverter<Double> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun readOrNull(source: Meta): Double? = source.double
override fun convert(obj: Double): Meta = Meta(obj.asValue())
}
public val float: MetaConverter<Float> = object : MetaConverter<Float> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun readOrNull(source: Meta): Float? = source.float
override fun convert(obj: Float): Meta = Meta(obj.asValue())
}
public val int: MetaConverter<Int> = object : MetaConverter<Int> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun readOrNull(source: Meta): Int? = source.int
override fun convert(obj: Int): Meta = Meta(obj.asValue())
}
public val long: MetaConverter<Long> = object : MetaConverter<Long> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.NUMBER)
}
override fun readOrNull(source: Meta): Long? = source.long
override fun convert(obj: Long): Meta = Meta(obj.asValue())
}
public inline fun <reified E : Enum<E>> enum(): MetaConverter<E> = object : MetaConverter<E> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.STRING)
allowedValues(enumValues<E>())
}
@Suppress("USELESS_CAST")
override fun readOrNull(source: Meta): E = source.enum<E>() as? E ?: error("The Item is not a Enum")
override fun convert(obj: E): Meta = Meta(obj.asValue())
}
public fun <T> valueList(
writer: (T) -> Value = { Value.of(it) },
reader: (Value) -> T,
): MetaConverter<List<T>> = object : MetaConverter<List<T>> {
override val descriptor: MetaDescriptor = MetaDescriptor {
valueType(ValueType.LIST)
}
override fun readOrNull(source: Meta): List<T>? = source.value?.list?.map(reader)
override fun convert(obj: List<T>): Meta = Meta(obj.map(writer).asValue())
}
/**
* Automatically generate [MetaConverter] for a class using its serializer and optional [descriptor]
*/
@DFExperimental
public inline fun <reified T> serializable(
descriptor: MetaDescriptor? = null,
jsonEncoder: Json = Json,
): MetaConverter<T> = object : MetaConverter<T> {
private val serializer: KSerializer<T> = serializer()
override fun readOrNull(source: Meta): T? {
val json = source.toJson(descriptor)
return jsonEncoder.decodeFromJsonElement(serializer, json)
}
override fun convert(obj: T): Meta {
val json = jsonEncoder.encodeToJsonElement(obj)
return json.toMeta(descriptor)
}
}
}
}
public fun <T : Any> MetaConverter<T>.convertNullable(obj: T?): Meta? = obj?.let { convert(it) }

View File

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

View File

@ -0,0 +1,21 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.descriptors.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
*/
public fun readOrNull(source: Meta): T?
/**
* Read generic read-only meta with this [MetaReader] producing instance of the desired type.
* Throws an error if conversion could not be done.
*/
public fun read(source: Meta): T = readOrNull(source) ?: error("Meta $source could not be interpreted by $this")
}
public fun <T : Any> MetaReader<T>.readNullable(item: Meta?): T? = item?.let { read(it) }
public fun <T> MetaReader<T>.readValue(value: Value): T? = read(Meta(value))

View File

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

View File

@ -1,6 +1,5 @@
package space.kscience.dataforge.meta.transformations
package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import kotlin.jvm.JvmInline

View File

@ -19,6 +19,10 @@ public annotation class MetaBuilderMarker
public interface MutableMetaProvider : MetaProvider, MutableValueProvider {
override fun get(name: Name): MutableMeta?
public operator fun set(name: Name, node: Meta?)
/**
* Set value with the given name. Does nothing if value is not changed.
*/
override fun setValue(name: Name, value: Value?)
}
@ -48,11 +52,13 @@ public interface MutableMeta : Meta, MutableMetaProvider {
}
override fun setValue(name: Name, value: Value?) {
getOrCreate(name).value = value
if (value != getValue(name)) {
getOrCreate(name).value = value
}
}
/**
* Get existing node or create a new one
* Get an existing node or create a new one
*/
public fun getOrCreate(name: Name): MutableMeta
@ -122,6 +128,10 @@ public interface MutableMeta : Meta, MutableMetaProvider {
setValue(Name.parse(this), array.asValue())
}
public infix fun String.put(array: ByteArray) {
setValue(Name.parse(this), array.asValue())
}
public infix fun String.put(repr: MetaRepr) {
set(Name.parse(this), repr.toMeta())
}
@ -165,7 +175,7 @@ public fun MutableMetaProvider.remove(key: String) {
// node setters
public operator fun MutableMetaProvider.set(Key: NameToken, value: Meta): Unit = set(Key.asName(), value)
public operator fun MutableMetaProvider.set(key: NameToken, value: Meta): Unit = set(key.asName(), value)
public operator fun MutableMetaProvider.set(key: String, value: Meta): Unit = set(Name.parse(key), value)
@ -198,10 +208,8 @@ public operator fun MutableMetaProvider.set(key: String, metas: Iterable<Meta>):
/**
* Update existing mutable node with another node. The rules are following:
* * value replaces anything
* * node updates node and replaces anything but node
* * node list updates node list if number of nodes in the list is the same and replaces anything otherwise
* Update the existing mutable node with another node.
* Values that are present in the current provider and are missing in [meta] are kept.
*/
public fun MutableMetaProvider.update(meta: Meta) {
meta.valueSequence().forEach { (name, value) ->
@ -222,7 +230,7 @@ public fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.edit(name: Name, builde
getOrCreate(name).apply(builder)
/**
* Set a value at a given [name]. If node does not exist, create it.
* Set a value at a given [name]. If a node does not exist, create it.
*/
public operator fun <M : MutableTypedMeta<M>> MutableTypedMeta<M>.set(name: Name, value: Value?) {
edit(name) {
@ -245,6 +253,9 @@ private class MutableMetaImpl(
value: Value?,
children: Map<NameToken, Meta> = emptyMap(),
) : AbstractObservableMeta(), ObservableMutableMeta {
override val self get() = this
override var value = value
@ThreadSafe set(value) {
val oldValue = field
@ -324,8 +335,6 @@ private class MutableMetaImpl(
//remove child and invalidate if argument is null
if (node == null) {
children.remove(token)?.removeListener(this)
// old item is not null otherwise we can't be here
invalidate(name)
} else {
val newNode = wrapItem(node)
newNode.adoptBy(this, token)
@ -335,7 +344,7 @@ private class MutableMetaImpl(
else -> {
val token = name.firstOrNull()!!
//get existing or create new node.
//get an existing node or create a new node.
if (items[token] == null) {
val newNode = MutableMetaImpl(null)
newNode.adoptBy(this, token)
@ -369,16 +378,37 @@ public fun MutableMeta.append(name: Name, value: Value): Unit = append(name, Met
public fun MutableMeta.append(key: String, value: Value): Unit = append(Name.parse(key), value)
/**
* Update all items that exist in the [newMeta] and remove existing items that are missing in [newMeta].
* This produces the same result as clearing all items and updating blank meta with a [newMeta], but does not
* produce unnecessary invalidation events (if they are supported).
*/
public fun MutableMeta.reset(newMeta: Meta) {
//remove old items
(items.keys - newMeta.items.keys).forEach {
remove(it.asName())
}
newMeta.items.forEach { (token, item)->
set(token, item)
}
}
/**
* Create a mutable copy of this meta. The copy is created even if the Meta is already mutable
*/
public fun Meta.toMutableMeta(): ObservableMutableMeta = MutableMetaImpl(value, items)
public fun Meta.toMutableMeta(): MutableMeta =
MutableMeta { update(this@toMutableMeta) } //MutableMetaImpl(value, items)
public fun Meta.asMutableMeta(): MutableMeta = (this as? MutableMeta) ?: toMutableMeta()
@JsName("newObservableMutableMeta")
public fun ObservableMutableMeta(): ObservableMutableMeta = MutableMetaImpl(null)
/**
* Create a pre-filled [ObservableMutableMeta]
*/
public fun ObservableMutableMeta(content: Meta): ObservableMutableMeta = ObservableMutableMeta { update(content) }
/**
* Build a [MutableMeta] using given transformation
*/
@ -387,12 +417,14 @@ public inline fun ObservableMutableMeta(builder: MutableMeta.() -> Unit = {}): O
/**
* Create a copy of this [Meta], optionally applying the given [block].
* The listeners of the original Config are not retained.
* Create a read-only copy of this [Meta]. [modification] is an optional modification applied to [Meta] on copy.
*
* The copy does not reflect changes of the initial Meta.
*/
public inline fun Meta.copy(block: MutableMeta.() -> Unit = {}): Meta =
toMutableMeta().apply(block)
public inline fun Meta.copy(modification: MutableMeta.() -> Unit = {}): Meta = Meta {
update(this@copy)
modification()
}
private class MutableMetaWithDefault(
val source: MutableMeta, val default: MetaProvider, val rootName: Name,

View File

@ -1,52 +1,123 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.transformations.MetaConverter
import space.kscience.dataforge.meta.descriptors.Described
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import space.kscience.dataforge.names.getIndexedList
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/* Read-write delegates */
public fun MutableMetaProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> =
object : ReadWriteProperty<Any?, Meta?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? {
return get(key ?: property.name.asName())
}
public interface MutableMetaDelegate<T> : ReadWriteProperty<Any?, T>, Described
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
val name = key ?: property.name.asName()
set(name, value)
}
public fun MutableMetaProvider.node(
key: Name? = null,
descriptor: MetaDescriptor? = null,
): MutableMetaDelegate<Meta?> = object : MutableMetaDelegate<Meta?> {
override val descriptor: MetaDescriptor? = descriptor
override fun getValue(thisRef: Any?, property: KProperty<*>): Meta? {
return get(key ?: property.name.asName())
}
public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConverter<T>): ReadWriteProperty<Any?, T?> =
object : ReadWriteProperty<Any?, T?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
return get(key ?: property.name.asName())?.let { converter.metaToObject(it) }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Meta?) {
val name = key ?: property.name.asName()
set(name, value)
}
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
val name = key ?: property.name.asName()
set(name, value?.let { converter.objectToMeta(it) })
}
/**
* Use [converter] to transform an object to Meta and back.
* Note that mutation of the object does not change Meta.
*/
public fun <T> MutableMetaProvider.convertable(
converter: MetaConverter<T>,
key: Name? = null,
): MutableMetaDelegate<T?> = object : MutableMetaDelegate<T?> {
override val descriptor: MetaDescriptor? get() = converter.descriptor
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val name = key ?: property.name.asName()
return get(name)?.let { converter.read(it) }
}
public fun MutableMetaProvider.value(key: Name? = null): ReadWriteProperty<Any?, Value?> =
object : ReadWriteProperty<Any?, Value?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
get(key ?: property.name.asName())?.value
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
setValue(key ?: property.name.asName(), value)
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
val name = key ?: property.name.asName()
set(name, value?.let { converter.convert(it) })
}
}
@Deprecated("Use convertable", ReplaceWith("convertable(converter, key)"))
public fun <T> MutableMetaProvider.node(key: Name? = null, converter: MetaConverter<T>): MutableMetaDelegate<T?> =
convertable(converter, key)
/**
* Use object serializer to transform it to Meta and back.
* Note that mutation of the object does not change Meta.
*/
@DFExperimental
public inline fun <reified T> MutableMetaProvider.serializable(
descriptor: MetaDescriptor? = null,
key: Name? = null,
): MutableMetaDelegate<T?> = convertable(MetaConverter.serializable(descriptor), key)
/**
* Use [converter] to convert a list of same name siblings meta to object and back.
* Note that mutation of the object does not change Meta.
*/
public fun <T> MutableMeta.listOfConvertable(
converter: MetaConverter<T>,
key: Name? = null,
): MutableMetaDelegate<List<T>> = object : MutableMetaDelegate<List<T>> {
override val descriptor: MetaDescriptor? = converter.descriptor?.copy(multiple = true)
override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
val name = key ?: property.name.asName()
return getIndexedList(name).map { converter.read(it) }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) {
val name = key ?: property.name.asName()
setIndexed(name, value.map { converter.convert(it) })
}
}
@DFExperimental
public inline fun <reified T> MutableMeta.listOfSerializable(
key: Name? = null,
descriptor: MetaDescriptor? = null,
): MutableMetaDelegate<List<T>> = listOfConvertable(MetaConverter.serializable(descriptor), key)
public fun MutableMetaProvider.value(
key: Name? = null,
descriptor: MetaDescriptor? = null,
): MutableMetaDelegate<Value?> = object : MutableMetaDelegate<Value?> {
override val descriptor: MetaDescriptor? = descriptor
override fun getValue(thisRef: Any?, property: KProperty<*>): Value? =
get(key ?: property.name.asName())?.value
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Value?) {
setValue(key ?: property.name.asName(), value)
}
}
public fun <T> MutableMetaProvider.value(
key: Name? = null,
writer: (T) -> Value? = { Value.of(it) },
reader: (Value?) -> T
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
descriptor: MetaDescriptor? = null,
reader: (Value?) -> T,
): MutableMetaDelegate<T> = object : MutableMetaDelegate<T> {
override val descriptor: MetaDescriptor? = descriptor
override fun getValue(thisRef: Any?, property: KProperty<*>): T =
reader(get(key ?: property.name.asName())?.value)
@ -57,65 +128,65 @@ public fun <T> MutableMetaProvider.value(
/* Read-write delegates for [MutableItemProvider] */
public fun MutableMetaProvider.string(key: Name? = null): ReadWriteProperty<Any?, String?> =
public fun MutableMetaProvider.string(key: Name? = null): MutableMetaDelegate<String?> =
value(key) { it?.string }
public fun MutableMetaProvider.boolean(key: Name? = null): ReadWriteProperty<Any?, Boolean?> =
public fun MutableMetaProvider.boolean(key: Name? = null): MutableMetaDelegate<Boolean?> =
value(key) { it?.boolean }
public fun MutableMetaProvider.number(key: Name? = null): ReadWriteProperty<Any?, Number?> =
public fun MutableMetaProvider.number(key: Name? = null): MutableMetaDelegate<Number?> =
value(key) { it?.number }
public fun MutableMetaProvider.string(default: String, key: Name? = null): ReadWriteProperty<Any?, String> =
public fun MutableMetaProvider.string(default: String, key: Name? = null): MutableMetaDelegate<String> =
value(key) { it?.string ?: default }
public fun MutableMetaProvider.boolean(default: Boolean, key: Name? = null): ReadWriteProperty<Any?, Boolean> =
public fun MutableMetaProvider.boolean(default: Boolean, key: Name? = null): MutableMetaDelegate<Boolean> =
value(key) { it?.boolean ?: default }
public fun MutableMetaProvider.number(default: Number, key: Name? = null): ReadWriteProperty<Any?, Number> =
public fun MutableMetaProvider.number(default: Number, key: Name? = null): MutableMetaDelegate<Number> =
value(key) { it?.number ?: default }
public fun MutableMetaProvider.string(key: Name? = null, default: () -> String): ReadWriteProperty<Any?, String> =
public fun MutableMetaProvider.string(key: Name? = null, default: () -> String): MutableMetaDelegate<String> =
value(key) { it?.string ?: default() }
public fun MutableMetaProvider.boolean(key: Name? = null, default: () -> Boolean): ReadWriteProperty<Any?, Boolean> =
public fun MutableMetaProvider.boolean(key: Name? = null, default: () -> Boolean): MutableMetaDelegate<Boolean> =
value(key) { it?.boolean ?: default() }
public fun MutableMetaProvider.number(key: Name? = null, default: () -> Number): ReadWriteProperty<Any?, Number> =
public fun MutableMetaProvider.number(key: Name? = null, default: () -> Number): MutableMetaDelegate<Number> =
value(key) { it?.number ?: default() }
public inline fun <reified E : Enum<E>> MutableMetaProvider.enum(
default: E,
key: Name? = null,
): ReadWriteProperty<Any?, E> = value(key) { value -> value?.string?.let { enumValueOf<E>(it) } ?: default }
): MutableMetaDelegate<E> = value(key) { value -> value?.string?.let { enumValueOf<E>(it) } ?: default }
/* Number delegates */
public fun MutableMetaProvider.int(key: Name? = null): ReadWriteProperty<Any?, Int?> =
public fun MutableMetaProvider.int(key: Name? = null): MutableMetaDelegate<Int?> =
value(key) { it?.int }
public fun MutableMetaProvider.double(key: Name? = null): ReadWriteProperty<Any?, Double?> =
public fun MutableMetaProvider.double(key: Name? = null): MutableMetaDelegate<Double?> =
value(key) { it?.double }
public fun MutableMetaProvider.long(key: Name? = null): ReadWriteProperty<Any?, Long?> =
public fun MutableMetaProvider.long(key: Name? = null): MutableMetaDelegate<Long?> =
value(key) { it?.long }
public fun MutableMetaProvider.float(key: Name? = null): ReadWriteProperty<Any?, Float?> =
public fun MutableMetaProvider.float(key: Name? = null): MutableMetaDelegate<Float?> =
value(key) { it?.float }
/* Safe number delegates*/
public fun MutableMetaProvider.int(default: Int, key: Name? = null): ReadWriteProperty<Any?, Int> =
public fun MutableMetaProvider.int(default: Int, key: Name? = null): MutableMetaDelegate<Int> =
value(key) { it?.int ?: default }
public fun MutableMetaProvider.double(default: Double, key: Name? = null): ReadWriteProperty<Any?, Double> =
public fun MutableMetaProvider.double(default: Double, key: Name? = null): MutableMetaDelegate<Double> =
value(key) { it?.double ?: default }
public fun MutableMetaProvider.long(default: Long, key: Name? = null): ReadWriteProperty<Any?, Long> =
public fun MutableMetaProvider.long(default: Long, key: Name? = null): MutableMetaDelegate<Long> =
value(key) { it?.long ?: default }
public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWriteProperty<Any?, Float> =
public fun MutableMetaProvider.float(default: Float, key: Name? = null): MutableMetaDelegate<Float> =
value(key) { it?.float ?: default }
@ -124,7 +195,7 @@ public fun MutableMetaProvider.float(default: Float, key: Name? = null): ReadWri
public fun MutableMetaProvider.stringList(
vararg default: String,
key: Name? = null,
): ReadWriteProperty<Any?, List<String>> = value(
): MutableMetaDelegate<List<String>> = value(
key,
writer = { list -> list.map { str -> str.asValue() }.asValue() },
reader = { it?.stringList ?: listOf(*default) },
@ -132,7 +203,7 @@ public fun MutableMetaProvider.stringList(
public fun MutableMetaProvider.stringList(
key: Name? = null,
): ReadWriteProperty<Any?, List<String>?> = value(
): MutableMetaDelegate<List<String>?> = value(
key,
writer = { it -> it?.map { str -> str.asValue() }?.asValue() },
reader = { it?.stringList },
@ -141,29 +212,18 @@ public fun MutableMetaProvider.stringList(
public fun MutableMetaProvider.numberList(
vararg default: Number,
key: Name? = null,
): ReadWriteProperty<Any?, List<Number>> = value(
): MutableMetaDelegate<List<Number>> = value(
key,
writer = { it.map { num -> num.asValue() }.asValue() },
reader = { it?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) },
)
/* A special delegate for double arrays */
public fun MutableMetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadWriteProperty<Any?, DoubleArray> = value(
key,
writer = { DoubleArrayValue(it) },
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public fun <T> MutableMetaProvider.listValue(
key: Name? = null,
writer: (T) -> Value = { Value.of(it) },
reader: (Value) -> T,
): ReadWriteProperty<Any?, List<T>?> = value(
): MutableMetaDelegate<List<T>?> = value(
key,
writer = { it?.map(writer)?.asValue() },
reader = { it?.list?.map(reader) }

View File

@ -1,8 +1,10 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.*
import kotlin.reflect.KProperty1
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.cutFirst
import space.kscience.dataforge.names.firstOrNull
import space.kscience.dataforge.names.isEmpty
internal data class MetaListener(
@ -15,12 +17,15 @@ internal data class MetaListener(
*/
public interface ObservableMeta : Meta {
/**
* Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed
* Add change listener to this meta. The Owner is declared to be able to remove listeners later.
* Listeners without an owner could be only removed all together.
*
* `this` object in the listener represents the current state of this meta. The name points to a changed node
*/
public fun onChange(owner: Any?, callback: Meta.(name: Name) -> Unit)
/**
* Remove all listeners belonging to given owner
* Remove all listeners belonging to the given [owner]. Passing null removes all listeners.
*/
public fun removeListener(owner: Any?)
@ -34,6 +39,9 @@ public interface ObservableMeta : Meta {
* A [Meta] which is both observable and mutable
*/
public interface ObservableMutableMeta : ObservableMeta, MutableMeta, MutableTypedMeta<ObservableMutableMeta> {
override val self: ObservableMutableMeta get() = this
override fun getOrCreate(name: Name): ObservableMutableMeta
override fun get(name: Name): ObservableMutableMeta? {
@ -67,24 +75,4 @@ internal abstract class AbstractObservableMeta : ObservableMeta {
override fun toString(): String = Meta.toString(this)
override fun equals(other: Any?): Boolean = Meta.equals(this, other as? Meta)
override fun hashCode(): Int = Meta.hashCode(this)
}
/**
* Use the value of the property in a [callBack].
* The callback is called once immediately after subscription to pass the initial value.
*
* Optional [owner] property is used for
*/
public fun <S : Scheme, T> S.useProperty(
property: KProperty1<S, T>,
owner: Any? = null,
callBack: S.(T) -> Unit,
) {
//Pass initial value.
callBack(property.get(this))
meta.onChange(owner) { name ->
if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty))
}
}
}

View File

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

View File

@ -7,36 +7,45 @@ import space.kscience.dataforge.meta.descriptors.validate
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.misc.ThreadSafe
import space.kscience.dataforge.names.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty1
/**
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [Specification].
* Default item provider and [MetaDescriptor] are optional
* A base for delegate-based or descriptor-based scheme. [Scheme] has an empty constructor to simplify usage from [MetaReader].
*
* @param prototype default values provided by this scheme
*/
public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurable {
public open class Scheme(
private var prototype: Meta? = null,
descriptor: MetaDescriptor? = null,
) : Described, MetaRepr, MutableMetaProvider, Configurable {
/**
* Meta to be mutated by this schme
* Meta to be mutated by this scheme
*/
private var targetMeta: MutableMeta = MutableMeta()
internal var target: MutableMeta = MutableMeta()
/**
* Default values provided by this scheme
* A descriptor of this scheme
*/
private var defaultMeta: Meta? = null
final override var descriptor: MetaDescriptor? = descriptor
private set
final override val meta: ObservableMutableMeta = SchemeMeta(Name.EMPTY)
final override var descriptor: MetaDescriptor? = null
internal set
internal fun wrap(
newMeta: MutableMeta,
preserveDefault: Boolean = false,
/**
* This method must be called before the scheme could be used
*/
internal fun initialize(
target: MutableMeta,
prototype: Meta,
descriptor: MetaDescriptor?,
) {
if (preserveDefault) {
defaultMeta = targetMeta.seal()
}
targetMeta = newMeta
this.target = target
this.prototype = prototype
this.descriptor = descriptor
}
/**
@ -47,11 +56,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
return descriptor?.validate(meta) ?: true
}
override fun get(name: Name): MutableMeta? = meta.get(name)
override fun get(name: Name): MutableMeta? = meta[name]
override fun set(name: Name, node: Meta?) {
if (validate(name, meta)) {
meta.set(name, node)
meta[name] = node
} else {
error("Validation failed for node $node at $name")
}
@ -68,14 +77,19 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
private val listeners: MutableList<MetaListener> = mutableListOf()
override fun toString(): String = meta.toString()
private inner class SchemeMeta(val pathName: Name) : ObservableMutableMeta {
override val self get() = this
override var value: Value?
get() = targetMeta[pathName]?.value
?: defaultMeta?.get(pathName)?.value
get() = target[pathName]?.value
?: prototype?.get(pathName)?.value
?: descriptor?.get(pathName)?.defaultValue
set(value) {
val oldValue = targetMeta[pathName]?.value
targetMeta[pathName] = value
val oldValue = target[pathName]?.value
target[pathName] = value
if (oldValue != value) {
invalidate(Name.EMPTY)
}
@ -83,8 +97,8 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
override val items: Map<NameToken, ObservableMutableMeta>
get() {
val targetKeys = targetMeta[pathName]?.items?.keys ?: emptySet()
val defaultKeys = defaultMeta?.get(pathName)?.items?.keys ?: emptySet()
val targetKeys = target[pathName]?.items?.keys ?: emptySet()
val defaultKeys = prototype?.get(pathName)?.items?.keys ?: emptySet()
return (targetKeys + defaultKeys).associateWith { SchemeMeta(pathName + it) }
}
@ -111,7 +125,7 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
override fun hashCode(): Int = Meta.hashCode(this)
override fun set(name: Name, node: Meta?) {
targetMeta.set(name, node)
target[pathName + name] = node
invalidate(name)
}
@ -119,7 +133,6 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
@DFExperimental
override fun attach(name: Name, node: ObservableMutableMeta) {
//TODO implement zero-copy attachment
set(name, node)
node.onChange(this) { changeName ->
set(name + changeName, this[changeName])
@ -131,10 +144,11 @@ public open class Scheme : Described, MetaRepr, MutableMetaProvider, Configurabl
/**
* Relocate scheme target onto given [MutableMeta]. Old provider does not get updates anymore.
* Current state of the scheme used as a default.
* The Current state of the scheme that os used as a default.
*/
@DFExperimental
public fun <T : Scheme> T.retarget(provider: MutableMeta): T = apply {
wrap(provider, true)
initialize(provider, meta.seal(), descriptor)
}
/**
@ -151,26 +165,150 @@ public inline fun <T : Scheme> T.copy(spec: SchemeSpec<T>, block: T.() -> Unit =
/**
* A specification for simplified generation of wrappers
*/
public open class SchemeSpec<out T : Scheme>(
public open class SchemeSpec<T : Scheme>(
private val builder: () -> T,
) : Specification<T> {
) : MetaConverter<T> {
override fun read(source: Meta): T = builder().also {
it.wrap(MutableMeta().withDefault(source))
}
override fun write(target: MutableMeta): T = empty().also {
it.wrap(target)
}
//TODO Generate descriptor from Scheme class
override val descriptor: MetaDescriptor? get() = null
override fun empty(): T = builder().also {
it.descriptor = descriptor
override fun readOrNull(source: Meta): T = builder().also {
it.initialize(MutableMeta(), source, descriptor)
}
@Suppress("OVERRIDE_BY_INLINE")
final override inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
/**
* Write changes made to the [Scheme] to target [MutableMeta]. If the empty [Scheme] contains any data it is copied to the target.
*/
public fun write(target: MutableMeta): T = empty().also {
target.update(it.meta)
it.initialize(target, Meta.EMPTY, descriptor)
}
/**
* Generate a blank object. The object could contain some elements if they are defined in a constructor
*/
public fun empty(): T = builder().also {
it.initialize(MutableMeta(), it.target, descriptor)
}
override fun convert(obj: T): Meta = obj.meta
/**
* A convenience method to use specifications in builders
*/
public inline operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
}
/**
* Update a [MutableMeta] using given specification
*/
public fun <T : Scheme> MutableMeta.updateWith(
spec: SchemeSpec<T>,
action: T.() -> Unit,
): T = spec.write(this).apply(action)
/**
* Update configuration using given specification
*/
public fun <T : Scheme> Configurable.updateWith(
spec: SchemeSpec<T>,
action: T.() -> Unit,
): T = spec.write(meta).apply(action)
/**
* A delegate that uses a [MetaReader] to wrap a child of this provider
*/
public fun <T : Scheme> MutableMeta.scheme(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val name = key ?: property.name.asName()
return spec.write(getOrCreate(name))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val name = key ?: property.name.asName()
set(name, value.toMeta())
}
}
public fun <T : Scheme> Scheme.scheme(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T> = meta.scheme(spec, key)
/**
* A delegate that uses a [MetaReader] to wrap a child of this provider.
* Returns null if meta with given name does not exist.
*/
public fun <T : Scheme> MutableMeta.schemeOrNull(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val name = key ?: property.name.asName()
return if (get(name) == null) null else spec.write(getOrCreate(name))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
val name = key ?: property.name.asName()
if (value == null) remove(name)
else set(name, value.toMeta())
}
}
public fun <T : Scheme> Scheme.schemeOrNull(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T?> = meta.schemeOrNull(spec, key)
/**
* A delegate that uses a [MetaReader] to wrap a list of child providers.
* If children are mutable, the changes in list elements are reflected on them.
* The list is a snapshot of children state, so change in structure is not reflected on its composition.
*/
public fun <T : Scheme> MutableMeta.listOfScheme(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
val name = key ?: property.name.asName()
return getIndexedList(name).map { spec.write(it as MutableMeta) }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) {
val name = key ?: property.name.asName()
setIndexed(name, value.map { it.toMeta() })
}
}
public fun <T : Scheme> Scheme.listOfScheme(
spec: SchemeSpec<T>,
key: Name? = null,
): ReadWriteProperty<Any?, List<T>> = meta.listOfScheme(spec, key)
/**
* Use the value of the property in a [callBack].
* The callback is called once immediately after subscription to pass the initial value.
*
* Optional [owner] property is used for
*/
public fun <S : Scheme, T> S.useProperty(
property: KProperty1<S, T>,
owner: Any? = null,
callBack: S.(T) -> Unit,
) {
//Pass initial value.
callBack(property.get(this))
meta.onChange(owner) { name ->
if (name.startsWith(property.name.asName())) {
callBack(property.get(this@useProperty))
}
}
}

View File

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

View File

@ -1,130 +0,0 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.meta.descriptors.Described
import space.kscience.dataforge.misc.DFExperimental
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.asName
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
public interface ReadOnlySpecification<out T : Any>: Described {
/**
* Read generic read-only meta with this [Specification] producing instance of desired type.
* The source is not mutated even if it is in theory mutable
*/
public fun read(source: Meta): T
/**
* Generate an empty object
*/
public fun empty(): T
/**
* A convenience method to use specifications in builders
*/
public operator fun invoke(action: T.() -> Unit): T = empty().apply(action)
}
/**
* Allows to apply custom configuration in a type safe way to simple untyped configuration.
* By convention [Scheme] companion should inherit this class
*
*/
public interface Specification<out T : Any> : ReadOnlySpecification<T> {
/**
* Wrap [MutableMeta], using it as inner storage (changes to [Specification] are reflected on [MutableMeta]
*/
public fun write(target: MutableMeta): T
}
/**
* Update a [MutableMeta] using given specification
*/
public fun <T : Any> MutableMeta.updateWith(
spec: Specification<T>,
action: T.() -> Unit,
): T = spec.write(this).apply(action)
/**
* Update configuration using given specification
*/
public fun <T : Any> Configurable.updateWith(
spec: Specification<T>,
action: T.() -> Unit,
): T = spec.write(meta).apply(action)
//
//public fun <M : MutableTypedMeta<M>> MutableMeta.withSpec(spec: Specification<M>): M? =
// spec.write(it)
/**
* A delegate that uses a [Specification] to wrap a child of this provider
*/
public fun <T : Scheme> MutableMeta.spec(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val name = key ?: property.name.asName()
return spec.write(getOrCreate(name))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val name = key ?: property.name.asName()
set(name, value.toMeta())
}
}
public fun <T : Scheme> Scheme.spec(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T> = meta.spec(spec, key)
/**
* A delegate that uses a [Specification] to wrap a child of this provider.
* Returns null if meta with given name does not exist.
*/
public fun <T : Scheme> MutableMeta.specOrNull(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
val name = key ?: property.name.asName()
return if (get(name) == null) null else spec.write(getOrCreate(name))
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) {
val name = key ?: property.name.asName()
if (value == null) remove(name)
else set(name, value.toMeta())
}
}
public fun <T : Scheme> Scheme.specOrNull(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, T?> = meta.specOrNull(spec, key)
/**
* A delegate that uses a [Specification] to wrap a list of child providers.
* If children are mutable, the changes in list elements are reflected on them.
* The list is a snapshot of children state, so change in structure is not reflected on its composition.
*/
@DFExperimental
public fun <T : Scheme> MutableMeta.listOfSpec(
spec: Specification<T>,
key: Name? = null,
): ReadWriteProperty<Any?, List<T>> = object : ReadWriteProperty<Any?, List<T>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): List<T> {
val name = key ?: property.name.asName()
return getIndexed(name).values.map { spec.write(it as MutableMeta) }
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: List<T>) {
val name = key ?: property.name.asName()
setIndexed(name, value.map { it.toMeta() })
}
}

View File

@ -256,8 +256,6 @@ public fun ShortArray.asValue(): Value = if (isEmpty()) Null else ListValue(map
public fun FloatArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
public fun ByteArray.asValue(): Value = if (isEmpty()) Null else ListValue(map { NumberValue(it) })
public fun <E : Enum<E>> E.asValue(): Value = EnumValue(this)

View File

@ -7,6 +7,7 @@ import space.kscience.dataforge.names.*
/**
* Restrictions on value in the node
*/
@Serializable
public enum class ValueRestriction {
/**
* No restrictions
@ -27,7 +28,7 @@ public enum class ValueRestriction {
/**
* The descriptor for a meta
* @param description description text
* @param children child descriptors for this node
* @param nodes child descriptors for this node
* @param multiple True if same name siblings with this name are allowed
* @param valueRestriction The requirements for node content
* @param valueTypes list of allowed types for [Meta.value], null if all values are allowed.
@ -39,7 +40,7 @@ public enum class ValueRestriction {
@Serializable
public data class MetaDescriptor(
public val description: String? = null,
public val children: Map<String, MetaDescriptor> = emptyMap(),
public val nodes: Map<String, MetaDescriptor> = emptyMap(),
public val multiple: Boolean = false,
public val valueRestriction: ValueRestriction = ValueRestriction.NONE,
public val valueTypes: List<ValueType>? = null,
@ -47,6 +48,9 @@ public data class MetaDescriptor(
public val defaultValue: Value? = null,
public val attributes: Meta = Meta.EMPTY,
) {
@Deprecated("Replace by nodes", ReplaceWith("nodes"))
public val children: Map<String, MetaDescriptor> get() = nodes
/**
* A node constructed of default values for this descriptor and its children
*/
@ -55,7 +59,7 @@ public data class MetaDescriptor(
defaultValue?.let { defaultValue ->
this.value = defaultValue
}
children.forEach { (key, descriptor) ->
nodes.forEach { (key, descriptor) ->
set(key, descriptor.defaultNode)
}
}
@ -67,13 +71,13 @@ public data class MetaDescriptor(
}
}
public val MetaDescriptor.required: Boolean get() = valueRestriction == ValueRestriction.REQUIRED || children.values.any { required }
public val MetaDescriptor.required: Boolean get() = valueRestriction == ValueRestriction.REQUIRED || nodes.values.any { required }
public val MetaDescriptor.allowedValues: List<Value>? get() = attributes[MetaDescriptor.ALLOWED_VALUES_KEY]?.value?.list
public operator fun MetaDescriptor.get(name: Name): MetaDescriptor? = when (name.length) {
0 -> this
1 -> children[name.firstOrNull()!!.toString()]
1 -> nodes[name.firstOrNull()!!.toString()]
else -> get(name.firstOrNull()!!.asName())?.get(name.cutFirst())
}
@ -95,7 +99,7 @@ public fun MetaDescriptor.validate(item: Meta?): Boolean {
if (item == null) return !required
if (!validate(item.value)) return false
children.forEach { (key, childDescriptor) ->
nodes.forEach { (key, childDescriptor) ->
if (!childDescriptor.validate(item[key])) return false
}
return true

View File

@ -9,7 +9,8 @@ import space.kscience.dataforge.names.length
import kotlin.collections.set
public class MetaDescriptorBuilder @PublishedApi internal constructor() {
public var info: String? = null
public var description: String? = null
public var children: MutableMap<String, MetaDescriptorBuilder> = linkedMapOf()
public var multiple: Boolean = false
public var valueRestriction: ValueRestriction = ValueRestriction.NONE
@ -40,38 +41,28 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
attributes.apply(block)
}
public fun item(name: Name, block: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptorBuilder {
return when (name.length) {
0 -> apply(block)
internal fun node(
name: Name,
descriptorBuilder: MetaDescriptorBuilder,
): Unit {
when (name.length) {
0 -> error("Can't set descriptor to root")
1 -> {
val target = MetaDescriptorBuilder().apply(block)
children[name.first().body] = target
target
children[name.first().body] = descriptorBuilder
}
else -> {
children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), block)
}
else -> children.getOrPut(name.first().body) {
MetaDescriptorBuilder()
}.node(name.cutFirst(), descriptorBuilder)
}
}
public fun node(
name: Name,
descriptor: MetaDescriptor,
block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = when (name.length) {
0 -> error("Can't set descriptor to root")
1 -> {
val item = descriptor.toBuilder().apply {
valueRestriction = ValueRestriction.ABSENT
}.apply(block)
children[name.first().body] = item
item
}
else -> children.getOrPut(name.first().body) {
MetaDescriptorBuilder()
}.node(name.cutFirst(), descriptor, block)
descriptorBuilder: MetaDescriptor,
): Unit {
node(name, descriptorBuilder.toBuilder())
}
public var allowedValues: List<Value>
@ -85,10 +76,21 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
allowedValues = values.map { Value.of(it) }
}
public fun from(descriptor: MetaDescriptor) {
description = descriptor.description
children.putAll(descriptor.nodes.mapValues { it.value.toBuilder() })
multiple = descriptor.multiple
valueRestriction = descriptor.valueRestriction
valueTypes = descriptor.valueTypes
indexKey = descriptor.indexKey
default = descriptor.defaultValue
attributes.update(descriptor.attributes)
}
@PublishedApi
internal fun build(): MetaDescriptor = MetaDescriptor(
description = info,
children = children.mapValues { it.value.build() },
description = description,
nodes = children.mapValues { it.value.build() },
multiple = multiple,
valueRestriction = valueRestriction,
valueTypes = valueTypes,
@ -98,12 +100,57 @@ public class MetaDescriptorBuilder @PublishedApi internal constructor() {
)
}
public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder =
item(Name.parse(name), block)
//public fun MetaDescriptorBuilder.item(name: String, block: MetaDescriptorBuilder.() -> Unit): MetaDescriptorBuilder =
// item(Name.parse(name), block)
public inline fun MetaDescriptor(block: MetaDescriptorBuilder.() -> Unit): MetaDescriptor =
MetaDescriptorBuilder().apply(block).build()
/**
* Create and configure child node descriptor
*/
public fun MetaDescriptorBuilder.node(
name: Name,
block: MetaDescriptorBuilder.() -> Unit,
) {
node(
name,
MetaDescriptorBuilder().apply(block)
)
}
public fun MetaDescriptorBuilder.node(name: String, descriptor: MetaDescriptor) {
node(Name.parse(name), descriptor)
}
public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder.() -> Unit) {
node(Name.parse(name), block)
}
public fun MetaDescriptorBuilder.node(
key: String,
base: Described,
block: MetaDescriptorBuilder.() -> Unit = {},
) {
node(Name.parse(key), base.descriptor?.toBuilder()?.apply(block) ?: MetaDescriptorBuilder())
}
public fun MetaDescriptorBuilder.required() {
valueRestriction = ValueRestriction.REQUIRED
}
private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
description = this@toBuilder.description
children = this@toBuilder.nodes.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
multiple = this@toBuilder.multiple
valueRestriction = this@toBuilder.valueRestriction
valueTypes = this@toBuilder.valueTypes
indexKey = this@toBuilder.indexKey
default = defaultValue
attributes = this@toBuilder.attributes.toMutableMeta()
}
/**
* Create and configure child value descriptor
*/
@ -112,7 +159,7 @@ public fun MetaDescriptorBuilder.value(
type: ValueType,
vararg additionalTypes: ValueType,
block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = item(name) {
): Unit = node(name) {
valueType(type, *additionalTypes)
block()
}
@ -122,41 +169,14 @@ public fun MetaDescriptorBuilder.value(
type: ValueType,
vararg additionalTypes: ValueType,
block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = value(Name.parse(name), type, additionalTypes = additionalTypes, block)
): Unit = value(Name.parse(name), type, additionalTypes = additionalTypes, block)
/**
* Create and configure child value descriptor
*/
public fun MetaDescriptorBuilder.node(
name: Name, block: MetaDescriptorBuilder.() -> Unit,
): MetaDescriptorBuilder = item(name) {
valueRestriction = ValueRestriction.ABSENT
block()
}
public fun MetaDescriptorBuilder.node(name: String, block: MetaDescriptorBuilder.() -> Unit) {
node(Name.parse(name), block)
}
public fun MetaDescriptorBuilder.node(
key: String,
described: Described,
block: MetaDescriptorBuilder.() -> Unit = {},
) {
described.descriptor?.let {
node(Name.parse(key), it, block)
}
}
public fun MetaDescriptorBuilder.required() {
valueRestriction = ValueRestriction.REQUIRED
}
public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
key: Name,
default: E?,
crossinline modifier: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = value(key, ValueType.STRING) {
): Unit = value(key, ValueType.STRING) {
default?.let {
this.default = default.asValue()
}
@ -164,17 +184,6 @@ public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
modifier()
}
private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
info = this@toBuilder.description
children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
multiple = this@toBuilder.multiple
valueRestriction = this@toBuilder.valueRestriction
valueTypes = this@toBuilder.valueTypes
indexKey = this@toBuilder.indexKey
default = defaultValue
attributes = this@toBuilder.attributes.toMutableMeta()
}
/**
* Make a deep copy of this descriptor applying given transformation [block]
*/

View File

@ -6,10 +6,13 @@ import space.kscience.dataforge.meta.ValueType
import kotlin.reflect.KProperty1
import kotlin.reflect.typeOf
/**
* Add a value item to a [MetaDescriptor] inferring some of its properties from the type
*/
public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
property: KProperty1<S, T>,
noinline block: MetaDescriptorBuilder.() -> Unit = {},
): MetaDescriptorBuilder = when (typeOf<T>()) {
): Unit = when (typeOf<T>()) {
typeOf<Number>(), typeOf<Int>(), typeOf<Double>(), typeOf<Short>(), typeOf<Long>(), typeOf<Float>() ->
value(property.name, ValueType.NUMBER) {
block()
@ -34,9 +37,12 @@ public inline fun <S : Scheme, reified T> MetaDescriptorBuilder.value(
multiple = true
block()
}
else -> item(property.name, block)
else -> node(property.name, block)
}
/**
* Add a schem-based branch to a [MetaDescriptor]
*/
public inline fun <S : Scheme, reified T : Scheme> MetaDescriptorBuilder.scheme(
property: KProperty1<S, T>,
spec: SchemeSpec<T>,

View File

@ -1,5 +1,9 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.names.Name
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
/**
* A value built from string which content and type are parsed on-demand
@ -44,3 +48,79 @@ public class DoubleArrayValue(override val value: DoubleArray) : Value, Iterable
}
public fun DoubleArray.asValue(): Value = if (isEmpty()) Null else DoubleArrayValue(this)
public val Value.doubleArray: DoubleArray
get() = if (this is DoubleArrayValue) {
value
} else {
DoubleArray(list.size) { list[it].double }
}
public val Meta?.doubleArray: DoubleArray? get() = this?.value?.doubleArray
public fun MetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadOnlyProperty<Any?, DoubleArray> = value(
key,
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public fun MutableMetaProvider.doubleArray(
vararg default: Double,
key: Name? = null,
): ReadWriteProperty<Any?, DoubleArray> = value(
key,
writer = { DoubleArrayValue(it) },
reader = { it?.doubleArray ?: doubleArrayOf(*default) },
)
public class ByteArrayValue(override val value: ByteArray) : Value, Iterable<Byte> {
override val type: ValueType get() = ValueType.LIST
override val list: List<Value> get() = value.map { NumberValue(it) }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Value) return false
return when (other) {
is ByteArrayValue -> value.contentEquals(other.value)
else -> list == other.list
}
}
override fun hashCode(): Int = value.contentHashCode()
override fun toString(): String = list.joinToString(prefix = "[", postfix = "]")
override fun iterator(): Iterator<Byte> = value.iterator()
}
public fun ByteArray.asValue(): Value = ByteArrayValue(this)
public val Value.byteArray: ByteArray
get() = if (this is ByteArrayValue) {
value
} else {
ByteArray(list.size) { list[it].number.toByte() }
}
public val Meta?.byteArray: ByteArray? get() = this?.value?.byteArray
public fun MetaProvider.byteArray(
vararg default: Byte,
key: Name? = null,
): ReadOnlyProperty<Any?, ByteArray> = value(
key,
reader = { it?.byteArray ?: byteArrayOf(*default) },
)
public fun MutableMetaProvider.byteArray(
vararg default: Byte,
key: Name? = null,
): ReadWriteProperty<Any?, ByteArray> = value(
key,
writer = { ByteArrayValue(it) },
reader = { it?.byteArray ?: byteArrayOf(*default) },
)

View File

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

View File

@ -31,12 +31,5 @@ public inline fun <reified E : Enum<E>> Value.enum(): E = if (this is EnumValue<
public val Value.stringList: List<String> get() = list.map { it.string }
public val Value.doubleArray: DoubleArray
get() = if (this is DoubleArrayValue) {
value
} else {
DoubleArray(list.size) { list[it].double }
}
public fun Value.toMeta(): Meta = Meta(this)

View File

@ -5,4 +5,4 @@ package space.kscience.dataforge.misc
*/
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
public annotation class DfId(val id: String)
public annotation class DfType(val id: String)

View File

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

View File

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

View File

@ -16,12 +16,10 @@ public class Name(public val tokens: List<NameToken>) {
override fun toString(): String = tokens.joinToString(separator = NAME_SEPARATOR) { it.toString() }
override fun equals(other: Any?): Boolean {
return when (other) {
is Name -> this.tokens == other.tokens
is NameToken -> this.length == 1 && this.tokens.first() == other
else -> false
}
override fun equals(other: Any?): Boolean = when (other) {
is Name -> this.tokens == other.tokens
is NameToken -> this.length == 1 && this.tokens.first() == other
else -> false
}
private val cachedHashCode = if (tokens.size == 1) {
@ -115,6 +113,13 @@ public class Name(public val tokens: List<NameToken>) {
}
}
/**
* Transform this [Name] to a string without escaping special characters in tokens.
*
* Parsing it back will produce a valid, but different name
*/
public fun Name.toStringUnescaped(): String = tokens.joinToString(separator = Name.NAME_SEPARATOR) { it.toStringUnescaped() }
public operator fun Name.get(i: Int): NameToken = tokens[i]
/**
@ -216,9 +221,13 @@ public fun Name.endsWith(token: NameToken): Boolean = lastOrNull() == token
public fun Name.startsWith(name: Name): Boolean =
this.length >= name.length && (this == name || tokens.subList(0, name.length) == name.tokens)
public fun Name.startsWith(name: String): Boolean = startsWith(name.parseAsName())
public fun Name.endsWith(name: Name): Boolean =
this.length >= name.length && (this == name || tokens.subList(length - name.length, length) == name.tokens)
public fun Name.endsWith(name: String): Boolean = endsWith(name.parseAsName())
/**
* if [this] starts with given [head] name, returns the reminder of the name (could be empty). Otherwise, returns null
*/

View File

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

View File

@ -69,7 +69,7 @@ public class NameToken(public val body: String, public val index: String? = null
public fun parse(string: String): NameToken {
val body = string.substringBefore('[')
val index = string.substringAfter('[', "")
if (index.isNotEmpty() && index.endsWith(']')) error("NameToken with index must end with ']'")
if (index.isNotEmpty() && !index.endsWith(']')) error("NameToken with index must end with ']'")
return NameToken(body, index.removeSuffix("]"))
}
}

View File

@ -2,7 +2,7 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.json.*
import space.kscience.dataforge.meta.descriptors.MetaDescriptor
import space.kscience.dataforge.meta.descriptors.item
import space.kscience.dataforge.meta.descriptors.node
import kotlin.test.Test
import kotlin.test.assertEquals
@ -32,7 +32,7 @@ class JsonMetaTest {
}
val descriptor = MetaDescriptor {
item("nodeArray") {
node("nodeArray") {
indexKey = "index"
}
}

View File

@ -20,7 +20,7 @@ class MetaDelegateTest {
var myValue by string()
var safeValue by double(2.2)
var enumValue by enum(TestEnum.YES)
var inner by spec(InnerScheme)
var inner by scheme(InnerScheme)
companion object : SchemeSpec<TestScheme>(::TestScheme)
}

View File

@ -61,4 +61,33 @@ class MetaTest {
assertEquals(null, indexed["8"])
assertEquals(12, indexed["12"].int)
}
@Test
fun reset() {
val oldMeta = MutableMeta {
"a" put {
"value" put "aValue"
}
"b" put {
"value" put "bValue"
}
"c" put {
"value" put "cValue"
}
}
val newMeta = Meta {
"a" put {
"value" put "aValue"
}
"b" put {
"value" put "bValue"
}
"d" put {
"value" put "dValue"
}
}
oldMeta.reset(newMeta)
println(oldMeta)
assertEquals(setOf("a", "b", "d"), oldMeta.items.keys.map { it.toString() }.toSet())
}
}

View File

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

View File

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

View File

@ -1,7 +1,17 @@
package space.kscience.dataforge.meta
import space.kscience.dataforge.misc.DFExperimental
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
internal class SubScheme : Scheme() {
var subValue by string()
companion object : SchemeSpec<SubScheme>(::SubScheme)
}
internal class TestScheme : Scheme() {
var list by numberList(1, 2, 3)
@ -11,9 +21,23 @@ internal class TestScheme : Scheme() {
var v by value()
var sub by scheme(SubScheme)
companion object : SchemeSpec<TestScheme>(::TestScheme)
}
private class SchemeWithInit: Scheme(){
init {
set("initial", "initialValue")
}
var initial by string()
companion object: SchemeSpec<SchemeWithInit>(::SchemeWithInit)
}
class SpecificationTest {
// @Test
@ -71,4 +95,64 @@ class SpecificationTest {
assertEquals(22, config["child.a"].int)
assertEquals("test", config["child.b"].string)
}
@Test
fun testSchemeWrappingBeforeEdit() {
val config = MutableMeta()
val scheme = TestScheme.write(config)
scheme.a = 29
assertEquals(29, config["a"].int)
}
@OptIn(DFExperimental::class)
@Test
fun testSchemeWrappingAfterEdit() {
val scheme = TestScheme.empty()
scheme.a = 29
val config = MutableMeta()
scheme.retarget(config)
assertEquals(29, scheme.a)
}
@Test
fun testSchemeSubscription() {
val scheme = TestScheme.empty()
var flag: Int? = null
scheme.useProperty(TestScheme::a) { a ->
flag = a
}
scheme.a = 2
assertEquals(2, flag)
}
@Test
fun testListSubscription(){
val scheme = TestScheme.empty()
var value: Value? = null
scheme.v = ListValue(0.0,0.0,0.0)
scheme.useProperty(TestScheme::v){
value = it
}
scheme.v = ListValue(1.0, 2.0, 3.0)
assertNotNull(value)
}
@Test
fun testSubScheme(){
val scheme = TestScheme.empty()
scheme.sub.subValue = "aaa"
assertEquals("aaa",scheme.sub.subValue)
}
@Test
fun testSchemeWithInit(){
val scheme = SchemeWithInit()
assertEquals("initialValue", scheme.initial)
scheme.initial = "none"
assertEquals("none", scheme.initial)
}
}

View File

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

Some files were not shown because too many files have changed in this diff Show More