Call remote tasks of service workspace #75

Closed
winter-yuki wants to merge 25 commits from winter-yuki/distributed into 0.6
167 changed files with 4154 additions and 3818 deletions
Showing only changes of commit a7ee2f5922 - Show all commits

19
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Gradle build
on: [ push ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build

View File

@ -1,17 +0,0 @@
name: Gradle build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Build with Gradle
run: ./gradlew build

40
.github/workflows/publish.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Bintray Publish
on:
release:
types:
- created
jobs:
build-on-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Gradle clean
run: ./gradlew clean
- name: Gradle build
run: ./gradlew build
- name: Run release task
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}
build-on-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Gradle clean
run: ./gradlew clean
- name: Gradle build
run: ./gradlew build
- name: Run release task
run: ./gradlew release -PbintrayUser=${{ secrets.BINTRAY_USER }} -PbintrayApiKey=${{ secrets.BINTRAY_KEY }}

View File

@ -12,6 +12,37 @@
### Fixed
### Security
## [0.3.0]
### Added
- Yaml meta format based on yaml.kt
- `Path` builders
- Special ValueType for lists
- `copy` method to descriptors
- Multiplatform yaml meta
### Changed
- `ListValue` and `DoubleArrayValue` implement `Iterable`.
- Changed the logic of `Value::isList` to check for type instead of size
- `Meta{}` builder made inline
- Moved `Envelope` builder to a top level function. Companion invoke is deprecated.
- Context logging moved to the extension
- `number` and `string` methods on `Value` moved to extensions (breaking change)
- \[Major breaking change\] Schemes and configurables us `MutableItemProvider` instead of `Config`
- \[Major breaking change\] `MetaItem` renamed to `TypedMetaItem` and `MetaItem` is now an alias for `TypedMetaItem<*>`
- \[Major breaking change\] Moved `NodeItem` and `ValueItem` to a top level
- Plugins are removed from Context constructor and added lazily in ContextBuilder
- \[Major breaking change\] Full refactor of DataTree/DataSource
- \[Major Breaking change\] Replace KClass with KType in data. Remove direct access to constructors with types.
### Deprecated
### Removed
### Fixed
### Security
## [0.2.0]
### Added

127
README.md
View File

@ -5,98 +5,53 @@
[ ![Download](https://api.bintray.com/packages/mipt-npm/dataforge/dataforge-meta/images/download.svg) ](https://bintray.com/mipt-npm/dataforge/dataforge-meta/_latestVersion)
<hr/>
* ### [dataforge-context](dataforge-context)
>
>
> **Maturity**: DEVELOPMENT
<hr/>
# Questions and Answers #
* ### [dataforge-data](dataforge-data)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
In this section we will try to cover DataForge main ideas in the form of questions and answers.
* ### [dataforge-io](dataforge-io)
>
>
> **Maturity**: PROTOTYPE
<hr/>
## General ##
* ### [dataforge-meta](dataforge-meta)
>
>
> **Maturity**: DEVELOPMENT
<hr/>
**Q:** I have a lot of data to analyze. The analysis process is complicated, requires a lot of stages and data flow is not always obvious. To top it the data size is huge, so I don't want to perform operation I don't need (calculate something I won't need or calculate something twice). And yes, I need it to be performed in parallel and probably on remote computer. By the way, I am sick and tired of scripts that modify other scripts that control scripts. Could you help me?
* ### [dataforge-scripting](dataforge-scripting)
>
>
> **Maturity**: PROTOTYPE
<hr/>
**A:** Yes, that is the precisely the problem DataForge was made to solve. It allows to perform some automated data manipulations with automatic optimization and parallelization. The important thing that data processing recipes are made in the declarative way, so it is quite easy to perform computations on a remote station. Also DataForge guarantees reproducibility of analysis results.
<hr>
* ### [dataforge-tables](dataforge-tables)
>
>
> **Maturity**: PROTOTYPE
<hr/>
**Q:** How does it work?
* ### [dataforge-workspace](dataforge-workspace)
>
>
> **Maturity**: EXPERIMENTAL
<hr/>
**A:** At the core of DataForge lies the idea of **metadata processor**. It utilizes the statement that in order to analyze something you need data itself and some additional information about what does that data represent and what does user want as a result. This additional information is called metadata and could be organized in a regular structure (a tree of values not unlike XML or JSON). The important thing is that this distinction leaves no place for user instructions (or scripts). Indeed, the idea of DataForge logic is that one do not need imperative commands. The framework configures itself according to input meta-data and decides what operations should be performed in the most efficient way.
<hr>
* ### [dataforge-io-yaml](dataforge-io-yaml)
> YAML meta converters and Front Matter envelope format
>
> **Maturity**: PROTOTYPE
<hr/>
**Q:** But where does it take algorithms to use?
**A:** Of course algorithms must be written somewhere. No magic here. The logic is written in specialized modules. Some modules are provided out of the box at the system core, some need to be developed for specific problem.
<hr>
**Q:** So I still need to write the code? What is the difference then?
**A:** Yes, someone still need to write the code. But not necessary you. Simple operations could be performed using provided core logic. Also your group can have one programmer writing the logic and all other using it without any real programming expertise. Also the framework organized in a such way that one writes some additional logic, he do not need to thing about complicated thing like parallel computing, resource handling, logging, caching etc. Most of the things are done by the DataForge.
<hr>
## Platform ##
**Q:** Which platform does DataForge use? Which operation system is it working on?
**A:** The DataForge is mostly written in Java and utilizes JVM as a platform. It works on any system that supports JVM (meaning almost any modern system excluding some mobile platforms).
<hr>
**Q:** But Java... it is slow!
**A:** [It is not](https://stackoverflow.com/questions/2163411/is-java-really-slow/2163570#2163570). It lacks some hardware specific optimizations and requires some additional time to start (due to JIT nature), but otherwise it is at least as fast as other languages traditionally used in science. More importantly, the memory safety, tooling support and vast ecosystem makes it №1 candidate for data analysis framework.
<hr>
**Q:** Can I use my C++/Fortran/Python code in DataForge?
**A:** Yes, as long as the code could be called from Java. Most of common languages have a bridge for Java access. There are completely no problems with compiled C/Fortran libraries. Python code could be called via one of existing python-java interfaces. It is also planned to implement remote method invocation for common languages, so your Python, or, say, Julia, code could run in its native environment. The metadata processor paradigm makes it much easier to do so.
<hr>
## Features ##
**Q:** What other features does DataForge provide?
**A:** Alongside metadata processing (and a lot of tools for metadata manipulation and layering), DataForge has two additional important concepts:
* **Modularisation**. Contrary to lot other frameworks, DataForge is intrinsically modular. The mandatory part is a rather tiny core module. Everything else could be customized.
* **Context encapsulation**. Every DataForge task is executed in some context. The context isolates environment for the task and also works as dependency injection base and specifies interaction of the task with the external world.
<!--<hr>
**Q:** OK, but now I want to work directly with my measuring devices. How can I do that?
**A:** The [dataforge-control](${site.url}/docs.html#control) module provides interfaces to interact with the hardware. Out of the box it supports safe communication with TCP/IP or COM/tty based devices. Specific device declaration could be done via additional modules. It is also possible to maintain data storage with [datforge-storage](${site.url}/docs.htm#storage) module.-->
<hr>
<!--**Q:** Declarations and metadata are good, but I want my scripts back!
**A:** We can do that. [GRIND](${site.url}/docs.html#grind) provides a shell-like environment called GrindShell. It allows to run imperative scripts with full access to all of the DataForge functionality. Grind scripts are basically context-encapsulated. Also there are convenient feature wrappers called helpers that could be loaded into the shell when new features modules are added.-->
<hr>
## Misc ##
**Q:** So everything looks great, can I replace my ROOT / other data analysis framework with DataForge?
**A:** One must note, that DataForge is made for analysis, not for visualisation. The visualisation and user interaction capabilities of DataForge are rather limited compared to frameworks like ROOT, JAS3 or DataMelt. The idea is to provide reliable API and core functionality. In fact JAS3 and DataMelt could be used as a frontend for DataForge mechanics. It is planned to add an interface to ROOT via JFreeHep AIDA.
<hr>
**Q:** How does DataForge compare to cluster computation frameworks like Hadoop or Spark?
**A:** Again, it is not the purpose of DataForge to replace cluster software. DataForge has some internal parallelism mechanics and implementations, but they are most certainly worse then specially developed programs. Still, DataForge is not fixed on one single implementation. Your favourite parallel processing tool could be still used as a back-end for the DataForge. With full benefit of configuration tools, integrations and no performance overhead.
<!--
<hr>
**Q:** Is it possible to use DataForge in notebook mode?
**A:** Yes, it is. DataForge can be used as is from [beaker/beakerx](http://beakernotebook.com/) groovy kernel with minor additional adjustments. It is planned to provide separate DataForge kernel to `beakerx` which will automatically call a specific GRIND shell.-->
<hr>
**Q:** Can I use DataForge on a mobile platform?
**A:** DataForge is modular. Core and the most of api are pretty compact, so it could be used in Android applications. Some modules are designed for PC and could not be used on other platforms. IPhone does not support Java and therefore could use only client-side DataForge applications.

View File

@ -2,23 +2,27 @@ plugins {
id("ru.mipt.npm.project")
}
val dataforgeVersion by extra("0.2.0")
val dataforgeVersion by extra("0.3.0")
val bintrayRepo by extra("dataforge")
val githubProject by extra("dataforge-core")
val spaceRepo by extra("https://maven.jetbrains.space/mipt-npm/p/df/maven")
allprojects {
group = "hep.dataforge"
version = dataforgeVersion
apply<org.jetbrains.dokka.gradle.DokkaPlugin>()
repositories {
mavenLocal()
}
}
subprojects {
apply(plugin = "ru.mipt.npm.publish")
}
readme {
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
}
ksciencePublish {
bintrayRepo = "dataforge"
githubProject = "dataforge-core"
spaceRepo = "https://maven.jetbrains.space/mipt-npm/p/df/maven"
}

View File

@ -4,16 +4,15 @@ public abstract class hep/dataforge/context/AbstractPlugin : hep/dataforge/conte
public synthetic fun <init> (Lhep/dataforge/meta/Meta;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun attach (Lhep/dataforge/context/Context;)V
public fun content (Ljava/lang/String;)Ljava/util/Map;
public synthetic fun dependsOn ()Ljava/util/Collection;
public final fun dependsOn ()Ljava/util/List;
public final fun dependsOn ()Ljava/util/Map;
public fun detach ()V
public fun getContext ()Lhep/dataforge/context/Context;
public fun getDefaultChainTarget ()Ljava/lang/String;
public fun getDefaultTarget ()Ljava/lang/String;
public fun getLogger ()Lmu/KLogger;
public fun getMeta ()Lhep/dataforge/meta/Meta;
public fun getName ()Lhep/dataforge/names/Name;
protected final fun require (Lhep/dataforge/context/PluginFactory;)Lkotlin/properties/ReadOnlyProperty;
protected final fun require (Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;)Lkotlin/properties/ReadOnlyProperty;
public static synthetic fun require$default (Lhep/dataforge/context/AbstractPlugin;Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}
@ -36,18 +35,15 @@ public final class hep/dataforge/context/ClassLoaderPluginKt {
public static final fun getClassLoaderPlugin (Lhep/dataforge/context/Context;)Lhep/dataforge/context/ClassLoaderPlugin;
}
public class hep/dataforge/context/Context : hep/dataforge/context/Named, hep/dataforge/meta/MetaRepr, hep/dataforge/provider/Provider, kotlinx/coroutines/CoroutineScope {
public class hep/dataforge/context/Context : hep/dataforge/meta/MetaRepr, hep/dataforge/misc/Named, hep/dataforge/provider/Provider, kotlinx/coroutines/CoroutineScope {
public static final field Companion Lhep/dataforge/context/Context$Companion;
public static final field PROPERTY_TARGET Ljava/lang/String;
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;)V
public synthetic fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/context/Context;Lhep/dataforge/meta/Meta;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun close ()V
public fun content (Ljava/lang/String;)Ljava/util/Map;
public final fun content (Ljava/lang/String;Z)Ljava/util/Map;
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;
public fun getDefaultChainTarget ()Ljava/lang/String;
public fun getDefaultTarget ()Ljava/lang/String;
public final fun getLogger ()Lmu/KLogger;
public final fun getName ()Lhep/dataforge/names/Name;
public final fun getParent ()Lhep/dataforge/context/Context;
public final fun getPlugins ()Lhep/dataforge/context/PluginManager;
@ -59,11 +55,6 @@ public final class hep/dataforge/context/Context$Companion {
public abstract interface class hep/dataforge/context/ContextAware {
public abstract fun getContext ()Lhep/dataforge/context/Context;
public abstract fun getLogger ()Lmu/KLogger;
}
public final class hep/dataforge/context/ContextAware$DefaultImpls {
public static fun getLogger (Lhep/dataforge/context/ContextAware;)Lmu/KLogger;
}
public final class hep/dataforge/context/ContextBuilder {
@ -72,7 +63,6 @@ public final class hep/dataforge/context/ContextBuilder {
public synthetic fun <init> (Lhep/dataforge/context/Context;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun build ()Lhep/dataforge/context/Context;
public final fun getName ()Ljava/lang/String;
public final fun plugin (Lhep/dataforge/context/Plugin;)V
public final fun plugin (Lhep/dataforge/context/PluginFactory;Lkotlin/jvm/functions/Function1;)V
public final fun plugin (Lhep/dataforge/context/PluginTag;Lkotlin/jvm/functions/Function1;)V
public final fun plugin (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V
@ -83,6 +73,11 @@ public final class hep/dataforge/context/ContextBuilder {
public final fun setName (Ljava/lang/String;)V
}
public final class hep/dataforge/context/ContextKt {
public static final fun Context (Ljava/lang/String;Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Context;
public static synthetic fun Context$default (Ljava/lang/String;Lhep/dataforge/context/Context;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/context/Context;
}
public abstract interface class hep/dataforge/context/Factory {
public abstract fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
}
@ -100,24 +95,16 @@ public final class hep/dataforge/context/Global : hep/dataforge/context/Context
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;
}
public abstract interface class hep/dataforge/context/Named {
public static final field Companion Lhep/dataforge/context/Named$Companion;
public abstract fun getName ()Lhep/dataforge/names/Name;
public final class hep/dataforge/context/LoggingKt {
public static final fun getLogger (Lhep/dataforge/context/Context;)Lmu/KLogger;
public static final fun getLogger (Lhep/dataforge/context/ContextAware;)Lmu/KLogger;
}
public final class hep/dataforge/context/Named$Companion {
public final fun nameOf (Ljava/lang/Object;)Lhep/dataforge/names/Name;
}
public final class hep/dataforge/context/NamedKt {
public static final fun isAnonymous (Lhep/dataforge/context/Named;)Z
}
public abstract interface class hep/dataforge/context/Plugin : hep/dataforge/context/ContextAware, hep/dataforge/context/Named, hep/dataforge/meta/MetaRepr, hep/dataforge/provider/Provider {
public abstract interface class hep/dataforge/context/Plugin : hep/dataforge/context/ContextAware, hep/dataforge/meta/MetaRepr, hep/dataforge/misc/Named, hep/dataforge/provider/Provider {
public static final field Companion Lhep/dataforge/context/Plugin$Companion;
public static final field TARGET Ljava/lang/String;
public abstract fun attach (Lhep/dataforge/context/Context;)V
public abstract fun dependsOn ()Ljava/util/Collection;
public abstract fun dependsOn ()Ljava/util/Map;
public abstract fun detach ()V
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
public abstract fun getName ()Lhep/dataforge/names/Name;
@ -133,7 +120,6 @@ public final class hep/dataforge/context/Plugin$DefaultImpls {
public static fun content (Lhep/dataforge/context/Plugin;Ljava/lang/String;)Ljava/util/Map;
public static fun getDefaultChainTarget (Lhep/dataforge/context/Plugin;)Ljava/lang/String;
public static fun getDefaultTarget (Lhep/dataforge/context/Plugin;)Ljava/lang/String;
public static fun getLogger (Lhep/dataforge/context/Plugin;)Lmu/KLogger;
public static fun getName (Lhep/dataforge/context/Plugin;)Lhep/dataforge/names/Name;
public static fun toMeta (Lhep/dataforge/context/Plugin;)Lhep/dataforge/meta/Meta;
}
@ -150,10 +136,10 @@ public final class hep/dataforge/context/PluginFactory$Companion {
}
public final class hep/dataforge/context/PluginManager : hep/dataforge/context/ContextAware, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> (Lhep/dataforge/context/Context;Ljava/util/Set;)V
public final fun fetch (Lhep/dataforge/context/PluginFactory;ZLhep/dataforge/meta/Meta;)Lhep/dataforge/context/Plugin;
public fun <init> (Lhep/dataforge/context/Context;)V
public final fun fetch (Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;Z)Lhep/dataforge/context/Plugin;
public final fun fetch (Lhep/dataforge/context/PluginFactory;ZLkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Plugin;
public static synthetic fun fetch$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginFactory;ZLhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/context/Plugin;
public static synthetic fun fetch$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginFactory;Lhep/dataforge/meta/Meta;ZILjava/lang/Object;)Lhep/dataforge/context/Plugin;
public static synthetic fun fetch$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginFactory;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/context/Plugin;
public final fun find (ZLkotlin/jvm/functions/Function1;)Lhep/dataforge/context/Plugin;
public static synthetic fun find$default (Lhep/dataforge/context/PluginManager;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/context/Plugin;
@ -162,7 +148,6 @@ public final class hep/dataforge/context/PluginManager : hep/dataforge/context/C
public static synthetic fun get$default (Lhep/dataforge/context/PluginManager;Lhep/dataforge/context/PluginTag;ZILjava/lang/Object;)Lhep/dataforge/context/Plugin;
public static synthetic fun get$default (Lhep/dataforge/context/PluginManager;Lkotlin/reflect/KClass;Lhep/dataforge/context/PluginTag;ZILjava/lang/Object;)Ljava/lang/Object;
public fun getContext ()Lhep/dataforge/context/Context;
public fun getLogger ()Lmu/KLogger;
public fun iterator ()Ljava/util/Iterator;
public final fun list (Z)Ljava/util/Collection;
public final fun load (Lhep/dataforge/context/Plugin;)Lhep/dataforge/context/Plugin;
@ -268,9 +253,6 @@ public final class hep/dataforge/provider/Path : java/lang/Iterable, kotlin/jvm/
public fun equals (Ljava/lang/Object;)Z
public static fun equals-impl (Ljava/util/List;Ljava/lang/Object;)Z
public static final fun equals-impl0 (Ljava/util/List;Ljava/util/List;)Z
public static final fun getHead-impl (Ljava/util/List;)Lhep/dataforge/provider/PathToken;
public static final fun getLength-impl (Ljava/util/List;)I
public static final fun getTail-e2ET3QM (Ljava/util/List;)Ljava/util/List;
public final fun getTokens ()Ljava/util/List;
public fun hashCode ()I
public static fun hashCode-impl (Ljava/util/List;)I
@ -282,12 +264,19 @@ public final class hep/dataforge/provider/Path : java/lang/Iterable, kotlin/jvm/
}
public final class hep/dataforge/provider/Path$Companion {
public final fun parse-IN54j3k (Ljava/lang/String;)Ljava/util/List;
public final fun parse-AnEnhig (Ljava/lang/String;)Ljava/util/List;
}
public final class hep/dataforge/provider/PathKt {
public static final fun plus-MQiGgVU (Ljava/util/List;Ljava/util/List;)Ljava/util/List;
public static final fun toPath (Lhep/dataforge/provider/PathToken;)Ljava/util/List;
public static final fun Path ([Lhep/dataforge/names/Name;)Ljava/util/List;
public static final fun Path ([Lkotlin/Pair;)Ljava/util/List;
public static final fun asPath (Lhep/dataforge/names/Name;Ljava/lang/String;)Ljava/util/List;
public static final fun asPath (Lhep/dataforge/provider/PathToken;)Ljava/util/List;
public static synthetic fun asPath$default (Lhep/dataforge/names/Name;Ljava/lang/String;ILjava/lang/Object;)Ljava/util/List;
public static final fun getHead-Ipm_iiw (Ljava/util/List;)Lhep/dataforge/provider/PathToken;
public static final fun getLength-Ipm_iiw (Ljava/util/List;)I
public static final fun getTail-Ipm_iiw (Ljava/util/List;)Ljava/util/List;
public static final fun plus-BlTXZnM (Ljava/util/List;Ljava/util/List;)Ljava/util/List;
}
public final class hep/dataforge/provider/PathToken {
@ -323,12 +312,8 @@ public final class hep/dataforge/provider/Provider$DefaultImpls {
}
public final class hep/dataforge/provider/ProviderKt {
public static final fun provide-0Dbucg0 (Lhep/dataforge/provider/Provider;Ljava/util/List;Ljava/lang/String;)Ljava/lang/Object;
public static synthetic fun provide-0Dbucg0$default (Lhep/dataforge/provider/Provider;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun provide-mzxrFLw (Lhep/dataforge/provider/Provider;Ljava/util/List;Ljava/lang/String;)Ljava/lang/Object;
public static synthetic fun provide-mzxrFLw$default (Lhep/dataforge/provider/Provider;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/Object;
public static final fun top (Lhep/dataforge/provider/Provider;Ljava/lang/String;Lkotlin/reflect/KClass;)Ljava/util/Map;
}
public abstract interface annotation class hep/dataforge/provider/Type : java/lang/annotation/Annotation {
public abstract fun id ()Ljava/lang/String;
}

View File

@ -28,4 +28,8 @@ kotlin {
}
}
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
}

View File

@ -1,6 +1,7 @@
package hep.dataforge.context
import hep.dataforge.meta.Meta
import hep.dataforge.misc.Named
import hep.dataforge.names.Name
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KClass
@ -8,7 +9,7 @@ import kotlin.reflect.KProperty
public abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plugin {
private var _context: Context? = null
private val dependencies = ArrayList<PluginFactory<*>>()
private val dependencies = HashMap<PluginFactory<*>, Meta>()
override val context: Context
get() = _context ?: error("Plugin $tag is not attached")
@ -21,13 +22,13 @@ public abstract class AbstractPlugin(override val meta: Meta = Meta.EMPTY) : Plu
this._context = null
}
final override fun dependsOn(): List<PluginFactory<*>> = dependencies
final override fun dependsOn(): Map<PluginFactory<*>, Meta> = dependencies
/**
* Register plugin dependency and return a delegate which provides lazily initialized reference to dependent plugin
*/
protected fun <P : Plugin> require(factory: PluginFactory<P>): ReadOnlyProperty<AbstractPlugin, P> {
dependencies.add(factory)
protected fun <P : Plugin> require(factory: PluginFactory<P>, meta: Meta = Meta.EMPTY): ReadOnlyProperty<AbstractPlugin, P> {
dependencies[factory] = meta
return PluginDependencyDelegate(factory.type)
}
}

View File

@ -3,15 +3,13 @@ package hep.dataforge.context
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.sequence
import hep.dataforge.meta.itemSequence
import hep.dataforge.misc.Named
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import hep.dataforge.provider.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import mu.KLogger
import mu.KotlinLogging
import kotlin.coroutines.CoroutineContext
/**
@ -24,11 +22,10 @@ import kotlin.coroutines.CoroutineContext
* be overridden by plugin implementation.
*
*/
public open class Context(
public open class Context internal constructor(
final override val name: Name,
public val parent: Context?,
meta: Meta,
plugins: Set<Plugin> = emptySet(),
) : Named, MetaRepr, Provider, CoroutineScope {
/**
@ -40,28 +37,23 @@ public open class Context(
Laminate(meta, parent.properties)
}
/**
* Context logger
*/
public val logger: KLogger = KotlinLogging.logger(name.toString())
/**
* A [PluginManager] for current context
*/
public val plugins: PluginManager by lazy { PluginManager(this, plugins)}
public val plugins: PluginManager by lazy { PluginManager(this) }
override val defaultTarget: String get() = Plugin.TARGET
public fun content(target: String, inherit: Boolean): Map<Name, Any> {
return if (inherit) {
when (target) {
PROPERTY_TARGET -> properties.sequence().toMap()
PROPERTY_TARGET -> properties.itemSequence().toMap()
Plugin.TARGET -> plugins.list(true).associateBy { it.name }
else -> emptyMap()
}
} else {
when (target) {
PROPERTY_TARGET -> properties.layers.firstOrNull()?.sequence()?.toMap() ?: emptyMap()
PROPERTY_TARGET -> properties.layers.firstOrNull()?.itemSequence()?.toMap() ?: emptyMap()
Plugin.TARGET -> plugins.list(false).associateBy { it.name }
else -> emptyMap()
}
@ -95,6 +87,9 @@ public open class Context(
}
}
public fun Context(name: String, parent: Context = Global, block: ContextBuilder.() -> Unit = {}): Context =
Global.context(name, parent, block)
/**
* The interface for something that encapsulated in context
*
@ -106,12 +101,4 @@ public interface ContextAware {
* @return
*/
public val context: Context
public val logger: KLogger
get() = if (this is Named) {
KotlinLogging.logger((context.name + this.name).toString())
} else {
context.logger
}
}

View File

@ -1,24 +1,29 @@
package hep.dataforge.context
import hep.dataforge.meta.*
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.seal
import hep.dataforge.misc.DFBuilder
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.toName
import kotlin.collections.HashMap
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.forEach
import kotlin.collections.set
/**
* A convenience builder for context
*/
@DFBuilder
public class ContextBuilder(private val parent: Context = Global, public var name: String = "@anonymous") {
private val plugins = HashSet<Plugin>()
private val factories = HashMap<PluginFactory<*>, Meta>()
private var meta = MetaBuilder()
public fun properties(action: MetaBuilder.() -> Unit) {
meta.action()
}
public fun plugin(plugin: Plugin) {
plugins.add(plugin)
}
@OptIn(DFExperimental::class)
private fun findPluginFactory(tag: PluginTag): PluginFactory<*> =
parent.gatherInSequence<PluginFactory<*>>(PluginFactory.TYPE).values
@ -26,12 +31,11 @@ public class ContextBuilder(private val parent: Context = Global, public var nam
public fun plugin(tag: PluginTag, metaBuilder: MetaBuilder.() -> Unit = {}) {
val factory = findPluginFactory(tag)
val plugin = factory.invoke(Meta(metaBuilder), parent)
plugins.add(plugin)
factories[factory] = Meta(metaBuilder)
}
public fun plugin(builder: PluginFactory<*>, action: MetaBuilder.() -> Unit = {}) {
plugins.add(builder.invoke(Meta(action)))
public fun plugin(factory: PluginFactory<*>, metaBuilder: MetaBuilder.() -> Unit = {}) {
factories[factory] = Meta(metaBuilder)
}
public fun plugin(name: String, group: String = "", version: String = "", action: MetaBuilder.() -> Unit = {}) {
@ -39,6 +43,10 @@ public class ContextBuilder(private val parent: Context = Global, public var nam
}
public fun build(): Context {
return Context(name.toName(), parent, meta.seal(), plugins)
return Context(name.toName(), parent, meta.seal()).apply {
factories.forEach { (factory, meta) ->
plugins.load(factory, meta)
}
}
}
}

View File

@ -3,10 +3,11 @@ package hep.dataforge.context
import hep.dataforge.context.Plugin.Companion.TARGET
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaRepr
import hep.dataforge.misc.Named
import hep.dataforge.misc.Type
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import hep.dataforge.provider.Provider
import hep.dataforge.provider.Type
/**
* The interface to define a Context plugin. A plugin stores all runtime features of a context.
@ -37,7 +38,7 @@ public interface Plugin : Named, ContextAware, Provider, MetaRepr {
* dependencies must be initialized and enabled in the Context before this
* plugin is enabled.
*/
public fun dependsOn(): Collection<PluginFactory<*>>
public fun dependsOn(): Map<PluginFactory<*>, Meta>
/**
* Start this plugin and attach registration info to the context. This method

View File

@ -0,0 +1,14 @@
package hep.dataforge.context
import hep.dataforge.misc.Type
import kotlin.reflect.KClass
@Type(PluginFactory.TYPE)
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
public val type: KClass<out T>
public companion object {
public const val TYPE: String = "pluginFactory"
}
}

View File

@ -2,34 +2,23 @@ package hep.dataforge.context
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.provider.Type
import kotlin.reflect.KClass
@Type(PluginFactory.TYPE)
public interface PluginFactory<T : Plugin> : Factory<T> {
public val tag: PluginTag
public val type: KClass<out T>
public companion object {
public const val TYPE: String = "pluginFactory"
}
}
/**
* The manager for plugin system. Should monitor plugin dependencies and locks.
*
* @property context A context for this plugin manager
* @author Alexander Nozik
*/
public class PluginManager(override val context: Context, plugins: Set<Plugin>) : ContextAware, Iterable<Plugin> {
public class PluginManager(override val context: Context) : ContextAware, Iterable<Plugin> {
//TODO refactor to read-only container
/**
* A set of loaded plugins
*/
private val plugins: HashSet<Plugin> = HashSet(plugins)
private val plugins: HashSet<Plugin> = HashSet()
init {
plugins.forEach { it.attach(context) }
@ -100,8 +89,8 @@ public class PluginManager(override val context: Context, plugins: Set<Plugin>)
if (get(plugin::class, plugin.tag, recursive = false) != null) {
error("Plugin with tag ${plugin.tag} already exists in ${context.name}")
} else {
for (tag in plugin.dependsOn()) {
fetch(tag, true)
for ((factory, meta) in plugin.dependsOn()) {
fetch(factory, meta, true)
}
logger.info { "Loading plugin ${plugin.name} into ${context.name}" }
@ -134,7 +123,7 @@ public class PluginManager(override val context: Context, plugins: Set<Plugin>)
/**
* Get an existing plugin with given meta or load new one using provided factory
*/
public fun <T : Plugin> fetch(factory: PluginFactory<T>, recursive: Boolean = true, meta: Meta = Meta.EMPTY): T {
public fun <T : Plugin> fetch(factory: PluginFactory<T>, meta: Meta = Meta.EMPTY, recursive: Boolean = true): T {
val loaded = get(factory.type, factory.tag, recursive)
return when {
loaded == null -> load(factory(meta, context))
@ -147,7 +136,7 @@ public class PluginManager(override val context: Context, plugins: Set<Plugin>)
factory: PluginFactory<T>,
recursive: Boolean = true,
metaBuilder: MetaBuilder.() -> Unit,
): T = fetch(factory, recursive, Meta(metaBuilder))
): T = fetch(factory, Meta(metaBuilder), recursive)
override fun iterator(): Iterator<Plugin> = plugins.iterator()

View File

@ -0,0 +1,22 @@
package hep.dataforge.context
import hep.dataforge.misc.Named
import hep.dataforge.provider.Path
import mu.KLogger
import mu.KotlinLogging
/**
* The logger specific to this context
*/
public val Context.logger: KLogger get() = KotlinLogging.logger(name.toString())
/**
* The logger
*/
public val ContextAware.logger: KLogger
get() = if (this is Named) {
KotlinLogging.logger(Path(context.name, this.name).toString())
} else {
context.logger
}

View File

@ -1,6 +1,6 @@
package hep.dataforge.context
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import hep.dataforge.provider.Provider
@ -48,8 +48,9 @@ public fun <T : Any> Context.gather(
putAll(top(target, type))
plugins.forEach { plugin ->
plugin.top(target, type).forEach { (name, value) ->
if (containsKey(name)) error("Name conflict during gather. An item with name $name could not be gathered from $plugin because key is already present.")
put(plugin.name + name, value)
val itemName = plugin.name + name
if (containsKey(itemName)) error("Name conflict during gather. An item with name $name could not be gathered from $plugin because key is already present.")
put(itemName, value)
}
}
if (inherit) {

View File

@ -1,11 +1,12 @@
package hep.dataforge.properties
import hep.dataforge.meta.Config
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.get
import hep.dataforge.meta.set
import hep.dataforge.meta.transformations.MetaConverter
import hep.dataforge.meta.transformations.nullableItemToObject
import hep.dataforge.meta.transformations.nullableObjectToMetaItem
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name
@DFExperimental
@ -18,7 +19,7 @@ public class ConfigProperty<T : Any>(
override var value: T?
get() = converter.nullableItemToObject(config[name])
set(value) {
config.setItem(name,converter.nullableObjectToMetaItem(value))
config[name] = converter.nullableObjectToMetaItem(value)
}
override fun onChange(owner: Any?, callback: (T?) -> Unit) {

View File

@ -1,6 +1,6 @@
package hep.dataforge.properties
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow

View File

@ -19,39 +19,39 @@ import hep.dataforge.names.Name
import hep.dataforge.names.toName
/**
*
*
* Path interface.
*
* @author Alexander Nozik
* @version $Id: $Id
*/
public inline class Path(public val tokens: List<PathToken>) : Iterable<PathToken> {
public val head: PathToken? get() = tokens.firstOrNull()
public val length: Int get() = tokens.size
/**
* Returns non-empty optional containing the chain without first segment in case of chain path.
*
* @return
*/
public val tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1))
override fun iterator(): Iterator<PathToken> = tokens.iterator()
override fun toString(): String = tokens.joinToString(separator = PATH_SEGMENT_SEPARATOR)
public companion object {
public const val PATH_SEGMENT_SEPARATOR: String = "/"
public fun parse(path: String): Path {
val head = path.substringBefore(PATH_SEGMENT_SEPARATOR)
val tail = path.substringAfter(PATH_SEGMENT_SEPARATOR)
return PathToken.parse(head).toPath() + parse(tail)
return PathToken.parse(head).asPath() + parse(tail)
}
}
}
public val Path.length: Int get() = tokens.size
public val Path.head: PathToken? get() = tokens.firstOrNull()
/**
* Returns non-empty optional containing the chain without first segment in case of chain path.
*
* @return
*/
public val Path.tail: Path? get() = if (tokens.isEmpty()) null else Path(tokens.drop(1))
public operator fun Path.plus(path: Path): Path = Path(this.tokens + path.tokens)
public data class PathToken(val name: Name, val target: String? = null) {
@ -72,4 +72,22 @@ public data class PathToken(val name: Name, val target: String? = null) {
}
}
public fun PathToken.toPath(): Path = Path(listOf(this))
/**
* Represent this path token as full path
*/
public fun PathToken.asPath(): Path = Path(listOf(this))
/**
* Represent a name with optional [target] as a [Path]
*/
public fun Name.asPath(target: String? = null): Path = PathToken(this, target).asPath()
/**
* Build a path from given names using default targets
*/
public fun Path(vararg names: Name): Path = Path(names.map { PathToken(it) })
/**
* Use an array of [Name]-target pairs to construct segmented [Path]
*/
public fun Path(vararg tokens: Pair<Name, String?>): Path = Path(tokens.map { PathToken(it.first, it.second) })

View File

@ -84,6 +84,6 @@ public fun <T : Any> Provider.top(target: String, type: KClass<out T>): Map<Name
/**
* Typed top level content
*/
public inline fun <reified T : Any> Provider.top(target: String): Map<Name, T> = top(target, T::class)
public inline fun <reified T : Any> Provider.top(target: String ): Map<Name, T> = top(target, T::class)

View File

@ -17,13 +17,13 @@ class ContextTest {
else -> emptyMap()
}
}
}
@Test
fun testPluginManager() {
val context = Global.context("test"){
plugin(DummyPlugin())
}
val context = Global.context("test")
context.plugins.load(DummyPlugin())
//Global.plugins.load(DummyPlugin())
val members = context.gather<Name>("test")
assertEquals(3, members.count())

View File

@ -1,10 +1,10 @@
package hep.dataforge.properties
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import org.w3c.dom.HTMLInputElement
@DFExperimental
fun HTMLInputElement.bindValue(property: Property<String>) {
public fun HTMLInputElement.bindValue(property: Property<String>) {
if (this.onchange != null) error("Input element already bound")
this.onchange = {
property.value = this.value
@ -18,7 +18,7 @@ fun HTMLInputElement.bindValue(property: Property<String>) {
}
@DFExperimental
fun HTMLInputElement.bindChecked(property: Property<Boolean>) {
public fun HTMLInputElement.bindChecked(property: Property<Boolean>) {
if (this.onchange != null) error("Input element already bound")
this.onchange = {
property.value = this.checked

View File

@ -16,7 +16,6 @@
package hep.dataforge.descriptors
import hep.dataforge.meta.DFExperimental
import hep.dataforge.values.ValueType
import kotlin.reflect.KClass

View File

@ -2,7 +2,8 @@ package hep.dataforge.provider
import hep.dataforge.context.Context
import hep.dataforge.context.gather
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import hep.dataforge.misc.Type
import hep.dataforge.names.Name
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation

View File

@ -26,6 +26,24 @@ public final class hep/dataforge/data/ActionKt {
public static final fun then (Lhep/dataforge/data/Action;Lhep/dataforge/data/Action;)Lhep/dataforge/data/Action;
}
public final class hep/dataforge/data/ComputationData : hep/dataforge/data/ComputationGoal, hep/dataforge/data/Data {
public fun <init> (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getMeta ()Lhep/dataforge/meta/Meta;
public fun getType ()Lkotlin/reflect/KClass;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}
public class hep/dataforge/data/ComputationGoal : hep/dataforge/data/Goal {
public fun <init> (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getBlock ()Lkotlin/jvm/functions/Function2;
public fun getDependencies ()Ljava/util/Collection;
public final fun getResult ()Lkotlinx/coroutines/Deferred;
public fun reset ()V
public fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred;
}
public final class hep/dataforge/data/CoroutineMonitor : kotlin/coroutines/CoroutineContext$Element {
public static final field Companion Lhep/dataforge/data/CoroutineMonitor$Companion;
public fun <init> ()V
@ -79,14 +97,6 @@ public final class hep/dataforge/data/Data$DefaultImpls {
public static fun toMeta (Lhep/dataforge/data/Data;)Lhep/dataforge/meta/Meta;
}
public final class hep/dataforge/data/DataCastKt {
public static final fun canCast (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Z
public static final fun cast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data;
public static final fun cast (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode;
public static final fun ensureType (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)V
public static final fun upcast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data;
}
public final class hep/dataforge/data/DataFilter : hep/dataforge/meta/Scheme {
public static final field Companion Lhep/dataforge/data/DataFilter$Companion;
public fun <init> ()V
@ -129,17 +139,22 @@ public final class hep/dataforge/data/DataItem$Node : hep/dataforge/data/DataIte
}
public final class hep/dataforge/data/DataJVMKt {
public static final fun canCast (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Z
public static final fun cast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data;
public static final fun cast (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode;
public static final fun ensureType (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)V
public static final fun filterIsInstance (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data;
public static final fun filterIsInstance (Lhep/dataforge/data/DataItem;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataItem;
public static final fun filterIsInstance (Lhep/dataforge/data/DataNode;Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataNode;
public static final fun get (Lhep/dataforge/data/Data;)Ljava/lang/Object;
public static final fun upcast (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;)Lhep/dataforge/data/Data;
}
public final class hep/dataforge/data/DataKt {
public static final fun map (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/Data;
public static synthetic fun map$default (Lhep/dataforge/data/Data;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/Data;
public static final fun reduce (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/DynamicData;
public static synthetic fun reduce$default (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/DynamicData;
public static final fun reduce (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/data/ComputationData;
public static synthetic fun reduce$default (Ljava/util/Map;Lkotlin/reflect/KClass;Lkotlin/coroutines/CoroutineContext;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/data/ComputationData;
}
public abstract interface class hep/dataforge/data/DataNode : hep/dataforge/meta/MetaRepr {
@ -148,50 +163,36 @@ public abstract interface class hep/dataforge/data/DataNode : hep/dataforge/meta
public abstract fun getItems ()Ljava/util/Map;
public abstract fun getMeta ()Lhep/dataforge/meta/Meta;
public abstract fun getType ()Lkotlin/reflect/KClass;
public abstract fun startAll (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
public abstract fun toMeta ()Lhep/dataforge/meta/Meta;
}
public final class hep/dataforge/data/DataNode$Companion {
public static final field TYPE Ljava/lang/String;
public final fun builder (Lkotlin/reflect/KClass;)Lhep/dataforge/data/DataTreeBuilder;
public final fun invoke (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/data/DataTree;
}
public final class hep/dataforge/data/DataNode$DefaultImpls {
public static fun startAll (Lhep/dataforge/data/DataNode;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
public static fun toMeta (Lhep/dataforge/data/DataNode;)Lhep/dataforge/meta/Meta;
}
public final class hep/dataforge/data/DataNodeKt {
public static final fun asSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence;
public static final fun builder (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/DataTreeBuilder;
public static final fun dataSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence;
public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/Data;)V
public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/Data;)V
public static final fun filter (Lhep/dataforge/data/DataNode;Lkotlin/jvm/functions/Function2;)Lhep/dataforge/data/DataNode;
public static final fun first (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/Data;
public static final fun get (Lhep/dataforge/data/DataNode;Lhep/dataforge/names/Name;)Lhep/dataforge/data/DataItem;
public static final fun get (Lhep/dataforge/data/DataNode;Ljava/lang/String;)Lhep/dataforge/data/DataItem;
public static final fun getData (Lhep/dataforge/data/DataItem;)Lhep/dataforge/data/Data;
public static final fun getNode (Lhep/dataforge/data/DataItem;)Lhep/dataforge/data/DataNode;
public static final fun itemSequence (Lhep/dataforge/data/DataNode;)Lkotlin/sequences/Sequence;
public static final fun iterator (Lhep/dataforge/data/DataNode;)Ljava/util/Iterator;
public static final fun join (Lhep/dataforge/data/DataNode;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/DataNode;)V
public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/DataNode;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun startAll (Lhep/dataforge/data/DataNode;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
}
public final class hep/dataforge/data/DataTree : hep/dataforge/data/DataNode {
public fun getItems ()Ljava/util/Map;
public fun getMeta ()Lhep/dataforge/meta/Meta;
public fun getType ()Lkotlin/reflect/KClass;
public fun startAll (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}
@ -214,6 +215,21 @@ public final class hep/dataforge/data/DataTreeBuilder {
public final fun update (Lhep/dataforge/data/DataNode;)V
}
public final class hep/dataforge/data/DataTreeBuilderKt {
public static final fun DataTree (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/data/DataTree;
public static final fun builder (Lhep/dataforge/data/DataNode;)Lhep/dataforge/data/DataTreeBuilder;
public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/Data;)V
public static final fun datum (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/Data;)V
public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Lhep/dataforge/data/DataNode;)V
public static final fun node (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Lhep/dataforge/data/DataNode;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static final fun static (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Lhep/dataforge/names/Name;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static synthetic fun static$default (Lhep/dataforge/data/DataTreeBuilder;Ljava/lang/String;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}
public final class hep/dataforge/data/Dependencies : kotlin/coroutines/CoroutineContext$Element {
public static final field Companion Lhep/dataforge/data/Dependencies$Companion;
public fun <init> (Ljava/util/Collection;)V
@ -228,24 +244,6 @@ public final class hep/dataforge/data/Dependencies : kotlin/coroutines/Coroutine
public final class hep/dataforge/data/Dependencies$Companion : kotlin/coroutines/CoroutineContext$Key {
}
public final class hep/dataforge/data/DynamicData : hep/dataforge/data/DynamicGoal, hep/dataforge/data/Data {
public fun <init> (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lkotlin/reflect/KClass;Lhep/dataforge/meta/Meta;Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getMeta ()Lhep/dataforge/meta/Meta;
public fun getType ()Lkotlin/reflect/KClass;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}
public class hep/dataforge/data/DynamicGoal : hep/dataforge/data/Goal {
public fun <init> (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;)V
public synthetic fun <init> (Lkotlin/coroutines/CoroutineContext;Ljava/util/Collection;Lkotlin/jvm/functions/Function2;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getBlock ()Lkotlin/jvm/functions/Function2;
public fun getDependencies ()Ljava/util/Collection;
public final fun getResult ()Lkotlinx/coroutines/Deferred;
public fun reset ()V
public fun startAsync (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Deferred;
}
public final class hep/dataforge/data/FragmentRule {
public field result Lkotlin/jvm/functions/Function2;
public fun <init> (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaBuilder;)V
@ -302,9 +300,7 @@ public final class hep/dataforge/data/JoinGroup {
}
public final class hep/dataforge/data/MapAction : hep/dataforge/data/Action {
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public final fun getInputType ()Lkotlin/reflect/KClass;
public final fun getOutputType ()Lkotlin/reflect/KClass;
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public fun invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
public fun isTerminal ()Z
}
@ -335,9 +331,7 @@ public final class hep/dataforge/data/NamedData : hep/dataforge/data/Data {
}
public final class hep/dataforge/data/ReduceAction : hep/dataforge/data/Action {
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public final fun getInputType ()Lkotlin/reflect/KClass;
public final fun getOutputType ()Lkotlin/reflect/KClass;
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public fun invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
public fun isTerminal ()Z
}
@ -357,9 +351,7 @@ public final class hep/dataforge/data/ReduceGroupBuilder {
}
public final class hep/dataforge/data/SplitAction : hep/dataforge/data/Action {
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public final fun getInputType ()Lkotlin/reflect/KClass;
public final fun getOutputType ()Lkotlin/reflect/KClass;
public fun <init> (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)V
public fun invoke (Lhep/dataforge/data/DataNode;Lhep/dataforge/meta/Meta;)Lhep/dataforge/data/DataNode;
public fun isTerminal ()Z
}
@ -394,7 +386,6 @@ public final class hep/dataforge/data/TypeFilteredDataNode : hep/dataforge/data/
public fun getMeta ()Lhep/dataforge/meta/Meta;
public final fun getOrigin ()Lhep/dataforge/data/DataNode;
public fun getType ()Lkotlin/reflect/KClass;
public fun startAll (Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}

View File

@ -12,12 +12,12 @@ kotlin {
commonMain{
dependencies {
api(project(":dataforge-meta"))
}
}
jvmMain{
dependencies{
api(kotlin("reflect"))
}
}
}
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.EXPERIMENTAL
}

View File

@ -0,0 +1,41 @@
package hep.dataforge.actions
import hep.dataforge.data.DataSet
import hep.dataforge.meta.Meta
import hep.dataforge.misc.DFExperimental
import kotlinx.coroutines.CoroutineScope
/**
* 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> {
/**
* 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.
*
* [scope] context used to compute the initial result, also it is used for updates propagation
*/
public suspend fun execute(dataSet: DataSet<T>, meta: Meta = Meta.EMPTY, scope: CoroutineScope? = null): DataSet<R>
public companion object
}
/**
* 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 suspend fun execute(dataSet: DataSet<T>, meta: Meta, scope: CoroutineScope?): DataSet<R> {
return action.execute(this@then.execute(dataSet, meta, scope), meta, scope)
}
}
}
@DFExperimental
public suspend fun <T : Any, R : Any> DataSet<T>.transformWith(
action: Action<T, R>,
meta: Meta = Meta.EMPTY,
scope: CoroutineScope? = null,
): DataSet<R> = action.execute(this, meta, scope)

View File

@ -0,0 +1,104 @@
package hep.dataforge.actions
import hep.dataforge.data.*
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.seal
import hep.dataforge.meta.toMutableMeta
import hep.dataforge.misc.DFBuilder
import hep.dataforge.misc.DFExperimental
import hep.dataforge.misc.DFInternal
import hep.dataforge.names.Name
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* Action environment includes data name, data meta and action configuration meta
*/
public data class ActionEnv(
val name: Name,
val meta: Meta,
val actionMeta: Meta,
)
/**
* Action environment
*/
@DFBuilder
public class MapActionBuilder<T, R>(public var name: Name, public var meta: MetaBuilder, public val actionMeta: Meta) {
public lateinit var result: suspend ActionEnv.(T) -> R
/**
* Calculate the result of goal
*/
public fun result(f: suspend ActionEnv.(T) -> R) {
result = f;
}
}
@PublishedApi
internal class MapAction<in T : Any, out R : Any>(
private val outputType: KType,
private val block: MapActionBuilder<T, R>.() -> Unit,
) : Action<T, R> {
override suspend fun execute(
dataSet: DataSet<T>,
meta: Meta,
scope: CoroutineScope?,
): DataSet<R> {
suspend fun mapOne(data: NamedData<T>): NamedData<R> {
// Creating a new environment for action using **old** name, old meta and task meta
val env = ActionEnv(data.name, data.meta, meta)
//applying transformation from builder
val builder = MapActionBuilder<T, R>(
data.name,
data.meta.toMutableMeta(), // using data meta
meta
).apply(block)
//getting new name
val newName = builder.name
//getting new meta
val newMeta = builder.meta.seal()
@OptIn(DFInternal::class) val newData = Data(outputType, newMeta, dependencies = listOf(data)) {
builder.result(env, data.await())
}
//setting the data node
return newData.named(newName)
}
val flow = dataSet.flow().map(::mapOne)
return ActiveDataTree(outputType) {
populate(flow)
scope?.launch {
dataSet.updates.collect { name ->
//clear old nodes
remove(name)
//collect new items
populate(dataSet.flowChildren(name).map(::mapOne))
}
}
}
}
}
/**
* A one-to-one mapping action
*/
@DFExperimental
@Suppress("FunctionName")
public inline fun <T : Any, reified R : Any> Action.Companion.map(
noinline builder: MapActionBuilder<T, R>.() -> Unit,
): Action<T, R> = MapAction(typeOf<R>(), builder)

View File

@ -0,0 +1,116 @@
package hep.dataforge.actions
import hep.dataforge.data.*
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.misc.DFBuilder
import hep.dataforge.misc.DFExperimental
import hep.dataforge.misc.DFInternal
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.fold
import kotlin.reflect.KType
import kotlin.reflect.typeOf
public class JoinGroup<T : Any, R : Any>(public var name: String, internal val set: DataSet<T>) {
public var meta: MetaBuilder = MetaBuilder()
public lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R
public fun result(f: suspend ActionEnv.(Map<Name, T>) -> R) {
this.result = f;
}
}
@DFBuilder
public class ReduceGroupBuilder<T : Any, R : Any>(
private val inputType: KType,
private val scope: CoroutineScope,
public val actionMeta: Meta,
) {
private val groupRules: MutableList<suspend (DataSet<T>) -> List<JoinGroup<T, R>>> = ArrayList();
/**
* introduce grouping by meta value
*/
public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) {
groupRules += { node ->
GroupRule.byMetaValue(scope, tag, defaultTag).gather(node).map {
JoinGroup<T, R>(it.key, it.value).apply(action)
}
}
}
public fun group(
groupName: String,
filter: suspend (Name, Data<T>) -> Boolean,
action: JoinGroup<T, R>.() -> Unit,
) {
groupRules += { source ->
listOf(
JoinGroup<T, R>(groupName, source.filter(filter)).apply(action)
)
}
}
/**
* Apply transformation to the whole node
*/
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) {
groupRules += { node ->
listOf(JoinGroup<T, R>(resultName, node).apply { result(f) })
}
}
internal suspend fun buildGroups(input: DataSet<T>): List<JoinGroup<T, R>> {
return groupRules.flatMap { it.invoke(input) }
}
}
@PublishedApi
internal class ReduceAction<T : Any, R : Any>(
private val inputType: KType,
outputType: KType,
private val action: ReduceGroupBuilder<T, R>.() -> Unit,
) : CachingAction<T, R>(outputType) {
//TODO optimize reduction. Currently the whole action recalculates on push
override fun CoroutineScope.transform(set: DataSet<T>, meta: Meta, key: Name): Flow<NamedData<R>> = flow {
ReduceGroupBuilder<T, R>(inputType, this@transform, meta).apply(action).buildGroups(set).forEach { group ->
val dataFlow: Map<Name, Data<T>> = group.set.flow().fold(HashMap()) { acc, value ->
acc.apply {
acc[value.name] = value.data
}
}
val groupName: String = group.name
val groupMeta = group.meta
val env = ActionEnv(groupName.toName(), groupMeta, meta)
@OptIn(DFInternal::class) val res: Data<R> = dataFlow.reduceToData(
outputType,
meta = groupMeta
) { group.result.invoke(env, it) }
emit(res.named(env.name))
}
}
}
/**
* A one-to-one mapping action
*/
@DFExperimental
@Suppress("FunctionName")
public inline fun <reified T : Any, reified R : Any> Action.Companion.reduce(
noinline builder: ReduceGroupBuilder<T, R>.() -> Unit,
): Action<T, R> = ReduceAction(typeOf<T>(), typeOf<R>(), builder)

View File

@ -0,0 +1,96 @@
package hep.dataforge.actions
import hep.dataforge.data.*
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.toMutableMeta
import hep.dataforge.misc.DFExperimental
import hep.dataforge.misc.DFInternal
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlin.collections.set
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 FragmentRule<T : Any, R : Any>(public val name: Name, public var meta: MetaBuilder) {
public lateinit var result: suspend (T) -> R
public fun result(f: suspend (T) -> R) {
result = f;
}
}
internal val fragments: MutableMap<Name, FragmentRule<T, R>.() -> Unit> = HashMap()
/**
* Add new fragment building rule. If the framgent not defined, result won't be available even if it is present in the map
* @param name the name of a fragment
* @param rule the rule to transform fragment name and meta using
*/
public fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) {
fragments[name.toName()] = rule
}
}
/**
* Action that splits each incoming element into a number of fragments defined in builder
*/
@PublishedApi
internal class SplitAction<T : Any, R : Any>(
private val outputType: KType,
private val action: SplitBuilder<T, R>.() -> Unit,
) : Action<T, R> {
@OptIn(FlowPreview::class)
override suspend fun execute(
dataSet: DataSet<T>,
meta: Meta,
scope: CoroutineScope?,
): DataSet<R> {
suspend fun splitOne(data: NamedData<T>): Flow<NamedData<R>> {
val laminate = Laminate(data.meta, meta)
val split = SplitBuilder<T, R>(data.name, data.meta).apply(action)
// apply individual fragment rules to result
return split.fragments.entries.asFlow().map { (fragmentName, rule) ->
val env = SplitBuilder.FragmentRule<T, R>(fragmentName, laminate.toMutableMeta()).apply(rule)
//data.map<R>(outputType, meta = env.meta) { env.result(it) }.named(fragmentName)
@OptIn(DFInternal::class) Data(outputType, meta = env.meta, dependencies = listOf(data)) {
env.result(data.await())
}.named(fragmentName)
}
}
return ActiveDataTree<R>(outputType) {
populate(dataSet.flow().flatMapConcat(transform = ::splitOne))
scope?.launch {
dataSet.updates.collect { name ->
//clear old nodes
remove(name)
//collect new items
populate(dataSet.flowChildren(name).flatMapConcat(transform = ::splitOne))
}
}
}
}
}
/**
* Action that splits each incoming element into a number of fragments defined in builder
*/
@DFExperimental
@Suppress("FunctionName")
public inline fun <T : Any, reified R : Any> Action.Companion.split(
noinline builder: SplitBuilder<T, R>.() -> Unit,
): Action<T, R> = SplitAction(typeOf<R>(), builder)

View File

@ -1,35 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
/**
* A simple data transformation on a data node
*/
public interface Action<in T : Any, out R : Any> {
/**
* 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 operator fun invoke(node: DataNode<T>, meta: Meta): DataNode<R>
/**
* Terminal action is the one that could not be invoked lazily and requires some kind of blocking computation to invoke
*/
public val isTerminal: Boolean get() = false
}
/**
* 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 invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
return action(this@then.invoke(node, meta), meta)
}
override val isTerminal: Boolean
get() = this@then.isTerminal || action.isTerminal
}
}

View File

@ -0,0 +1,118 @@
package hep.dataforge.data
import hep.dataforge.meta.*
import hep.dataforge.names.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A mutable [DataTree.Companion.active]. It
*/
public class ActiveDataTree<T : Any>(
override val dataType: KType,
) : DataTree<T>, DataSetBuilder<T>, ActiveDataSet<T> {
private val mutex = Mutex()
private val treeItems = HashMap<NameToken, DataTreeItem<T>>()
override suspend fun items(): Map<NameToken, DataTreeItem<T>> = mutex.withLock {
treeItems.filter { !it.key.body.startsWith("@") }
}
private val _updates = MutableSharedFlow<Name>()
override val updates: Flow<Name>
get() = _updates
private suspend fun remove(token: NameToken) {
mutex.withLock {
if (treeItems.remove(token) != null) {
_updates.emit(token.asName())
}
}
}
override suspend fun remove(name: Name) {
if (name.isEmpty()) error("Can't remove the root node")
(getItem(name.cutLast()).tree as? ActiveDataTree)?.remove(name.lastOrNull()!!)
}
private suspend fun set(token: NameToken, data: Data<T>) {
mutex.withLock {
treeItems[token] = DataTreeItem.Leaf(data)
}
}
private suspend fun getOrCreateNode(token: NameToken): ActiveDataTree<T> =
(treeItems[token] as? DataTreeItem.Node<T>)?.tree as? ActiveDataTree<T>
?: ActiveDataTree<T>(dataType).also {
mutex.withLock {
treeItems[token] = DataTreeItem.Node(it)
}
}
private suspend fun getOrCreateNode(name: Name): ActiveDataTree<T> {
return when (name.length) {
0 -> this
1 -> getOrCreateNode(name.firstOrNull()!!)
else -> getOrCreateNode(name.firstOrNull()!!).getOrCreateNode(name.cutFirst())
}
}
override suspend fun emit(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)
}
}
_updates.emit(name)
}
/**
* Copy given data set and mirror its changes to this [ActiveDataTree] in [this@setAndObserve]. Returns an update [Job]
*/
public fun CoroutineScope.setAndObserve(name: Name, dataSet: DataSet<T>): Job = launch {
emit(name, dataSet)
dataSet.updates.collect { nameInBranch ->
emit(name + nameInBranch, dataSet.getData(nameInBranch))
}
}
}
/**
* Create a dynamic tree. Initial data is placed synchronously. Updates are propagated via [updatesScope]
*/
@Suppress("FunctionName")
public suspend fun <T : Any> ActiveDataTree(
type: KType,
block: suspend ActiveDataTree<T>.() -> Unit,
): ActiveDataTree<T> {
val tree = ActiveDataTree<T>(type)
tree.block()
return tree
}
@Suppress("FunctionName")
public suspend inline fun <reified T : Any> ActiveDataTree(
crossinline block: suspend ActiveDataTree<T>.() -> Unit,
): ActiveDataTree<T> = ActiveDataTree<T>(typeOf<T>()).apply { block() }
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
name: Name,
noinline block: suspend ActiveDataTree<T>.() -> Unit,
): Unit = emit(name, ActiveDataTree(typeOf<T>(), block))
public suspend inline fun <reified T : Any> ActiveDataTree<T>.emit(
name: String,
noinline block: suspend ActiveDataTree<T>.() -> Unit,
): Unit = emit(name.toName(), ActiveDataTree(typeOf<T>(), block))

View File

@ -0,0 +1,52 @@
package hep.dataforge.data
import hep.dataforge.actions.Action
import hep.dataforge.meta.Meta
import hep.dataforge.names.Name
import hep.dataforge.names.startsWith
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlin.reflect.KType
/**
* Remove all values with keys starting with [name]
*/
internal fun MutableMap<Name, *>.removeWhatStartsWith(name: Name) {
val toRemove = keys.filter { it.startsWith(name) }
toRemove.forEach(::remove)
}
/**
* An action that caches results on-demand and recalculates them on source push
*/
public abstract class CachingAction<in T : Any, out R : Any>(
public val outputType: KType,
) : Action<T, R> {
protected abstract fun CoroutineScope.transform(
set: DataSet<T>,
meta: Meta,
key: Name = Name.EMPTY,
): Flow<NamedData<R>>
override suspend fun execute(
dataSet: DataSet<T>,
meta: Meta,
scope: CoroutineScope?,
): DataSet<R> = ActiveDataTree<R>(outputType) {
coroutineScope {
populate(transform(dataSet, meta))
}
scope?.let {
dataSet.updates.collect {
//clear old nodes
remove(it)
//collect new items
populate(scope.transform(dataSet, meta, it))
//FIXME if the target is data, updates are fired twice
}
}
}
}

View File

@ -1,6 +1,6 @@
package hep.dataforge.data
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext

View File

@ -3,28 +3,32 @@ package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaRepr
import hep.dataforge.meta.isEmpty
import kotlinx.coroutines.CoroutineScope
import hep.dataforge.misc.DFInternal
import hep.dataforge.misc.Type
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A data element characterized by its meta
*/
public interface Data<out T : Any> : Goal<T>, MetaRepr{
@Type(Data.TYPE)
public interface Data<out T : Any> : Goal<T>, MetaRepr {
/**
* Type marker for the data. The type is known before the calculation takes place so it could be checked.
*/
public val type: KClass<out T>
public val type: KType
/**
* Meta for the data
*/
public val meta: Meta
override fun toMeta(): Meta = Meta {
"type" put (type.simpleName?:"undefined")
if(!meta.isEmpty()) {
override fun toMeta(): Meta = Meta {
"type" put (type.toString())
if (!meta.isEmpty()) {
"meta" put meta
}
}
@ -32,131 +36,67 @@ public interface Data<out T : Any> : Goal<T>, MetaRepr{
public companion object {
public const val TYPE: String = "data"
public operator fun <T : Any> invoke(
type: KClass<out T>,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
block: suspend CoroutineScope.() -> T
): Data<T> = DynamicData(type, meta, context, dependencies, block)
/**
* The type that can't have any subtypes
*/
internal val TYPE_OF_NOTHING: KType = typeOf<Unit>()
public inline operator fun <reified T : Any> invoke(
public inline fun <reified T : Any> static(
value: T,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
noinline block: suspend CoroutineScope.() -> T
): Data<T> = invoke(T::class, meta, context, dependencies, block)
): Data<T> = StaticData(typeOf<T>(), value, meta)
public operator fun <T : Any> invoke(
name: String,
type: KClass<out T>,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
block: suspend CoroutineScope.() -> T
): Data<T> = NamedData(name, invoke(type, meta, context, dependencies, block))
/**
* An empty data containing only meta
*/
public fun empty(meta: Meta): Data<Nothing> = object : Data<Nothing> {
override val type: KType = TYPE_OF_NOTHING
override val meta: Meta = meta
override val dependencies: Collection<Goal<*>> = emptyList()
override val deferred: Deferred<Nothing>
get() = GlobalScope.async(start = CoroutineStart.LAZY) {
error("The Data is empty and could not be computed")
}
public inline operator fun <reified T : Any> invoke(
name: String,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
noinline block: suspend CoroutineScope.() -> T
): Data<T> =
invoke(name, T::class, meta, context, dependencies, block)
public fun <T : Any> static(value: T, meta: Meta = Meta.EMPTY): Data<T> =
StaticData(value, meta)
override fun async(coroutineScope: CoroutineScope): Deferred<Nothing> = deferred
override fun reset() {}
}
}
}
public class DynamicData<T : Any>(
override val type: KClass<out T>,
/**
* 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>(
override val type: KType,
override val meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
additionalContext: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
block: suspend CoroutineScope.() -> T
) : Data<T>, DynamicGoal<T>(context, dependencies, block)
block: suspend () -> T,
) : Data<T>, LazyGoal<T>(additionalContext, dependencies, block)
public class StaticData<T : Any>(
override val type: KType,
value: T,
override val meta: Meta = Meta.EMPTY
) : Data<T>, StaticGoal<T>(value) {
override val type: KClass<out T> get() = value::class
}
public class NamedData<out T : Any>(public val name: String, data: Data<T>) : Data<T> by data
public fun <T : Any, R : Any> Data<T>.map(
outputType: KClass<out R>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
block: suspend CoroutineScope.(T) -> R
): Data<R> = DynamicData(outputType, meta, coroutineContext, listOf(this)) {
block(await())
}
/**
* Create a data pipe
*/
public inline fun <T : Any, reified R : Any> Data<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
noinline block: suspend CoroutineScope.(T) -> R
): Data<R> = DynamicData(R::class, meta, coroutineContext, listOf(this)) {
block(await())
}
/**
* Create a joined data.
*/
public inline fun <T : Any, reified R : Any> Collection<Data<T>>.reduce(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta,
noinline block: suspend CoroutineScope.(Collection<T>) -> R
): Data<R> = DynamicData(
R::class,
meta,
coroutineContext,
this
) {
block(map { run { it.await() } })
}
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduce(
outputType: KClass<out R>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta,
block: suspend CoroutineScope.(Map<K, T>) -> R
): DynamicData<R> = DynamicData(
outputType,
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
/**
* A joining of multiple data into a single one
* @param K type of the map key
* @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>>.reduce(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta,
noinline block: suspend CoroutineScope.(Map<K, T>) -> R
): DynamicData<R> = DynamicData(
R::class,
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
override val meta: Meta = Meta.EMPTY,
) : Data<T>, StaticGoal<T>(value)
@Suppress("FunctionName")
@DFInternal
public fun <T : Any> Data(
type: KType,
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
block: suspend () -> T,
): Data<T> = LazyData(type, meta, context, dependencies, block)
@OptIn(DFInternal::class)
@Suppress("FunctionName")
public inline fun <reified T : Any> Data(
meta: Meta = Meta.EMPTY,
context: CoroutineContext = EmptyCoroutineContext,
dependencies: Collection<Data<*>> = emptyList(),
noinline block: suspend () -> T,
): Data<T> = Data(typeOf<T>(), meta, context, dependencies, block)

View File

@ -1,53 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.*
import hep.dataforge.names.toName
public class DataFilter : Scheme() {
/**
* A source node for the filter
*/
public var from: String? by string()
/**
* A target placement for the filtered node
*/
public var to: String? by string()
/**
* A regular expression pattern for the filter
*/
public var pattern: String by string(".*")
// val prefix by string()
// val suffix by string()
public companion object : SchemeSpec<DataFilter>(::DataFilter)
}
/**
* Apply meta-based filter to given data node
*/
public fun <T : Any> DataNode<T>.filter(filter: DataFilter): DataNode<T> {
val sourceNode = filter.from?.let { get(it.toName()).node } ?: this@filter
val regex = filter.pattern.toRegex()
val targetNode = DataTreeBuilder(type).apply {
sourceNode.dataSequence().forEach { (name, data) ->
if (name.toString().matches(regex)) {
this[name] = data
}
}
}
return filter.to?.let {
DataTreeBuilder(type).apply { this[it.toName()] = targetNode }.build()
} ?: targetNode.build()
}
/**
* Filter data using [DataFilter] specification
*/
public fun <T : Any> DataNode<T>.filter(filter: Meta): DataNode<T> = filter(DataFilter.read(filter))
/**
* Filter data using [DataFilter] builder
*/
public fun <T : Any> DataNode<T>.filter(filterBuilder: DataFilter.() -> Unit): DataNode<T> =
filter(DataFilter(filterBuilder))

View File

@ -1,296 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.*
import hep.dataforge.names.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
import kotlin.reflect.KClass
public sealed class DataItem<out T : Any> : MetaRepr {
public abstract val type: KClass<out T>
public abstract val meta: Meta
public class Node<out T : Any>(public val node: DataNode<T>) : DataItem<T>() {
override val type: KClass<out T> get() = node.type
override fun toMeta(): Meta = node.toMeta()
override val meta: Meta get() = node.meta
}
public class Leaf<out T : Any>(public val data: Data<T>) : DataItem<T>() {
override val type: KClass<out T> get() = data.type
override fun toMeta(): Meta = data.toMeta()
override val meta: Meta get() = data.meta
}
}
/**
* A tree-like data structure grouped into the node. All data inside the node must inherit its type
*/
public interface DataNode<out T : Any> : MetaRepr {
/**
* The minimal common ancestor to all data in the node
*/
public val type: KClass<out T>
public val items: Map<NameToken, DataItem<T>>
public val meta: Meta
override fun toMeta(): Meta = Meta {
"type" put (type.simpleName ?: "undefined")
"items" put {
this@DataNode.items.forEach {
it.key.toString() put it.value.toMeta()
}
}
}
/**
* Start computation for all goals in data node and return a job for the whole node
*/
@Suppress("DeferredResultUnused")
public fun CoroutineScope.startAll(): Job = launch {
items.values.forEach {
when (it) {
is DataItem.Node<*> -> it.node.run { startAll() }
is DataItem.Leaf<*> -> it.data.run { startAsync() }
}
}
}
public companion object {
public const val TYPE: String = "dataNode"
public operator fun <T : Any> invoke(type: KClass<out T>, block: DataTreeBuilder<T>.() -> Unit): DataTree<T> =
DataTreeBuilder(type).apply(block).build()
public inline operator fun <reified T : Any> invoke(noinline block: DataTreeBuilder<T>.() -> Unit): DataTree<T> =
DataTreeBuilder(T::class).apply(block).build()
public fun <T : Any> builder(type: KClass<out T>): DataTreeBuilder<T> = DataTreeBuilder(type)
}
}
public suspend fun <T: Any> DataNode<T>.join(): Unit = coroutineScope { startAll().join() }
public val <T : Any> DataItem<T>?.node: DataNode<T>? get() = (this as? DataItem.Node<T>)?.node
public val <T : Any> DataItem<T>?.data: Data<T>? get() = (this as? DataItem.Leaf<T>)?.data
public operator fun <T : Any> DataNode<T>.get(name: Name): DataItem<T>? = when (name.length) {
0 -> error("Empty name")
1 -> items[name.firstOrNull()]
else -> get(name.firstOrNull()!!.asName()).node?.get(name.cutFirst())
}
public operator fun <T : Any> DataNode<T>.get(name: String): DataItem<T>? = get(name.toName())
/**
* Sequence of all children including nodes
*/
public fun <T : Any> DataNode<T>.asSequence(): Sequence<Pair<Name, DataItem<T>>> = sequence {
items.forEach { (head, item) ->
yield(head.asName() to item)
if (item is DataItem.Node) {
val subSequence = item.node.asSequence()
.map { (name, data) -> (head.asName() + name) to data }
yieldAll(subSequence)
}
}
}
/**
* Sequence of data entries
*/
public fun <T : Any> DataNode<T>.dataSequence(): Sequence<Pair<Name, Data<T>>> = sequence {
items.forEach { (head, item) ->
when (item) {
is DataItem.Leaf -> yield(head.asName() to item.data)
is DataItem.Node -> {
val subSequence = item.node.dataSequence()
.map { (name, data) -> (head.asName() + name) to data }
yieldAll(subSequence)
}
}
}
}
public operator fun <T : Any> DataNode<T>.iterator(): Iterator<Pair<Name, DataItem<T>>> = asSequence().iterator()
public class DataTree<out T : Any> internal constructor(
override val type: KClass<out T>,
override val items: Map<NameToken, DataItem<T>>,
override val meta: Meta
) : DataNode<T>
private sealed class DataTreeBuilderItem<out T : Any> {
class Node<T : Any>(val tree: DataTreeBuilder<T>) : DataTreeBuilderItem<T>()
class Leaf<T : Any>(val value: Data<T>) : DataTreeBuilderItem<T>()
}
/**
* A builder for a DataTree.
*/
@DFBuilder
public class DataTreeBuilder<T : Any>(public val type: KClass<out T>) {
private val map = HashMap<NameToken, DataTreeBuilderItem<T>>()
private var meta = MetaBuilder()
public operator fun set(token: NameToken, node: DataTreeBuilder<out T>) {
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
map[token] = DataTreeBuilderItem.Node(node)
}
public operator fun set(token: NameToken, data: Data<T>) {
if (map.containsKey(token)) error("Tree entry with name $token is not empty")
map[token] = DataTreeBuilderItem.Leaf(data)
}
private fun buildNode(token: NameToken): DataTreeBuilder<T> {
return if (!map.containsKey(token)) {
DataTreeBuilder(type).also { map[token] = DataTreeBuilderItem.Node(it) }
} else {
(map[token] as? DataTreeBuilderItem.Node<T> ?: error("The node with name $token is occupied by leaf")).tree
}
}
private fun buildNode(name: Name): DataTreeBuilder<T> {
return when (name.length) {
0 -> this
1 -> buildNode(name.firstOrNull()!!)
else -> buildNode(name.firstOrNull()!!).buildNode(name.cutFirst())
}
}
public operator fun set(name: Name, data: Data<T>) {
when (name.length) {
0 -> error("Can't add data with empty name")
1 -> set(name.firstOrNull()!!, data)
2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = data
}
}
public operator fun set(name: Name, node: DataTreeBuilder<out T>) {
when (name.length) {
0 -> error("Can't add data with empty name")
1 -> set(name.firstOrNull()!!, node)
2 -> buildNode(name.cutLast())[name.lastOrNull()!!] = node
}
}
public operator fun set(name: Name, node: DataNode<T>): Unit = set(name, node.builder())
public operator fun set(name: Name, item: DataItem<T>): Unit = when (item) {
is DataItem.Node<T> -> set(name, item.node.builder())
is DataItem.Leaf<T> -> set(name, item.data)
}
/**
* Append data to node
*/
public infix fun String.put(data: Data<T>): Unit = set(toName(), data)
/**
* Append node
*/
public infix fun String.put(node: DataNode<T>): Unit = set(toName(), node)
public infix fun String.put(item: DataItem<T>): Unit = set(toName(), item)
/**
* Build and append node
*/
public infix fun String.put(block: DataTreeBuilder<T>.() -> Unit): Unit = set(toName(), DataTreeBuilder(type).apply(block))
/**
* Update data with given node data and meta with node meta.
*/
public fun update(node: DataNode<T>) {
node.dataSequence().forEach {
//TODO check if the place is occupied
this[it.first] = it.second
}
meta.update(node.meta)
}
public fun meta(block: MetaBuilder.() -> Unit): MetaBuilder = meta.apply(block)
public fun meta(meta: Meta) {
this.meta = meta.builder()
}
public fun build(): DataTree<T> {
val resMap = map.mapValues { (_, value) ->
when (value) {
is DataTreeBuilderItem.Leaf -> DataItem.Leaf(value.value)
is DataTreeBuilderItem.Node -> DataItem.Node(value.tree.build())
}
}
return DataTree(type, resMap, meta.seal())
}
}
public fun <T : Any> DataTreeBuilder<T>.datum(name: Name, data: Data<T>) {
this[name] = data
}
public fun <T : Any> DataTreeBuilder<T>.datum(name: String, data: Data<T>) {
this[name.toName()] = data
}
public fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, meta: Meta = Meta.EMPTY) {
this[name] = Data.static(data, meta)
}
public fun <T : Any> DataTreeBuilder<T>.static(name: Name, data: T, block: MetaBuilder.() -> Unit = {}) {
this[name] = Data.static(data, Meta(block))
}
public fun <T : Any> DataTreeBuilder<T>.static(name: String, data: T, block: MetaBuilder.() -> Unit = {}) {
this[name.toName()] = Data.static(data, Meta(block))
}
public fun <T : Any> DataTreeBuilder<T>.node(name: Name, node: DataNode<T>) {
this[name] = node
}
public fun <T : Any> DataTreeBuilder<T>.node(name: String, node: DataNode<T>) {
this[name.toName()] = node
}
public inline fun <reified T : Any> DataTreeBuilder<T>.node(name: Name, noinline block: DataTreeBuilder<T>.() -> Unit) {
this[name] = DataNode(T::class, block)
}
public inline fun <reified T : Any> DataTreeBuilder<T>.node(name: String, noinline block: DataTreeBuilder<T>.() -> Unit) {
this[name.toName()] = DataNode(T::class, block)
}
/**
* Generate a mutable builder from this node. Node content is not changed
*/
public fun <T : Any> DataNode<T>.builder(): DataTreeBuilder<T> = DataTreeBuilder(type).apply {
dataSequence().forEach { (name, data) -> this[name] = data }
}
public fun <T : Any> DataNode<T>.filter(predicate: (Name, Data<T>) -> Boolean): DataNode<T> = DataNode.invoke(type) {
dataSequence().forEach { (name, data) ->
if (predicate(name, data)) {
this[name] = data
}
}
}
public fun <T : Any> DataNode<T>.first(): Data<T>? = dataSequence().first().second

View File

@ -0,0 +1,99 @@
package hep.dataforge.data
import hep.dataforge.data.Data.Companion.TYPE_OF_NOTHING
import hep.dataforge.meta.Meta
import hep.dataforge.meta.set
import hep.dataforge.names.*
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.reflect.KType
public interface DataSet<out T : Any> {
/**
* The minimal common ancestor to all data in the node
*/
public val dataType: KType
/**
* Traverse this provider or its child. The order is not guaranteed.
* [root] points to a root name for traversal. If it is empty, traverse this source, if it points to a [Data],
* return flow, that contains single [Data], if it points to a node with children, return children.
*/
public fun flow(): Flow<NamedData<T>>
/**
* Get data with given name.
*/
public suspend fun getData(name: Name): Data<T>?
/**
* Get a snapshot of names of children of given node. Empty if node does not exist or is a leaf.
*
* By default traverses the whole tree. Could be optimized in descendants
*/
public suspend fun listChildren(prefix: Name = Name.EMPTY): List<Name> =
flow().map { it.name }.filter { it.startsWith(prefix) && (it.length == prefix.length + 1) }.toList()
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
private val nothing: Nothing get() = error("this is nothing")
override fun flow(): Flow<NamedData<Nothing>> = emptyFlow()
override suspend fun getData(name: Name): Data<Nothing>? = null
}
}
}
public interface ActiveDataSet<T : Any> : DataSet<T> {
/**
* 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>
}
public val <T : Any> DataSet<T>.updates: Flow<Name> get() = if (this is ActiveDataSet) updates else emptyFlow()
/**
* Flow all data nodes with names starting with [branchName]
*/
public fun <T : Any> DataSet<T>.flowChildren(branchName: Name): Flow<NamedData<T>> = this@flowChildren.flow().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 {
flow().map {
it.launch(this@launch)
}.toList().joinAll()
}
public suspend fun <T : Any> DataSet<T>.join(): Unit = coroutineScope { startAll(this).join() }
public suspend fun DataSet<*>.toMeta(): Meta = Meta {
flow().collect {
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 { getData(it)?.named(it) }

View File

@ -0,0 +1,145 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name
import hep.dataforge.names.plus
import hep.dataforge.names.toName
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collect
import kotlin.reflect.KType
public interface DataSetBuilder<in T : Any> {
public val dataType: KType
/**
* Remove all data items starting with [name]
*/
public suspend fun remove(name: Name)
public suspend fun emit(name: Name, data: Data<T>?)
/**
* Set a current state of given [dataSet] into a branch [name]. Does not propagate updates
*/
public suspend fun emit(name: Name, dataSet: DataSet<T>) {
//remove previous items
if (name != Name.EMPTY) {
remove(name)
}
//Set new items
dataSet.flow().collect {
emit(name + it.name, it.data)
}
}
/**
* Append data to node
*/
public suspend infix fun String.put(data: Data<T>): Unit = emit(toName(), data)
/**
* Append node
*/
public suspend infix fun String.put(dataSet: DataSet<T>): Unit = emit(toName(), dataSet)
/**
* Build and append node
*/
public suspend infix fun String.put(block: suspend DataSetBuilder<T>.() -> Unit): Unit = emit(toName(), block)
}
private class SubSetBuilder<in T : Any>(
private val parent: DataSetBuilder<T>,
private val branch: Name,
) : DataSetBuilder<T> {
override val dataType: KType get() = parent.dataType
override suspend fun remove(name: Name) {
parent.remove(branch + name)
}
override suspend fun emit(name: Name, data: Data<T>?) {
parent.emit(branch + name, data)
}
override suspend fun emit(name: Name, dataSet: DataSet<T>) {
parent.emit(branch + name, dataSet)
}
}
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: Name, block: suspend DataSetBuilder<T>.() -> Unit) {
SubSetBuilder(this, name).apply { block() }
}
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, data: Data<T>) {
emit(name.toName(), data)
}
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, set: DataSet<T>) {
this.emit(name.toName(), set)
}
public suspend fun <T : Any> DataSetBuilder<T>.emit(name: String, block: suspend DataSetBuilder<T>.() -> Unit): Unit =
this@emit.emit(name.toName(), block)
public suspend fun <T : Any> DataSetBuilder<T>.emit(data: NamedData<T>) {
emit(data.name, data.data)
}
/**
* Produce lazy [Data] and emit it into the [DataSetBuilder]
*/
public suspend inline fun <reified T : Any> DataSetBuilder<T>.produce(
name: String,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
emit(name, data)
}
public suspend inline fun <reified T : Any> DataSetBuilder<T>.produce(
name: Name,
meta: Meta = Meta.EMPTY,
noinline producer: suspend () -> T,
) {
val data = Data(meta, block = producer)
emit(name, data)
}
/**
* Emit a static data with the fixed value
*/
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(name: String, data: T, meta: Meta = Meta.EMPTY): Unit =
emit(name, Data.static(data, meta))
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(name: Name, data: T, meta: Meta = Meta.EMPTY): Unit =
emit(name, Data.static(data, meta))
public suspend inline fun <reified T : Any> DataSetBuilder<T>.static(
name: String,
data: T,
metaBuilder: MetaBuilder.() -> Unit,
): Unit = emit(name.toName(), Data.static(data, Meta(metaBuilder)))
/**
* Update data with given node data and meta with node meta.
*/
@DFExperimental
public suspend fun <T : Any> DataSetBuilder<T>.populate(tree: DataSet<T>): Unit = coroutineScope {
tree.flow().collect {
//TODO check if the place is occupied
emit(it.name, it.data)
}
}
public suspend fun <T : Any> DataSetBuilder<T>.populate(flow: Flow<NamedData<T>>) {
flow.collect {
emit(it.name, it.data)
}
}

View File

@ -0,0 +1,96 @@
package hep.dataforge.data
import hep.dataforge.misc.Type
import hep.dataforge.names.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.reflect.KType
public sealed class DataTreeItem<out T : Any> {
public class Node<out T : Any>(public val tree: DataTree<T>) : DataTreeItem<T>()
public class Leaf<out T : Any>(public val data: Data<T>) : DataTreeItem<T>()
}
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
*/
@Type(DataTree.TYPE)
public interface DataTree<out T : Any> : DataSet<T> {
/**
* Children items of this [DataTree] provided asynchronously
*/
public suspend fun items(): Map<NameToken, DataTreeItem<T>>
override fun flow(): Flow<NamedData<T>> = flow {
items().forEach { (token, childItem: DataTreeItem<T>) ->
if(!token.body.startsWith("@")) {
when (childItem) {
is DataTreeItem.Leaf -> emit(childItem.data.named(token.asName()))
is DataTreeItem.Node -> emitAll(childItem.tree.flow().map { it.named(token + it.name) })
}
}
}
}
override suspend fun listChildren(prefix: Name): List<Name> =
getItem(prefix).tree?.items()?.keys?.map { prefix + it } ?: emptyList()
override suspend fun getData(name: Name): Data<T>? = when (name.length) {
0 -> null
1 -> items()[name.firstOrNull()!!].data
else -> items()[name.firstOrNull()!!].tree?.getData(name.cutFirst())
}
public companion object {
public const val TYPE: String = "dataTree"
}
}
public suspend fun <T: Any> DataSet<T>.getData(name: String): Data<T>? = getData(name.toName())
/**
* Get a [DataTreeItem] with given [name] or null if the item does not exist
*/
public tailrec suspend 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
/**
* Flow of all children including nodes
*/
public fun <T : Any> DataTree<T>.itemFlow(): Flow<Pair<Name, DataTreeItem<T>>> = flow {
items().forEach { (head, item) ->
emit(head.asName() to item)
if (item is DataTreeItem.Node) {
val subSequence = item.tree.itemFlow()
.map { (name, data) -> (head.asName() + name) to data }
emitAll(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]
*/
public fun <T : Any> DataTree<T>.branch(branchName: Name): DataTree<T> = object : DataTree<T> {
override val dataType: KType get() = this@branch.dataType
override suspend fun items(): Map<NameToken, DataTreeItem<T>> = getItem(branchName).tree?.items() ?: emptyMap()
}

View File

@ -1,22 +1,28 @@
package hep.dataforge.data
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
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<*>>
/**
* Returns current running coroutine if the goal is started
* Returns current running coroutine if the goal is started. Null if the computation is not started.
*/
public val result: Deferred<T>?
public val deferred: Deferred<T>?
/**
* Get ongoing computation or start a new one.
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
*
* If the computation is already running, the scope is not used.
*/
public fun CoroutineScope.startAsync(): Deferred<T>
public fun async(coroutineScope: CoroutineScope): Deferred<T>
/**
* Reset the computation
@ -26,89 +32,81 @@ public interface Goal<out T> {
public companion object
}
public suspend fun <T> Goal<T>.await(): T = coroutineScope { startAsync().await() }
public fun Goal<*>.launch(coroutineScope: CoroutineScope): Job = async(coroutineScope)
public val Goal<*>.isComplete: Boolean get() = result?.isCompleted ?: false
public suspend fun <T> Goal<T>.await(): T = coroutineScope { async(this).await() }
public val Goal<*>.isComplete: Boolean get() = deferred?.isCompleted ?: false
public open class StaticGoal<T>(public val value: T) : Goal<T> {
override val dependencies: Collection<Goal<*>> get() = emptyList()
override val result: Deferred<T> = CompletableDeferred(value)
override val deferred: Deferred<T> = CompletableDeferred(value)
override fun CoroutineScope.startAsync(): Deferred<T> = result
override fun async(coroutineScope: CoroutineScope): Deferred<T> = deferred
override fun reset() {
//doNothing
}
}
public open class DynamicGoal<T>(
/**
* @param coroutineContext additional context information
*/
public open class LazyGoal<T>(
private val coroutineContext: CoroutineContext = EmptyCoroutineContext,
override val dependencies: Collection<Goal<*>> = emptyList(),
public val block: suspend CoroutineScope.() -> T
public val block: suspend () -> T,
) : Goal<T> {
final override var result: Deferred<T>? = null
final override var deferred: Deferred<T>? = null
private set
/**
* Get ongoing computation or start a new one.
* Does not guarantee thread safety. In case of multi-thread access, could create orphan computations.
* If [GoalExecutionRestriction] is present in the [coroutineScope] context, the call could produce a error a warning
* depending on the settings.
*/
@DFExperimental
override fun CoroutineScope.startAsync(): Deferred<T> {
val startedDependencies = this@DynamicGoal.dependencies.map { goal ->
goal.run { startAsync() }
}
return result
?: async(this@DynamicGoal.coroutineContext + CoroutineMonitor() + Dependencies(startedDependencies)) {
startedDependencies.forEach { deferred ->
deferred.invokeOnCompletion { error ->
if (error != null) cancel(CancellationException("Dependency $deferred failed with error: ${error.message}"))
}
override fun async(coroutineScope: CoroutineScope): Deferred<T> {
val log = coroutineScope.coroutineContext[GoalLogger]
// Check if context restricts goal computation
coroutineScope.coroutineContext[GoalExecutionRestriction]?.let { restriction ->
when (restriction.policy) {
GoalExecutionRestrictionPolicy.WARNING -> log?.emit(GoalLogger.WARNING_TAG) { "Goal eager execution is prohibited by the coroutine scope policy" }
GoalExecutionRestrictionPolicy.ERROR -> error("Goal eager execution is prohibited by the coroutine scope policy")
else -> {
/*do nothing*/
}
block()
}.also { result = it }
}
}
log?.emit { "Starting dependencies computation for ${this@LazyGoal}" }
val startedDependencies = this.dependencies.map { goal ->
goal.run { async(coroutineScope) }
}
return deferred ?: coroutineScope.async(
coroutineContext
+ CoroutineMonitor()
+ Dependencies(startedDependencies)
+ GoalExecutionRestriction(GoalExecutionRestrictionPolicy.NONE) // Remove restrictions on goal execution
) {
//cancel execution if error encountered in one of dependencies
startedDependencies.forEach { deferred ->
deferred.invokeOnCompletion { error ->
if (error != null) this.cancel(CancellationException("Dependency $deferred failed with error: ${error.message}"))
}
}
coroutineContext[GoalLogger]?.emit { "Starting computation of ${this@LazyGoal}" }
block()
}.also { deferred = it }
}
/**
* Reset the computation
*/
override fun reset() {
result?.cancel()
result = null
deferred?.cancel()
deferred = null
}
}
/**
* Create a one-to-one goal based on existing goal
*/
public fun <T, R> Goal<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.(T) -> R
): Goal<R> = DynamicGoal(coroutineContext, listOf(this)) {
block(await())
}
/**
* Create a joining goal.
*/
public fun <T, R> Collection<Goal<T>>.reduce(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.(Collection<T>) -> R
): Goal<R> = DynamicGoal(coroutineContext, this) {
block(map { run { it.await() } })
}
/**
* A joining goal for a map
* @param K type of the map key
* @param T type of the input goal
* @param R type of the result goal
*/
public fun <K, T, R> Map<K, Goal<T>>.reduce(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.(Map<K, T>) -> R
): Goal<R> = DynamicGoal(coroutineContext, this.values) {
block(mapValues { it.value.await() })
}
}

View File

@ -0,0 +1,17 @@
package hep.dataforge.data
import kotlin.coroutines.CoroutineContext
public enum class GoalExecutionRestrictionPolicy {
NONE,
WARNING,
ERROR
}
public class GoalExecutionRestriction(
public val policy: GoalExecutionRestrictionPolicy = GoalExecutionRestrictionPolicy.ERROR,
) : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> get() = Companion
public companion object : CoroutineContext.Key<GoalExecutionRestriction>
}

View File

@ -0,0 +1,13 @@
package hep.dataforge.data
import kotlin.coroutines.CoroutineContext
public interface GoalLogger : CoroutineContext.Element {
override val key: CoroutineContext.Key<*> get() = GoalLogger
public fun emit(vararg tags: String, message: suspend () -> String)
public companion object : CoroutineContext.Key<GoalLogger>{
public const val WARNING_TAG: String = "WARNING"
}
}

View File

@ -15,14 +15,16 @@
*/
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.string
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
public interface GroupRule {
public operator fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>>
public suspend fun <T : Any> gather(set: DataSet<T>): Map<String, DataSet<T>>
public companion object{
public companion object {
/**
* Create grouping rule that creates groups for different values of value
* field with name [key]
@ -31,38 +33,32 @@ public interface GroupRule {
* @param defaultTagValue
* @return
*/
public fun byValue(key: String, defaultTagValue: String): GroupRule = object :
GroupRule {
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> {
val map = HashMap<String, DataTreeBuilder<T>>()
public fun byMetaValue(
scope: CoroutineScope,
key: String,
defaultTagValue: String,
): GroupRule = object : GroupRule {
node.dataSequence().forEach { (name, data) ->
override suspend fun <T : Any> gather(
set: DataSet<T>,
): Map<String, DataSet<T>> {
val map = HashMap<String, ActiveDataTree<T>>()
set.flow().collect { data ->
val tagValue = data.meta[key]?.string ?: defaultTagValue
map.getOrPut(tagValue) { DataNode.builder(node.type) }[name] = data
map.getOrPut(tagValue) { ActiveDataTree(set.dataType) }.emit(data.name, data.data)
}
return map.mapValues { it.value.build() }
}
}
// @ValueDef(key = "byValue", required = true, info = "The name of annotation value by which grouping should be made")
// @ValueDef(
// key = "defaultValue",
// def = "default",
// info = "Default value which should be used for content in which the grouping value is not presented"
// )
public fun byMeta(config: Meta): GroupRule {
//TODO expand grouping options
return config["byValue"]?.string?.let {
byValue(
it,
config["defaultValue"]?.string ?: "default"
)
}
?: object : GroupRule {
override fun <T : Any> invoke(node: DataNode<T>): Map<String, DataNode<T>> = mapOf("" to node)
scope.launch {
set.updates.collect { name ->
val data = set.getData(name)
val tagValue = data?.meta[key]?.string ?: defaultTagValue
map.getOrPut(tagValue) { ActiveDataTree(set.dataType) }.emit(name, data)
}
}
return map
}
}
}
}
}

View File

@ -1,75 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import kotlin.reflect.KClass
/**
* Action environment includes data name, data meta and action configuration meta
*/
public data class ActionEnv(
val name: Name,
val meta: Meta,
val actionMeta: Meta
)
/**
* Action environment
*/
@DFBuilder
public class MapActionBuilder<T, R>(public var name: Name, public var meta: MetaBuilder, public val actionMeta: Meta) {
public lateinit var result: suspend ActionEnv.(T) -> R
/**
* Calculate the result of goal
*/
public fun result(f: suspend ActionEnv.(T) -> R) {
result = f;
}
}
public class MapAction<T : Any, out R : Any>(
public val inputType: KClass<T>,
public val outputType: KClass<out R>,
private val block: MapActionBuilder<T, R>.() -> Unit
) : Action<T, R> {
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
node.ensureType(inputType)
return DataNode.invoke(outputType) {
node.dataSequence().forEach { (name, data) ->
/*
* Creating a new environment for action using **old** name, old meta and task meta
*/
val env = ActionEnv(name, data.meta, meta)
//applying transformation from builder
val builder = MapActionBuilder<T, R>(
name,
data.meta.builder(), // using data meta
meta
).apply(block)
//getting new name
val newName = builder.name
//getting new meta
val newMeta = builder.meta.seal()
val newData = data.map(outputType, meta = newMeta) { builder.result(env, it) }
//setting the data node
this[newName] = newData
}
}
}
}
public inline fun <reified T : Any, reified R : Any> DataNode<T>.map(
meta: Meta,
noinline action: MapActionBuilder<in T, out R>.() -> Unit
): DataNode<R> = MapAction(T::class, R::class, action).invoke(this, meta)

View File

@ -0,0 +1,32 @@
package hep.dataforge.data
import hep.dataforge.meta.isEmpty
import hep.dataforge.misc.Named
import hep.dataforge.names.Name
public interface NamedData<out T : Any> : Named, Data<T> {
override val name: Name
public val data: Data<T>
}
private class NamedDataImpl<out T : Any>(
override val name: Name,
override val data: Data<T>,
) : Data<T> by data, NamedData<T> {
override fun toString(): String = buildString {
append("NamedData(name=\"$name\"")
if (data is StaticData) {
append(", value=${data.value}")
}
if (!data.meta.isEmpty()) {
append(", meta=${data.meta}")
}
append(")")
}
}
public fun <T : Any> Data<T>.named(name: Name): NamedData<T> = if (this is NamedData) {
NamedDataImpl(name, this.data)
} else {
NamedDataImpl(name, this)
}

View File

@ -1,107 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlin.reflect.KClass
public class JoinGroup<T : Any, R : Any>(public var name: String, internal val node: DataNode<T>) {
public var meta: MetaBuilder = MetaBuilder()
public lateinit var result: suspend ActionEnv.(Map<Name, T>) -> R
public fun result(f: suspend ActionEnv.(Map<Name, T>) -> R) {
this.result = f;
}
}
public class ReduceGroupBuilder<T : Any, R : Any>(public val actionMeta: Meta) {
private val groupRules: MutableList<(DataNode<T>) -> List<JoinGroup<T, R>>> = ArrayList();
/**
* introduce grouping by value name
*/
public fun byValue(tag: String, defaultTag: String = "@default", action: JoinGroup<T, R>.() -> Unit) {
groupRules += { node ->
GroupRule.byValue(tag, defaultTag).invoke(node).map {
JoinGroup<T, R>(it.key, it.value).apply(action)
}
}
}
/**
* Add a single fixed group to grouping rules
*/
public fun group(groupName: String, filter: DataFilter, action: JoinGroup<T, R>.() -> Unit) {
groupRules += { node ->
listOf(
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
)
}
}
public fun group(groupName: String, filter: (Name, Data<T>) -> Boolean, action: JoinGroup<T, R>.() -> Unit) {
groupRules += { node ->
listOf(
JoinGroup<T, R>(groupName, node.filter(filter)).apply(action)
)
}
}
/**
* Apply transformation to the whole node
*/
public fun result(resultName: String, f: suspend ActionEnv.(Map<Name, T>) -> R) {
groupRules += { node ->
listOf(JoinGroup<T, R>(resultName, node).apply { result(f) })
}
}
internal fun buildGroups(input: DataNode<T>): List<JoinGroup<T, R>> {
return groupRules.flatMap { it.invoke(input) }
}
}
/**
* The same rules as for KPipe
*/
public class ReduceAction<T : Any, R : Any>(
public val inputType: KClass<T>,
public val outputType: KClass<out R>,
private val action: ReduceGroupBuilder<T, R>.() -> Unit
) : Action<T, R> {
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
node.ensureType(inputType)
return DataNode.invoke(outputType) {
ReduceGroupBuilder<T, R>(meta).apply(action).buildGroups(node).forEach { group ->
//val laminate = Laminate(group.meta, meta)
val dataMap = group.node.dataSequence().associate { it }
val groupName: String = group.name
val groupMeta = group.meta
val env = ActionEnv(groupName.toName(), groupMeta, meta)
val res: DynamicData<R> = dataMap.reduce(
outputType,
meta = groupMeta
) { group.result.invoke(env, it) }
set(env.name, res)
}
}
}
}
public operator fun <T> Map<Name, T>.get(name: String): T? = get(name.toName())

View File

@ -1,64 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.Laminate
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.builder
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlin.collections.set
import kotlin.reflect.KClass
public class FragmentRule<T : Any, R : Any>(public val name: Name, public var meta: MetaBuilder) {
public lateinit var result: suspend (T) -> R
public fun result(f: suspend (T) -> R) {
result = f;
}
}
public class SplitBuilder<T : Any, R : Any>(public val name: Name, public val meta: Meta) {
internal val fragments: MutableMap<Name, FragmentRule<T, R>.() -> Unit> = HashMap()
/**
* Add new fragment building rule. If the framgent not defined, result won't be available even if it is present in the map
* @param name the name of a fragment
* @param rule the rule to transform fragment name and meta using
*/
public fun fragment(name: String, rule: FragmentRule<T, R>.() -> Unit) {
fragments[name.toName()] = rule
}
}
public class SplitAction<T : Any, R : Any>(
public val inputType: KClass<T>,
public val outputType: KClass<out R>,
private val action: SplitBuilder<T, R>.() -> Unit
) : Action<T, R> {
override fun invoke(node: DataNode<T>, meta: Meta): DataNode<R> {
node.ensureType(inputType)
return DataNode.invoke(outputType) {
node.dataSequence().forEach { (name, data) ->
val laminate = Laminate(data.meta, meta)
val split = SplitBuilder<T, R>(name, data.meta).apply(action)
// apply individual fragment rules to result
split.fragments.forEach { (fragmentName, rule) ->
val env = FragmentRule<T, R>(fragmentName, laminate.builder())
rule(env)
val res = data.map(outputType, meta = env.meta) { env.result(it) }
set(env.name, res)
}
}
}
}
}

View File

@ -0,0 +1,76 @@
package hep.dataforge.data
import hep.dataforge.names.*
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collect
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 suspend fun items(): Map<NameToken, DataTreeItem<T>> = items.filter { !it.key.body.startsWith("@") }
override suspend 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 suspend 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 suspend fun emit(name: Name, data: Data<T>?) {
set(name, data?.let { DataTreeItem.Leaf(it) })
}
override suspend fun emit(name: Name, dataSet: DataSet<T>) {
if (dataSet is StaticDataTree) {
set(name, DataTreeItem.Node(dataSet))
} else {
coroutineScope {
dataSet.flow().collect {
emit(name + it.name, it.data)
}
}
}
}
}
@Suppress("FunctionName")
public suspend fun <T : Any> DataTree(
dataType: KType,
block: suspend DataSetBuilder<T>.() -> Unit,
): DataTree<T> = StaticDataTree<T>(dataType).apply { block() }
@Suppress("FunctionName")
public suspend inline fun <reified T : Any> DataTree(
noinline block: suspend DataSetBuilder<T>.() -> Unit,
): DataTree<T> = DataTree(typeOf<T>(), block)
public suspend fun <T : Any> DataSet<T>.seal(): DataTree<T> = DataTree(dataType){
populate(this@seal)
}

View File

@ -1,73 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.names.NameToken
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlin.reflect.KClass
public fun <R : Any, T : R> Data<T>.upcast(type: KClass<out R>): Data<R> {
return object : Data<R> by this {
override val type: KClass<out R> = type
}
}
/**
* Safe upcast a [Data] to a supertype
*/
public inline fun <reified R : Any, T : R> Data<T>.upcast(): Data<R> = upcast(R::class)
/**
* Check if node could be safely cast to given class
*/
internal expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean
/**
* Check if data could be safely cast to given class
*/
internal expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean
public fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
is DataItem.Node -> node.canCast(type)
is DataItem.Leaf -> data.canCast(type)
}
/**
* Unsafe cast of data node
*/
@Suppress("UNCHECKED_CAST")
public fun <R : Any> Data<*>.cast(type: KClass<out R>): Data<R> {
return object : Data<R> {
override val meta: Meta get() = this@cast.meta
override val dependencies: Collection<Goal<*>> get() = this@cast.dependencies
override val result: Deferred<R>? get() = this@cast.result as Deferred<R>
override fun CoroutineScope.startAsync(): Deferred<R> = this@cast.run { startAsync() as Deferred<R> }
override fun reset() = this@cast.reset()
override val type: KClass<out R> = type
}
}
public inline fun <reified R : Any> Data<*>.cast(): Data<R> = cast(R::class)
@Suppress("UNCHECKED_CAST")
public fun <R : Any> DataNode<*>.cast(type: KClass<out R>): DataNode<R> {
return object : DataNode<R> {
override val meta: Meta get() = this@cast.meta
override val type: KClass<out R> = type
override val items: Map<NameToken, DataItem<R>> get() = this@cast.items as Map<NameToken, DataItem<R>>
}
}
public inline fun <reified R : Any> DataNode<*>.cast(): DataNode<R> = cast(R::class)
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
public fun <T : Any> DataNode<*>.ensureType(type: KClass<out T>) {
if (!canCast(type)) {
error("$type expected, but $type received")
}
}
//expect fun <T : Any, R : Any> DataNode<T>.cast(type: KClass<out R>): DataNode<R>

View File

@ -0,0 +1,71 @@
package hep.dataforge.data
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KType
/**
* A stateless filtered [DataSet]
*/
public fun <T : Any> DataSet<T>.filter(
predicate: suspend (Name, Data<T>) -> Boolean,
): ActiveDataSet<T> = object : ActiveDataSet<T> {
override val dataType: KType get() = this@filter.dataType
override fun flow(): Flow<NamedData<T>> =
this@filter.flow().filter { predicate(it.name, it.data) }
override suspend fun getData(name: Name): Data<T>? = this@filter.getData(name)?.takeIf {
predicate(name, it)
}
override val updates: Flow<Name> = this@filter.updates.filter flowFilter@{ name ->
val theData = this@filter.getData(name) ?: return@flowFilter false
predicate(name, theData)
}
}
/**
* 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 : ActiveDataSet<T> {
override val dataType: KType get() = this@withNamePrefix.dataType
override fun flow(): Flow<NamedData<T>> = this@withNamePrefix.flow().map { it.data.named(prefix + it.name) }
override suspend fun getData(name: Name): Data<T>? =
name.removeHeadOrNull(name)?.let { this@withNamePrefix.getData(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 : ActiveDataSet<T> {
override val dataType: KType get() = this@branch.dataType
override fun flow(): Flow<NamedData<T>> = this@branch.flow().mapNotNull {
it.name.removeHeadOrNull(branchName)?.let { name ->
it.data.named(name)
}
}
override suspend fun getData(name: Name): Data<T>? = this@branch.getData(branchName + name)
override val updates: Flow<Name> get() = this@branch.updates.mapNotNull { it.removeHeadOrNull(branchName) }
}
public fun <T : Any> DataSet<T>.branch(branchName: String): DataSet<T> = this@branch.branch(branchName.toName())
@DFExperimental
public suspend fun <T : Any> DataSet<T>.rootData(): Data<T>? = getData(Name.EMPTY)

View File

@ -0,0 +1,20 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
/**
* Get a metadata node for this set if it is present
*/
public suspend fun DataSet<*>.getMeta(): Meta? = getData(DataSet.META_KEY)?.meta
/**
* Add meta-data node to a [DataSet]
*/
public suspend fun DataSetBuilder<*>.meta(meta: Meta): Unit = emit(DataSet.META_KEY, Data.empty(meta))
/**
* Add meta-data node to a [DataSet]
*/
public suspend fun DataSetBuilder<*>.meta(metaBuilder: MetaBuilder.() -> Unit): Unit = meta(Meta(metaBuilder))

View File

@ -0,0 +1,181 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.seal
import hep.dataforge.meta.toMutableMeta
import hep.dataforge.misc.DFInternal
import kotlinx.coroutines.flow.*
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* Lazily transform this data to another data. By convention [block] should not use external data (be pure).
* @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
*/
public inline fun <T : Any, reified R : Any> Data<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
crossinline block: suspend (T) -> R,
): Data<R> = Data(meta, coroutineContext, listOf(this)) {
block(await())
}
/**
* Combine this data with the other data using [block]. See [map] for other details
*/
public inline fun <T1 : Any, T2 : Any, reified R : Any> Data<T1>.combine(
other: Data<T2>,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = this.meta,
crossinline block: suspend (left: T1, right: T2) -> R,
): Data<R> = Data(meta, coroutineContext, listOf(this, other)) {
block(await(), other.await())
}
//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 (Collection<T>) -> R,
): Data<R> = Data(
meta,
coroutineContext,
this
) {
block(map { it.await() })
}
@DFInternal
public fun <K, T : Any, R : Any> Map<K, Data<T>>.reduceToData(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
block: suspend (Map<K, T>) -> R,
): Data<R> = Data(
outputType,
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
/**
* Lazily reduce a [Map] of [Data] with any static key.
* @param K type of the map key
* @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(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (Map<K, T>) -> R,
): Data<R> = Data(
meta,
coroutineContext,
this.values
) {
block(mapValues { it.value.await() })
}
//flow operations
/**
* Transform a [Flow] of [NamedData] to a single [Data].
*/
@DFInternal
public suspend fun <T : Any, R : Any> Flow<NamedData<T>>.reduceToData(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
transformation: suspend (Flow<NamedData<T>>) -> R,
): Data<R> = Data(
outputType,
meta,
coroutineContext,
toList()
) {
transformation(this)
}
@OptIn(DFInternal::class)
public suspend inline fun <T : Any, reified R : Any> Flow<NamedData<T>>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline transformation: suspend (Flow<NamedData<T>>) -> R,
): Data<R> = reduceToData(typeOf<R>(), coroutineContext, meta) {
transformation(it)
}
/**
* Fold a flow of named data into a single [Data]
*/
public suspend inline fun <T : Any, reified R : Any> Flow<NamedData<T>>.foldToData(
initial: R,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (result: R, data: NamedData<T>) -> R,
): Data<R> = reduceToData(
coroutineContext, meta
) {
it.fold(initial, block)
}
//DataSet operations
@DFInternal
public suspend fun <T : Any, R : Any> DataSet<T>.map(
outputType: KType,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
metaTransform: MetaBuilder.() -> Unit = {},
block: suspend (T) -> R,
): DataTree<R> = DataTree<R>(outputType) {
populate(
flow().map {
val newMeta = it.meta.toMutableMeta().apply(metaTransform).seal()
Data(outputType, newMeta, coroutineContext, listOf(it)) {
block(it.await())
}.named(it.name)
}
)
}
@OptIn(DFInternal::class)
public suspend inline fun <T : Any, reified R : Any> DataSet<T>.map(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
noinline metaTransform: MetaBuilder.() -> Unit = {},
noinline block: suspend (T) -> R,
): DataTree<R> = map(typeOf<R>(), coroutineContext, metaTransform, block)
public suspend fun <T : Any> DataSet<T>.forEach(block: suspend (NamedData<T>) -> Unit) {
contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) }
flow().collect {
block(it)
}
}
public suspend inline fun <T : Any, reified R : Any> DataSet<T>.reduceToData(
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline transformation: suspend (Flow<NamedData<T>>) -> R,
): Data<R> = flow().reduceToData(coroutineContext, meta, transformation)
public suspend inline fun <T : Any, reified R : Any> DataSet<T>.foldToData(
initial: R,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
meta: Meta = Meta.EMPTY,
noinline block: suspend (result: R, data: NamedData<T>) -> R,
): Data<R> = flow().foldToData(initial, coroutineContext, meta, block)

View File

@ -1,32 +0,0 @@
package hep.dataforge.data
import kotlin.test.Test
import kotlin.test.assertTrue
internal class DataTreeBuilderTest{
@Test
fun testDataUpdate(){
val updateData = DataNode<Any>{
"update" put {
"a" put Data.static("a")
"b" put Data.static("b")
}
}
val node = DataNode<Any>{
node("primary"){
static("a","a")
static("b","b")
}
static("root","root")
update(updateData)
}
println(node.toMeta())
assertTrue { node["update.a"] != null }
assertTrue { node["primary.a"] != null }
}
}

View File

@ -1,14 +0,0 @@
package hep.dataforge.data
import kotlin.reflect.KClass
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
return this.type == type
}
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
return this.type == type
}

View File

@ -1,27 +0,0 @@
package hep.dataforge.data
import hep.dataforge.meta.Meta
import hep.dataforge.names.NameToken
import kotlin.reflect.KClass
/**
* A zero-copy data node wrapper that returns only children with appropriate type.
*/
public class TypeFilteredDataNode<out T : Any>(public val origin: DataNode<*>, override val type: KClass<out T>) : DataNode<T> {
override val meta: Meta get() = origin.meta
override val items: Map<NameToken, DataItem<T>> by lazy {
origin.items.mapNotNull { (key, item) ->
when (item) {
is DataItem.Leaf -> {
(item.data.filterIsInstance(type))?.let {
key to DataItem.Leaf(it)
}
}
is DataItem.Node -> {
key to DataItem.Node(item.node.filterIsInstance(type))
}
}
}.associate { it }
}
}

View File

@ -1,48 +0,0 @@
package hep.dataforge.data
import kotlinx.coroutines.runBlocking
import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf
/**
* Block the thread and get data content
*/
public fun <T : Any> Data<T>.get(): T = runBlocking { await() }
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
type.isSubclassOf(this.type)
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
this.type.isSubclassOf(type)
/**
* Cast the node to given type if the cast is possible or return null
*/
public fun <R : Any> Data<*>.filterIsInstance(type: KClass<out R>): Data<R>? =
if (canCast(type)) cast(type) else null
/**
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
* but could contain empty nodes
*/
public fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> {
return when {
canCast(type) -> cast(type)
this is TypeFilteredDataNode -> origin.filterIsInstance(type)
else -> TypeFilteredDataNode(this, type)
}
}
/**
* Filter all elements of given data item that could be cast to given type. If no elements are available, return null.
*/
public fun <R : Any> DataItem<*>?.filterIsInstance(type: KClass<out R>): DataItem<R>? = when (this) {
null -> null
is DataItem.Node -> DataItem.Node(this.node.filterIsInstance(type))
is DataItem.Leaf -> this.data.filterIsInstance(type)?.let { DataItem.Leaf(it) }
}
public inline fun <reified R : Any> DataItem<*>?.filterIsInstance(): DataItem<R>? = this@filterIsInstance.filterIsInstance(R::class)

View File

@ -0,0 +1,64 @@
package hep.dataforge.data
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.Name
import hep.dataforge.names.matches
import hep.dataforge.names.toName
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlin.reflect.KType
import kotlin.reflect.full.isSubtypeOf
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>? =
if (!this.type.isSubtypeOf(type)) null else object : Data<R> by (this as Data<R>) {
override val type: KType = type
}
/**
* Select all data matching given type and filters. Does not modify paths
*/
@OptIn(DFExperimental::class)
@PublishedApi
internal fun <R : Any> DataSet<*>.select(
type: KType,
namePattern: Name? = null,
): ActiveDataSet<R> = object : ActiveDataSet<R> {
override val dataType = type
override fun flow(): Flow<NamedData<R>> = this@select.flow().filter { datum ->
datum.type.isSubtypeOf(type) && (namePattern == null || datum.name.matches(namePattern))
}.map {
@Suppress("UNCHECKED_CAST")
it as NamedData<R>
}
override suspend fun getData(name: Name): Data<R>? = this@select.getData(name)?.castOrNull(type)
override val updates: Flow<Name> = this@select.updates.filter {
val datum = this@select.getData(it)
datum?.type?.isSubtypeOf(type) ?: false
}
}
/**
* Select a single datum of the appropriate type
*/
public inline fun <reified R : Any> DataSet<*>.select(namePattern: Name? = null): DataSet<R> =
select(typeOf<R>(), namePattern)
public suspend fun <R : Any> DataSet<*>.selectOne(type: KType, name: Name): NamedData<R>? =
getData(name)?.castOrNull<R>(type)?.named(name)
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: Name): NamedData<R>? = selectOne(typeOf<R>(), name)
public suspend inline fun <reified R : Any> DataSet<*>.selectOne(name: String): NamedData<R>? =
selectOne(typeOf<R>(), name.toName())

View File

@ -0,0 +1,42 @@
package hep.dataforge.data
import hep.dataforge.actions.Action
import hep.dataforge.actions.map
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
@Suppress("EXPERIMENTAL_API_USAGE")
class ActionsTest {
val data: DataTree<Int> = runBlocking {
DataTree {
repeat(10) {
static(it.toString(), it)
}
}
}
@Test
fun testStaticMapAction() {
val plusOne = Action.map<Int, Int> {
result { it + 1 }
}
runBlocking {
val result = plusOne.execute(data)
assertEquals(2, result.getData("1")?.await())
}
}
@Test
fun testDynamicMapAction() {
val plusOne = Action.map<Int, Int> {
result { it + 1 }
}
val datum = runBlocking {
val result = plusOne.execute(data, scope = this)
result.getData("1")?.await()
}
assertEquals(2, datum)
}
}

View File

@ -0,0 +1,90 @@
package hep.dataforge.data
import hep.dataforge.names.toName
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
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.getData("primary.a")?.await())
assertEquals("b", node.getData("primary.b")?.await())
assertEquals("c.d", node.getData("c.d")?.await())
assertEquals("c.f", node.getData("c.f")?.await())
}
}
@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")
populate(updateData)
}
runBlocking {
assertEquals("a", node.getData("update.a")?.await())
assertEquals("a", node.getData("primary.a")?.await())
}
}
@Test
fun testDynamicUpdates() = runBlocking {
try {
lateinit var updateJob: Job
supervisorScope {
val subNode = ActiveDataTree<Int> {
updateJob = launch {
repeat(10) {
delay(10)
static("value", it)
}
delay(10)
}
}
launch {
subNode.updatesWithData.collect {
println(it)
}
}
val rootNode = ActiveDataTree<Int> {
setAndObserve("sub".toName(), subNode)
}
launch {
rootNode.updatesWithData.collect {
println(it)
}
}
updateJob.join()
assertEquals(9, rootNode.getData("sub.value")?.await())
cancel()
}
} catch (t: Throwable) {
if (t !is CancellationException) throw t
}
}
}

View File

@ -1,14 +0,0 @@
package hep.dataforge.data
import kotlin.reflect.KClass
/**
* Check that node is compatible with given type meaning that each element could be cast to the type
*/
internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
return this.type == type
}
internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
return this.type == type
}

View File

@ -7,7 +7,7 @@ public final class hep/dataforge/io/BinaryMetaFormat : hep/dataforge/io/MetaForm
public fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Lhep/dataforge/io/MetaFormat;
public synthetic fun invoke (Lhep/dataforge/meta/Meta;Lhep/dataforge/context/Context;)Ljava/lang/Object;
public fun readMeta (Lkotlinx/io/Input;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Meta;
public final fun readMetaItem (Lkotlinx/io/Input;)Lhep/dataforge/meta/MetaItem;
public final fun readMetaItem (Lkotlinx/io/Input;)Lhep/dataforge/meta/TypedMetaItem;
public fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/meta/Meta;
public synthetic fun readObject (Lkotlinx/io/Input;)Ljava/lang/Object;
public fun toMeta ()Lhep/dataforge/meta/Meta;
@ -77,6 +77,10 @@ public final class hep/dataforge/io/EnvelopeBuilder : hep/dataforge/io/Envelope
public final fun setType (Ljava/lang/String;)V
}
public final class hep/dataforge/io/EnvelopeBuilderKt {
public static final fun Envelope (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/io/Envelope;
}
public abstract interface class hep/dataforge/io/EnvelopeFormat : hep/dataforge/io/IOFormat {
public abstract fun getDefaultMetaFormat ()Lhep/dataforge/io/MetaFormatFactory;
public abstract fun readObject (Lkotlinx/io/Input;)Lhep/dataforge/io/Envelope;
@ -215,8 +219,8 @@ public final class hep/dataforge/io/IOPlugin : hep/dataforge/context/AbstractPlu
public final fun getIoFormatFactories ()Ljava/util/Collection;
public final fun getMetaFormatFactories ()Ljava/util/Collection;
public fun getTag ()Lhep/dataforge/context/PluginTag;
public final fun resolveEnvelopeFormat (Lhep/dataforge/meta/MetaItem;)Lhep/dataforge/io/EnvelopeFormat;
public final fun resolveIOFormat (Lhep/dataforge/meta/MetaItem;Lkotlin/reflect/KClass;)Lhep/dataforge/io/IOFormat;
public final fun resolveEnvelopeFormat (Lhep/dataforge/meta/TypedMetaItem;)Lhep/dataforge/io/EnvelopeFormat;
public final fun resolveIOFormat (Lhep/dataforge/meta/TypedMetaItem;Lkotlin/reflect/KClass;)Lhep/dataforge/io/IOFormat;
public final fun resolveMetaFormat (Ljava/lang/String;Lhep/dataforge/meta/Meta;)Lhep/dataforge/io/MetaFormat;
public final fun resolveMetaFormat (SLhep/dataforge/meta/Meta;)Lhep/dataforge/io/MetaFormat;
public static synthetic fun resolveMetaFormat$default (Lhep/dataforge/io/IOPlugin;Ljava/lang/String;Lhep/dataforge/meta/Meta;ILjava/lang/Object;)Lhep/dataforge/io/MetaFormat;

View File

@ -22,4 +22,8 @@ kotlin {
}
}
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
}

View File

@ -57,3 +57,10 @@ public final class hep/dataforge/io/yaml/YamlMetaFormat$Companion : hep/dataforg
public synthetic fun writeObject (Lkotlinx/io/Output;Ljava/lang/Object;)V
}
public final class hep/dataforge/io/yaml/YamlMetaFormatKt {
public static final fun toMeta (Lnet/mamoe/yamlkt/YamlMap;)Lhep/dataforge/meta/Meta;
public static final fun toMetaItem (Lnet/mamoe/yamlkt/YamlElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;)Lhep/dataforge/meta/TypedMetaItem;
public static synthetic fun toMetaItem$default (Lnet/mamoe/yamlkt/YamlElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun toYaml (Lhep/dataforge/meta/Meta;)Lnet/mamoe/yamlkt/YamlMap;
}

View File

@ -1,16 +1,33 @@
plugins {
id("ru.mipt.npm.jvm")
id("ru.mipt.npm.mpp")
// id("ru.mipt.npm.native")
}
description = "YAML meta IO"
kscience {
useSerialization {
yaml()
useSerialization{
yamlKt("0.9.0-dev-1")
}
}
dependencies {
api(project(":dataforge-io"))
api("org.yaml:snakeyaml:1.26")
repositories{
maven("https://dl.bintray.com/mamoe/yamlkt")
}
kotlin {
sourceSets {
commonMain{
dependencies {
api(project(":dataforge-io"))
}
}
}
}
readme{
maturity = ru.mipt.npm.gradle.Maturity.PROTOTYPE
description ="""
YAML meta converters and Front Matter envelope format
""".trimIndent()
}

View File

@ -4,8 +4,8 @@ import hep.dataforge.context.Context
import hep.dataforge.io.*
import hep.dataforge.io.IOFormat.Companion.META_KEY
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.misc.DFExperimental
import kotlinx.io.*
import kotlinx.io.text.readUtf8Line
import kotlinx.io.text.writeUtf8String
@ -17,11 +17,11 @@ public class FrontMatterEnvelopeFormat(
) : EnvelopeFormat {
override fun readPartial(input: Input): PartialEnvelope {
var line = ""
var line: String
var offset = 0u
do {
line = input.readUtf8Line() //?: error("Input does not contain front matter separator")
offset += line.toByteArray().size.toUInt()
offset += line.encodeToByteArray().size.toUInt()
} while (!line.startsWith(SEPARATOR))
val readMetaFormat =
@ -33,7 +33,7 @@ public class FrontMatterEnvelopeFormat(
do {
line = input.readUtf8Line()
writeUtf8String(line + "\r\n")
offset += line.toByteArray().size.toUInt()
offset += line.encodeToByteArray().size.toUInt()
} while (!line.startsWith(SEPARATOR))
}.read {
readMetaFormat.readMeta(input)
@ -43,7 +43,7 @@ public class FrontMatterEnvelopeFormat(
}
override fun readObject(input: Input): Envelope {
var line = ""
var line: String
do {
line = input.readUtf8Line() //?: error("Input does not contain front matter separator")
} while (!line.startsWith(SEPARATOR))
@ -86,7 +86,7 @@ public class FrontMatterEnvelopeFormat(
}
public companion object : EnvelopeFormatFactory {
public const val SEPARATOR = "---"
public const val SEPARATOR: String = "---"
private val metaTypeRegex = "---(\\w*)\\s*".toRegex()

View File

@ -0,0 +1,122 @@
package hep.dataforge.io.yaml
import hep.dataforge.context.Context
import hep.dataforge.io.IOFormat.Companion.META_KEY
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
import hep.dataforge.io.MetaFormat
import hep.dataforge.io.MetaFormatFactory
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.ItemDescriptor
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.misc.DFExperimental
import hep.dataforge.names.NameToken
import hep.dataforge.names.withIndex
import hep.dataforge.values.ListValue
import hep.dataforge.values.Null
import hep.dataforge.values.parseValue
import kotlinx.io.Input
import kotlinx.io.Output
import kotlinx.io.text.readUtf8String
import kotlinx.io.text.writeUtf8String
import net.mamoe.yamlkt.*
public fun Meta.toYaml(): YamlMap {
val map: Map<String, Any?> = items.entries.associate { (key, item) ->
key.toString() to when (item) {
is MetaItemValue -> {
item.value.value
}
is MetaItemNode -> {
item.node.toYaml()
}
}
}
return YamlMap(map)
}
private class YamlMeta(private val yamlMap: YamlMap, private val descriptor: NodeDescriptor? = null) : MetaBase() {
private fun buildItems(): Map<NameToken, MetaItem> {
val map = LinkedHashMap<NameToken, MetaItem>()
yamlMap.content.entries.forEach { (key, value) ->
val stringKey = key.toString()
val itemDescriptor = descriptor?.items?.get(stringKey)
val token = NameToken(stringKey)
when (value) {
YamlNull -> Null.asMetaItem()
is YamlLiteral -> map[token] = value.content.parseValue().asMetaItem()
is YamlMap -> map[token] = value.toMeta().asMetaItem()
is YamlList -> if (value.all { it is YamlLiteral }) {
val listValue = ListValue(
value.map {
//We already checked that all values are primitives
(it as YamlLiteral).content.parseValue()
}
)
map[token] = MetaItemValue(listValue)
} else value.forEachIndexed { index, yamlElement ->
val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: ItemDescriptor.DEFAULT_INDEX_KEY
val indexValue: String = (yamlElement as? YamlMap)?.getStringOrNull(indexKey)
?: index.toString() //In case index is non-string, the backward transformation will be broken.
val tokenWithIndex = token.withIndex(indexValue)
map[tokenWithIndex] = yamlElement.toMetaItem(itemDescriptor)
}
}
}
return map
}
override val items: Map<NameToken, MetaItem> get() = buildItems()
}
public fun YamlElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem = when (this) {
YamlNull -> Null.asMetaItem()
is YamlLiteral -> content.parseValue().asMetaItem()
is YamlMap -> toMeta().asMetaItem()
//We can't return multiple items therefore we create top level node
is YamlList -> YamlMap(mapOf("@yamlArray" to this)).toMetaItem(descriptor)
}
public fun YamlMap.toMeta(): Meta = YamlMeta(this)
/**
* Represent meta as Yaml
*/
@DFExperimental
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
val yaml = meta.toYaml()
val string = Yaml.encodeToString(yaml)
output.writeUtf8String(string)
}
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
val yaml = Yaml.decodeYamlMapFromString(input.readUtf8String())
return yaml.toMeta()
}
override fun toMeta(): Meta = Meta {
NAME_KEY put FrontMatterEnvelopeFormat.name.toString()
META_KEY put meta
}
public companion object : MetaFormatFactory {
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
override val shortName: String = "yaml"
override val key: Short = 0x594d //YM
private val default = YamlMetaFormat()
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
default.writeMeta(output, meta, descriptor)
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta =
default.readMeta(input, descriptor)
}
}

View File

@ -2,10 +2,10 @@ package hep.dataforge.io.yaml
import hep.dataforge.io.parse
import hep.dataforge.io.toString
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.meta.get
import hep.dataforge.meta.seal
import hep.dataforge.misc.DFExperimental
import kotlin.test.Test
import kotlin.test.assertEquals

View File

@ -1,56 +0,0 @@
package hep.dataforge.io.yaml
import hep.dataforge.context.Context
import hep.dataforge.io.IOFormat.Companion.META_KEY
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
import hep.dataforge.io.MetaFormat
import hep.dataforge.io.MetaFormatFactory
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.toMap
import hep.dataforge.meta.toMeta
import kotlinx.io.Input
import kotlinx.io.Output
import kotlinx.io.asInputStream
import kotlinx.io.text.writeUtf8String
import org.yaml.snakeyaml.Yaml
/**
* Represent meta as Yaml
*/
@DFExperimental
public class YamlMetaFormat(private val meta: Meta) : MetaFormat {
private val yaml = Yaml()
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
val string = yaml.dump(meta.toMap(descriptor))
output.writeUtf8String(string)
}
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
val map: Map<String, Any?> = yaml.load(input.asInputStream())
return map.toMeta(descriptor)
}
override fun toMeta(): Meta = Meta{
NAME_KEY put FrontMatterEnvelopeFormat.name.toString()
META_KEY put meta
}
public companion object : MetaFormatFactory {
override fun invoke(meta: Meta, context: Context): MetaFormat = YamlMetaFormat(meta)
override val shortName: String = "yaml"
override val key: Short = 0x594d //YM
private val default = YamlMetaFormat()
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?): Unit =
default.writeMeta(output, meta, descriptor)
override fun readMeta(input: kotlinx.io.Input, descriptor: NodeDescriptor?): Meta =
default.readMeta(input, descriptor)
}
}

View File

@ -1,11 +1,8 @@
package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaBuilder
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.*
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.setItem
import hep.dataforge.values.*
import kotlinx.io.*
import kotlinx.io.text.readUtf8String
@ -22,7 +19,7 @@ public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
override fun invoke(meta: Meta, context: Context): MetaFormat = this
override fun readMeta(input: Input, descriptor: NodeDescriptor?): Meta {
return (input.readMetaItem() as MetaItem.NodeItem).node
return (input.readMetaItem() as MetaItemNode).node
}
private fun Output.writeChar(char: Char) = writeByte(char.toByte())
@ -32,67 +29,66 @@ public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
writeUtf8String(str)
}
public fun Output.writeValue(value: Value) {
if (value.isList()) {
public fun Output.writeValue(value: Value): Unit = when (value.type) {
ValueType.NUMBER -> when (value.value) {
is Short -> {
writeChar('s')
writeShort(value.short)
}
is Int -> {
writeChar('i')
writeInt(value.int)
}
is Long -> {
writeChar('l')
writeLong(value.long)
}
is Float -> {
writeChar('f')
writeFloat(value.float)
}
else -> {
writeChar('d')
writeDouble(value.double)
}
}
ValueType.STRING -> {
writeChar('S')
writeString(value.string)
}
ValueType.BOOLEAN -> {
if (value.boolean) {
writeChar('+')
} else {
writeChar('-')
}
}
ValueType.NULL -> {
writeChar('N')
}
ValueType.LIST -> {
writeChar('L')
writeInt(value.list.size)
value.list.forEach {
writeValue(it)
}
} else when (value.type) {
ValueType.NUMBER -> when (value.value) {
is Short -> {
writeChar('s')
writeShort(value.number.toShort())
}
is Int -> {
writeChar('i')
writeInt(value.number.toInt())
}
is Long -> {
writeChar('l')
writeLong(value.number.toLong())
}
is Float -> {
writeChar('f')
writeFloat(value.number.toFloat())
}
else -> {
writeChar('d')
writeDouble(value.number.toDouble())
}
}
ValueType.STRING -> {
writeChar('S')
writeString(value.string)
}
ValueType.BOOLEAN -> {
if (value.boolean) {
writeChar('+')
} else {
writeChar('-')
}
}
ValueType.NULL -> {
writeChar('N')
}
}
}
override fun writeMeta(
output: kotlinx.io.Output,
meta: hep.dataforge.meta.Meta,
descriptor: hep.dataforge.meta.descriptors.NodeDescriptor?
descriptor: hep.dataforge.meta.descriptors.NodeDescriptor?,
) {
output.writeChar('M')
output.writeInt(meta.items.size)
meta.items.forEach { (key, item) ->
output.writeString(key.toString())
when (item) {
is MetaItem.ValueItem -> {
is MetaItemValue -> {
output.writeValue(item.value)
}
is MetaItem.NodeItem -> {
is MetaItemNode -> {
writeObject(output, item.node)
}
}
@ -105,21 +101,21 @@ public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
}
@Suppress("UNCHECKED_CAST")
public fun Input.readMetaItem(): MetaItem<MetaBuilder> {
public fun Input.readMetaItem(): TypedMetaItem<MetaBuilder> {
return when (val keyChar = readByte().toChar()) {
'S' -> MetaItem.ValueItem(StringValue(readString()))
'N' -> MetaItem.ValueItem(Null)
'+' -> MetaItem.ValueItem(True)
'-' -> MetaItem.ValueItem(True)
's' -> MetaItem.ValueItem(NumberValue(readShort()))
'i' -> MetaItem.ValueItem(NumberValue(readInt()))
'l' -> MetaItem.ValueItem(NumberValue(readInt()))
'f' -> MetaItem.ValueItem(NumberValue(readFloat()))
'd' -> MetaItem.ValueItem(NumberValue(readDouble()))
'S' -> MetaItemValue(StringValue(readString()))
'N' -> MetaItemValue(Null)
'+' -> MetaItemValue(True)
'-' -> MetaItemValue(True)
's' -> MetaItemValue(NumberValue(readShort()))
'i' -> MetaItemValue(NumberValue(readInt()))
'l' -> MetaItemValue(NumberValue(readInt()))
'f' -> MetaItemValue(NumberValue(readFloat()))
'd' -> MetaItemValue(NumberValue(readDouble()))
'L' -> {
val length = readInt()
val list = (1..length).map { (readMetaItem() as MetaItem.ValueItem).value }
MetaItem.ValueItem(Value.of(list))
val list = (1..length).map { (readMetaItem() as MetaItemValue).value }
MetaItemValue(Value.of(list))
}
'M' -> {
val length = readInt()
@ -127,10 +123,10 @@ public object BinaryMetaFormat : MetaFormat, MetaFormatFactory {
(1..length).forEach { _ ->
val name = readString()
val item = readMetaItem()
setItem(name, item)
set(name, item)
}
}
MetaItem.NodeItem(meta)
MetaItemNode(meta)
}
else -> error("Unknown serialization key character: $keyChar")
}

View File

@ -1,6 +1,6 @@
package hep.dataforge.io
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
/**
* A fire-and-forget consumer of messages

View File

@ -29,6 +29,7 @@ public interface Envelope {
/**
* Build a static envelope using provided builder
*/
@Deprecated("Use top level function instead")
public inline operator fun invoke(block: EnvelopeBuilder.() -> Unit): Envelope =
EnvelopeBuilder().apply(block).seal()
}

View File

@ -44,6 +44,12 @@ public class EnvelopeBuilder : Envelope {
}
/**
* Build a static envelope using provided [builder]
*/
public inline fun Envelope(builder: EnvelopeBuilder.() -> Unit): Envelope = EnvelopeBuilder().apply(builder).seal()
//@ExperimentalContracts
//suspend fun EnvelopeBuilder.buildData(block: suspend Output.() -> Unit): Binary{
// contract {

View File

@ -3,12 +3,13 @@ package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.io.EnvelopeFormatFactory.Companion.ENVELOPE_FORMAT_TYPE
import hep.dataforge.meta.Meta
import hep.dataforge.misc.Type
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.provider.Type
import kotlinx.io.Input
import kotlinx.io.Output
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A partially read envelope with meta, but without data
@ -16,6 +17,8 @@ import kotlin.reflect.KClass
public data class PartialEnvelope(val meta: Meta, val dataOffset: UInt, val dataSize: ULong?)
public interface EnvelopeFormat : IOFormat<Envelope> {
override val type: KType get() = typeOf<Envelope>()
public val defaultMetaFormat: MetaFormatFactory get() = JsonMetaFormat
public fun readPartial(input: Input): PartialEnvelope
@ -37,7 +40,7 @@ public fun EnvelopeFormat.read(input: Input): Envelope = readObject(input)
@Type(ENVELOPE_FORMAT_TYPE)
public interface EnvelopeFormatFactory : IOFormatFactory<Envelope>, EnvelopeFormat {
override val name: Name get() = "envelope".asName()
override val type: KClass<out Envelope> get() = Envelope::class
override val type: KType get() = typeOf<Envelope>()
override fun invoke(meta: Meta, context: Context): EnvelopeFormat

View File

@ -10,13 +10,14 @@ import hep.dataforge.io.PartDescriptor.Companion.SEPARATOR_KEY
import hep.dataforge.meta.*
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.names.toName
import kotlinx.io.Binary
import kotlinx.io.writeBinary
private class PartDescriptor : Scheme() {
var offset by int(0)
var size by int(0)
var meta by node()
var partMeta by node("meta".toName())
companion object : SchemeSpec<PartDescriptor>(::PartDescriptor) {
val MULTIPART_KEY = ENVELOPE_NODE_KEY + "multipart"
@ -48,7 +49,7 @@ public fun EnvelopeBuilder.multipart(
PartDescriptor {
offset = offsetCounter
size = binary.size
meta = description
partMeta = description
}.also {
offsetCounter += binary.size
}
@ -95,7 +96,7 @@ public fun Envelope.parts(): EnvelopeParts {
} else {
parts.map {
val binary = data!!.view(it.offset, it.size)
val meta = Laminate(it.meta, meta[MULTIPART_KEY].node)
val meta = Laminate(it.partMeta, meta[MULTIPART_KEY].node)
EnvelopePart(binary, meta)
}
}

View File

@ -2,25 +2,28 @@ package hep.dataforge.io
import hep.dataforge.context.Context
import hep.dataforge.context.Factory
import hep.dataforge.context.Named
import hep.dataforge.io.IOFormat.Companion.NAME_KEY
import hep.dataforge.io.IOFormatFactory.Companion.IO_FORMAT_TYPE
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MetaItemValue
import hep.dataforge.meta.MetaRepr
import hep.dataforge.misc.Named
import hep.dataforge.misc.Type
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.provider.Type
import hep.dataforge.values.Value
import kotlinx.io.*
import kotlinx.io.buffer.Buffer
import kotlinx.io.pool.ObjectPool
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* And interface for reading and writing objects into with IO streams
*/
public interface IOFormat<T : Any> : MetaRepr {
public val type: KType
public fun writeObject(output: Output, obj: T)
public fun readObject(input: Input): T
@ -42,10 +45,14 @@ public fun <T : Any> Binary.readWith(format: IOFormat<T>): T = read {
public fun <T : Any> Output.writeWith(format: IOFormat<T>, obj: T): Unit =
format.run { writeObject(this@writeWith, obj) }
public class ListIOFormat<T : Any>(public val format: IOFormat<T>) : IOFormat<List<T>> {
public inline fun <reified T : Any> IOFormat.Companion.listOf(
format: IOFormat<T>,
): IOFormat<List<T>> = object : IOFormat<List<T>> {
override val type: KType = typeOf<List<T>>()
override fun writeObject(output: Output, obj: List<T>) {
output.writeInt(obj.size)
this.format.run {
format.run {
obj.forEach {
writeObject(output, it)
}
@ -63,9 +70,8 @@ public class ListIOFormat<T : Any>(public val format: IOFormat<T>) : IOFormat<Li
NAME_KEY put "list"
"contentFormat" put format.toMeta()
}
}
//public val <T : Any> IOFormat<T>.list: ListIOFormat<T> get() = ListIOFormat(this)
}
public fun ObjectPool<Buffer>.fill(block: Buffer.() -> Unit): Buffer {
val buffer = borrow()
@ -82,7 +88,7 @@ public interface IOFormatFactory<T : Any> : Factory<IOFormat<T>>, Named, MetaRep
/**
* Explicit type for dynamic type checks
*/
public val type: KClass<out T>
public val type: KType
override fun toMeta(): Meta = Meta {
NAME_KEY put name.toString()
@ -100,7 +106,7 @@ public object DoubleIOFormat : IOFormat<Double>, IOFormatFactory<Double> {
override val name: Name = "double".asName()
override val type: KClass<out Double> get() = Double::class
override val type: KType get() = typeOf<Double>()
override fun writeObject(output: Output, obj: kotlin.Double) {
output.writeDouble(obj)
@ -114,14 +120,14 @@ public object ValueIOFormat : IOFormat<Value>, IOFormatFactory<Value> {
override val name: Name = "value".asName()
override val type: KClass<out Value> get() = Value::class
override val type: KType get() = typeOf<Value>()
override fun writeObject(output: Output, obj: Value) {
BinaryMetaFormat.run { output.writeValue(obj) }
}
override fun readObject(input: Input): Value {
return (BinaryMetaFormat.run { input.readMetaItem() } as? MetaItem.ValueItem)?.value
return (BinaryMetaFormat.run { input.readMetaItem() } as? MetaItemValue)?.value
?: error("The item is not a value")
}
}

View File

@ -18,7 +18,7 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
context.gather<IOFormatFactory<*>>(IO_FORMAT_TYPE).values
}
public fun <T : Any> resolveIOFormat(item: MetaItem<*>, type: KClass<out T>): IOFormat<T>? {
public fun <T : Any> resolveIOFormat(item: MetaItem, type: KClass<out T>): IOFormat<T>? {
val key = item.string ?: item.node[NAME_KEY]?.string ?: error("Format name not defined")
val name = key.toName()
return ioFormatFactories.find { it.name == name }?.let {
@ -46,7 +46,7 @@ public class IOPlugin(meta: Meta) : AbstractPlugin(meta) {
private fun resolveEnvelopeFormat(name: Name, meta: Meta = Meta.EMPTY): EnvelopeFormat? =
envelopeFormatFactories.find { it.name == name }?.invoke(meta, context)
public fun resolveEnvelopeFormat(item: MetaItem<*>): EnvelopeFormat? {
public fun resolveEnvelopeFormat(item: MetaItem): EnvelopeFormat? {
val name = item.string ?: item.node[NAME_KEY]?.string ?: error("Envelope format name not defined")
val meta = item.node[META_KEY].node ?: Meta.EMPTY
return resolveEnvelopeFormat(name.toName(), meta)

View File

@ -16,12 +16,16 @@ import kotlinx.io.text.readUtf8String
import kotlinx.io.text.writeUtf8String
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A Json format for Meta representation
*/
public class JsonMetaFormat(private val json: Json = DEFAULT_JSON) : MetaFormat {
override val type: KType get() = typeOf<Meta>()
override fun writeMeta(output: Output, meta: Meta, descriptor: NodeDescriptor?) {
val jsonObject = meta.toJson(descriptor)
output.writeUtf8String(json.encodeToString(JsonObject.serializer(), jsonObject))

View File

@ -4,20 +4,22 @@ import hep.dataforge.context.Context
import hep.dataforge.io.MetaFormatFactory.Companion.META_FORMAT_TYPE
import hep.dataforge.meta.Meta
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.misc.Type
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.names.plus
import hep.dataforge.provider.Type
import kotlinx.io.ByteArrayInput
import kotlinx.io.Input
import kotlinx.io.Output
import kotlinx.io.use
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.typeOf
/**
* A format for meta serialization
*/
public interface MetaFormat : IOFormat<Meta> {
override val type: KType get() = typeOf<Meta>()
override fun writeObject(output: Output, obj: Meta) {
writeMeta(output, obj, null)
@ -40,7 +42,7 @@ public interface MetaFormatFactory : IOFormatFactory<Meta>, MetaFormat {
override val name: Name get() = "meta".asName() + shortName
override val type: KClass<out Meta> get() = Meta::class
override val type: KType get() = typeOf<Meta>()
public val key: Short get() = name.hashCode().toShort()

View File

@ -7,7 +7,7 @@ import kotlin.test.assertEquals
class EnvelopeFormatTest {
val envelope = Envelope.invoke {
val envelope = Envelope {
type = "test.format"
meta{
"d" put 22.2

View File

@ -2,6 +2,8 @@ package hep.dataforge.io
import hep.dataforge.meta.*
import hep.dataforge.meta.JsonMeta.Companion.JSON_ARRAY_KEY
import hep.dataforge.values.ListValue
import hep.dataforge.values.number
import kotlinx.io.asBinary
import kotlinx.serialization.json.*
import kotlin.test.Test
@ -78,4 +80,27 @@ class MetaFormatTest {
assertEquals(listOf(1.0, 2.0, 3.0), meta["$JSON_ARRAY_KEY[2"].value?.list?.map { it.number.toDouble() })
}
@Test
fun testJsonStringToMeta(){
val jsonString = """
{
"comments": [
],
"end_time": "2018-04-13T22:01:46",
"format_description": "https://docs.google.com/document/d/12qmnZRO55y6zr08Wf-BQYAmklqgf5y3j_gD_VkNscXc/edit?usp=sharing",
"iteration_info": {
"iteration": 4,
"reverse": false
},
"operator": "Vasiliy",
"programm_revision": "1.1.1-79-g7c0cad6",
"start_time": "2018-04-13T21:42:04",
"type": "info_file"
}
""".trimIndent()
val json = Json.parseToJsonElement(jsonString)
val meta = json.toMetaItem().node!!
assertEquals(ListValue.EMPTY, meta["comments"].value)
}
}

View File

@ -1,8 +1,8 @@
package hep.dataforge.io
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem
import hep.dataforge.meta.MetaSerializer
import hep.dataforge.meta.TypedMetaItem
import hep.dataforge.names.Name
import hep.dataforge.names.toName
import kotlinx.serialization.ExperimentalSerializationApi
@ -52,7 +52,7 @@ class MetaSerializerTest {
@OptIn(ExperimentalSerializationApi::class)
@Test
fun testMetaItemDescriptor() {
val descriptor = MetaItem.serializer(MetaSerializer).descriptor.getElementDescriptor(0)
val descriptor = TypedMetaItem.serializer(MetaSerializer).descriptor.getElementDescriptor(0)
println(descriptor)
}
}

View File

@ -1,9 +1,9 @@
package hep.dataforge.io
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.get
import hep.dataforge.meta.int
import hep.dataforge.misc.DFExperimental
import kotlinx.io.text.writeUtf8String
import kotlin.test.Test
import kotlin.test.assertEquals

View File

@ -1,14 +1,15 @@
package hep.dataforge.io
import hep.dataforge.meta.DFExperimental
import hep.dataforge.meta.Meta
import hep.dataforge.meta.descriptors.NodeDescriptor
import hep.dataforge.meta.isEmpty
import hep.dataforge.misc.DFExperimental
import kotlinx.io.*
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import kotlin.reflect.full.isSuperclassOf
import kotlin.reflect.full.isSupertypeOf
import kotlin.reflect.typeOf
import kotlin.streams.asSequence
public fun <R> Path.read(block: Input.() -> R): R = asBinary().read(block = block)
@ -59,7 +60,7 @@ public fun Path.readEnvelope(format: EnvelopeFormat): Envelope {
@Suppress("UNCHECKED_CAST")
@DFExperimental
public inline fun <reified T : Any> IOPlugin.resolveIOFormat(): IOFormat<T>? {
return ioFormatFactories.find { it.type.isSuperclassOf(T::class) } as IOFormat<T>?
return ioFormatFactories.find { it.type.isSupertypeOf(typeOf<T>())} as IOFormat<T>?
}
/**
@ -115,18 +116,18 @@ public fun IOPlugin.writeMetaFile(
* Return inferred [EnvelopeFormat] if only one format could read given file. If no format accepts file, return null. If
* multiple formats accepts file, throw an error.
*/
public fun IOPlugin.peekBinaryFormat(path: Path): EnvelopeFormat? {
public fun IOPlugin.peekFileEnvelopeFormat(path: Path): EnvelopeFormat? {
val binary = path.asBinary()
val formats = envelopeFormatFactories.mapNotNull { factory ->
binary.read {
factory.peekFormat(this@peekBinaryFormat, this@read)
factory.peekFormat(this@peekFileEnvelopeFormat, this@read)
}
}
return when (formats.size) {
0 -> null
1 -> formats.first()
else -> error("Envelope format binary recognition clash")
else -> error("Envelope format binary recognition clash: $formats")
}
}
@ -137,10 +138,10 @@ public val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
* Read and envelope from file if the file exists, return null if file does not exist.
*
* If file is directory, then expect two files inside:
* * **meta.<format name>** for meta
* * **meta.<meta format extension>** for meta
* * **data** for data
*
* If the file is envelope read it using [EnvelopeFormatFactory.peekFormat] functionality to infer format.
* If the file is envelope read it using [EnvelopeFormatFactory.peekFormat] functionality to infer format (if not overridden with [formatPicker]).
*
* If the file is not an envelope and [readNonEnvelopes] is true, return an Envelope without meta, using file as binary.
*
@ -150,9 +151,9 @@ public val IOPlugin.Companion.DATA_FILE_NAME: String get() = "@data"
public fun IOPlugin.readEnvelopeFile(
path: Path,
readNonEnvelopes: Boolean = false,
formatPeeker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekBinaryFormat,
): Envelope? {
if (!Files.exists(path)) return null
formatPicker: IOPlugin.(Path) -> EnvelopeFormat? = IOPlugin::peekFileEnvelopeFormat,
): Envelope {
if (!Files.exists(path)) error("File with path $path does not exist")
//read two-files directory
if (Files.isDirectory(path)) {
@ -177,11 +178,11 @@ public fun IOPlugin.readEnvelopeFile(
return SimpleEnvelope(meta, data)
}
return formatPeeker(path)?.let { format ->
return formatPicker(path)?.let { format ->
path.readEnvelope(format)
} ?: if (readNonEnvelopes) { // if no format accepts file, read it as binary
SimpleEnvelope(Meta.EMPTY, path.asBinary())
} else null
} else error("Can't infer format for file $path")
}
/**

View File

@ -1,7 +1,7 @@
package hep.dataforge.io
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import kotlinx.io.asBinary
import kotlinx.io.toByteArray
import kotlinx.io.writeDouble
@ -54,7 +54,7 @@ class FileBinaryTest {
val tmpPath = Files.createTempFile("dataforge_test", ".df")
Global.io.writeEnvelopeFile(tmpPath, envelope)
val binary = Global.io.readEnvelopeFile(tmpPath)?.data!!
val binary = Global.io.readEnvelopeFile(tmpPath).data!!
assertEquals(binary.size, binary.toByteArray().size)
}
}

View File

@ -1,7 +1,7 @@
package hep.dataforge.io
import hep.dataforge.context.Global
import hep.dataforge.meta.DFExperimental
import hep.dataforge.misc.DFExperimental
import kotlinx.io.writeDouble
import java.nio.file.Files
import kotlin.test.Test
@ -29,7 +29,7 @@ class FileEnvelopeTest {
val tmpPath = Files.createTempFile("dataforge_test", ".df")
writeEnvelopeFile(tmpPath, envelope)
println(tmpPath.toUri())
val restored: Envelope = readEnvelopeFile(tmpPath)!!
val restored: Envelope = readEnvelopeFile(tmpPath)
assertTrue { envelope.contentEquals(restored) }
}
}
@ -40,7 +40,7 @@ class FileEnvelopeTest {
val tmpPath = Files.createTempFile("dataforge_test_tagless", ".df")
writeEnvelopeFile(tmpPath, envelope, envelopeFormat = TaglessEnvelopeFormat)
println(tmpPath.toUri())
val restored: Envelope = readEnvelopeFile(tmpPath)!!
val restored: Envelope = readEnvelopeFile(tmpPath)
assertTrue { envelope.contentEquals(restored) }
}
}

View File

@ -1,20 +1,18 @@
public abstract class hep/dataforge/meta/AbstractMetaNode : hep/dataforge/meta/MetaBase, hep/dataforge/meta/MetaNode {
public fun <init> ()V
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public fun toMeta ()Lhep/dataforge/meta/Meta;
}
public abstract class hep/dataforge/meta/AbstractMutableMeta : hep/dataforge/meta/AbstractMetaNode, hep/dataforge/meta/MutableMeta {
public abstract class hep/dataforge/meta/AbstractMutableMeta : hep/dataforge/meta/AbstractTypedMeta, hep/dataforge/meta/MutableMeta {
public fun <init> ()V
protected final fun getChildren ()Ljava/util/Map;
public fun getItems ()Ljava/util/Map;
protected fun replaceItem (Lhep/dataforge/names/NameToken;Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/MetaItem;)V
public fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)V
protected final fun wrapItem (Lhep/dataforge/meta/MetaItem;)Lhep/dataforge/meta/MetaItem;
protected fun replaceItem (Lhep/dataforge/names/NameToken;Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/TypedMetaItem;)V
public fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)V
protected abstract fun wrapNode (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/MutableMeta;
}
public final class hep/dataforge/meta/Config : hep/dataforge/meta/AbstractMutableMeta, hep/dataforge/meta/ObservableMeta {
public abstract class hep/dataforge/meta/AbstractTypedMeta : hep/dataforge/meta/MetaBase, hep/dataforge/meta/TypedMeta {
public fun <init> ()V
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
}
public final class hep/dataforge/meta/Config : hep/dataforge/meta/AbstractMutableMeta, hep/dataforge/meta/ObservableItemProvider {
public static final field ConfigSerializer Lhep/dataforge/meta/Config$ConfigSerializer;
public fun <init> ()V
public synthetic fun empty$dataforge_meta ()Lhep/dataforge/meta/MutableMeta;
@ -35,7 +33,8 @@ public final class hep/dataforge/meta/Config$ConfigSerializer : kotlinx/serializ
public final class hep/dataforge/meta/ConfigKt {
public static final fun asConfig (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Config;
public static final fun get (Lhep/dataforge/meta/Config;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/Config;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun toConfig (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Config;
}
public abstract interface class hep/dataforge/meta/Configurable {
@ -49,19 +48,6 @@ public final class hep/dataforge/meta/ConfigurableKt {
public static final fun configure (Lhep/dataforge/meta/Configurable;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/Configurable;
}
public abstract interface annotation class hep/dataforge/meta/DFBuilder : java/lang/annotation/Annotation {
}
public abstract interface annotation class hep/dataforge/meta/DFExperimental : java/lang/annotation/Annotation {
}
public final class hep/dataforge/meta/GetIndexedKt {
public static final fun getIndexed (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/Name;)Ljava/util/Map;
public static final fun getIndexed (Lhep/dataforge/meta/Meta;Ljava/lang/String;)Ljava/util/Map;
public static final fun getIndexed (Lhep/dataforge/meta/MetaNode;Lhep/dataforge/names/Name;)Ljava/util/Map;
public static final fun getIndexed (Lhep/dataforge/meta/MetaNode;Ljava/lang/String;)Ljava/util/Map;
}
public final class hep/dataforge/meta/ItemDelegateKt {
public static final fun boolean (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadOnlyProperty;
public static final fun boolean (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadOnlyProperty;
@ -108,15 +94,41 @@ public final class hep/dataforge/meta/ItemDelegateKt {
public static synthetic fun value$default (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty;
}
public final class hep/dataforge/meta/ItemListener {
public fun <init> (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)V
public synthetic fun <init> (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Lkotlin/jvm/functions/Function3;
public final fun copy (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/meta/ItemListener;
public static synthetic fun copy$default (Lhep/dataforge/meta/ItemListener;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/meta/ItemListener;
public fun equals (Ljava/lang/Object;)Z
public final fun getAction ()Lkotlin/jvm/functions/Function3;
public final fun getOwner ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public abstract interface class hep/dataforge/meta/ItemProvider {
public static final field Companion Lhep/dataforge/meta/ItemProvider$Companion;
public abstract fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public abstract fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
}
public final class hep/dataforge/meta/ItemProvider$Companion {
public final fun getEMPTY ()Lhep/dataforge/meta/ItemProvider;
}
public final class hep/dataforge/meta/ItemProviderKt {
public static final fun get (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun get (Lhep/dataforge/meta/ItemProvider;Ljava/lang/String;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun getChild (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/ItemProvider;
public static final fun getChild (Lhep/dataforge/meta/ItemProvider;Ljava/lang/String;)Lhep/dataforge/meta/ItemProvider;
public static final fun getIndexed (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/names/Name;)Ljava/util/Map;
public static final fun getIndexed (Lhep/dataforge/meta/ItemProvider;Ljava/lang/String;)Ljava/util/Map;
public static final fun getRootItem (Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun getRootNode (Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/Meta;
public static final fun withDefault (Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/ItemProvider;
}
public final class hep/dataforge/meta/JsonMeta : hep/dataforge/meta/MetaBase {
public static final field Companion Lhep/dataforge/meta/JsonMeta$Companion;
public static final field JSON_ARRAY_KEY Ljava/lang/String;
@ -135,8 +147,8 @@ public final class hep/dataforge/meta/JsonMetaKt {
public static synthetic fun toJson$default (Lhep/dataforge/values/Value;Lhep/dataforge/meta/descriptors/ValueDescriptor;ILjava/lang/Object;)Lkotlinx/serialization/json/JsonElement;
public static final fun toMeta (Lkotlinx/serialization/json/JsonObject;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/JsonMeta;
public static synthetic fun toMeta$default (Lkotlinx/serialization/json/JsonObject;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/JsonMeta;
public static final fun toMetaItem (Lkotlinx/serialization/json/JsonElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;)Lhep/dataforge/meta/MetaItem;
public static synthetic fun toMetaItem$default (Lkotlinx/serialization/json/JsonElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/MetaItem;
public static final fun toMetaItem (Lkotlinx/serialization/json/JsonElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;)Lhep/dataforge/meta/TypedMetaItem;
public static synthetic fun toMetaItem$default (Lkotlinx/serialization/json/JsonElement;Lhep/dataforge/meta/descriptors/ItemDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun toValue (Lkotlinx/serialization/json/JsonPrimitive;Lhep/dataforge/meta/descriptors/ValueDescriptor;)Lhep/dataforge/values/Value;
}
@ -155,7 +167,7 @@ public final class hep/dataforge/meta/Laminate$Companion {
public final class hep/dataforge/meta/LaminateKt {
public static final fun Laminate ([Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Laminate;
public static final fun getFirst (Lhep/dataforge/meta/Laminate;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static final fun getFirst (Lhep/dataforge/meta/Laminate;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun withBottom (Lhep/dataforge/meta/Laminate;Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Laminate;
public static final fun withTop (Lhep/dataforge/meta/Laminate;Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Laminate;
}
@ -172,7 +184,7 @@ public abstract interface class hep/dataforge/meta/Meta : hep/dataforge/meta/Ite
public static final field TYPE Ljava/lang/String;
public static final field VALUE_KEY Ljava/lang/String;
public abstract fun equals (Ljava/lang/Object;)Z
public abstract fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public abstract fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public abstract fun getItems ()Ljava/util/Map;
public abstract fun hashCode ()I
public abstract fun toMeta ()Lhep/dataforge/meta/Meta;
@ -186,14 +198,14 @@ public final class hep/dataforge/meta/Meta$Companion {
}
public final class hep/dataforge/meta/Meta$DefaultImpls {
public static fun getItem (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static fun getItem (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static fun toMeta (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Meta;
}
public abstract class hep/dataforge/meta/MetaBase : hep/dataforge/meta/Meta {
public fun <init> ()V
public fun equals (Ljava/lang/Object;)Z
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public fun hashCode ()I
public fun toMeta ()Lhep/dataforge/meta/Meta;
public fun toString ()Ljava/lang/String;
@ -211,8 +223,8 @@ public final class hep/dataforge/meta/MetaBuilder : hep/dataforge/meta/AbstractM
public final fun put (Lhep/dataforge/names/Name;Ljava/lang/String;)V
public final fun put (Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)V
public final fun put (Ljava/lang/String;Lhep/dataforge/meta/Meta;)V
public final fun put (Ljava/lang/String;Lhep/dataforge/meta/MetaItem;)V
public final fun put (Ljava/lang/String;Lhep/dataforge/meta/MetaRepr;)V
public final fun put (Ljava/lang/String;Lhep/dataforge/meta/TypedMetaItem;)V
public final fun put (Ljava/lang/String;Lhep/dataforge/values/Value;)V
public final fun put (Ljava/lang/String;Ljava/lang/Boolean;)V
public final fun put (Ljava/lang/String;Ljava/lang/Enum;)V
@ -231,23 +243,27 @@ public final class hep/dataforge/meta/MetaBuilder : hep/dataforge/meta/AbstractM
public final class hep/dataforge/meta/MetaBuilderKt {
public static final fun Meta (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MetaBuilder;
public static final fun builder (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/MetaBuilder;
public static final fun edit (Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MetaBuilder;
public static final fun toMutableMeta (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/MetaBuilder;
}
public abstract class hep/dataforge/meta/MetaItem {
public static final field Companion Lhep/dataforge/meta/MetaItem$Companion;
public abstract fun equals (Ljava/lang/Object;)Z
public abstract fun hashCode ()I
public final class hep/dataforge/meta/MetaItemKt {
public static final fun asMetaItem (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/MetaItemNode;
public static final fun asMetaItem (Lhep/dataforge/values/Value;)Lhep/dataforge/meta/MetaItemValue;
public static final fun getBoolean (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Boolean;
public static final fun getDouble (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Double;
public static final fun getFloat (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Float;
public static final fun getInt (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Integer;
public static final fun getLong (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Long;
public static final fun getNode (Lhep/dataforge/meta/TypedMetaItem;)Lhep/dataforge/meta/Meta;
public static final fun getNumber (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Number;
public static final fun getShort (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Short;
public static final fun getString (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/String;
public static final fun getStringList (Lhep/dataforge/meta/TypedMetaItem;)Ljava/util/List;
public static final fun getValue (Lhep/dataforge/meta/TypedMetaItem;)Lhep/dataforge/values/Value;
}
public final class hep/dataforge/meta/MetaItem$Companion {
public final fun of (Ljava/lang/Object;)Lhep/dataforge/meta/MetaItem;
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
}
public final class hep/dataforge/meta/MetaItem$NodeItem : hep/dataforge/meta/MetaItem {
public static final field Companion Lhep/dataforge/meta/MetaItem$NodeItem$Companion;
public final class hep/dataforge/meta/MetaItemNode : hep/dataforge/meta/TypedMetaItem {
public static final field Companion Lhep/dataforge/meta/MetaItemNode$Companion;
public fun <init> (Lhep/dataforge/meta/Meta;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getNode ()Lhep/dataforge/meta/Meta;
@ -255,12 +271,21 @@ public final class hep/dataforge/meta/MetaItem$NodeItem : hep/dataforge/meta/Met
public fun toString ()Ljava/lang/String;
}
public final class hep/dataforge/meta/MetaItem$NodeItem$Companion {
public final class hep/dataforge/meta/MetaItemNode$Companion {
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
}
public final class hep/dataforge/meta/MetaItem$ValueItem : hep/dataforge/meta/MetaItem {
public static final field Companion Lhep/dataforge/meta/MetaItem$ValueItem$Companion;
public final class hep/dataforge/meta/MetaItemSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lhep/dataforge/meta/MetaItemSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lhep/dataforge/meta/TypedMetaItem;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lhep/dataforge/meta/TypedMetaItem;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
}
public final class hep/dataforge/meta/MetaItemValue : hep/dataforge/meta/TypedMetaItem {
public static final field Companion Lhep/dataforge/meta/MetaItemValue$Companion;
public fun <init> (Lhep/dataforge/values/Value;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getValue ()Lhep/dataforge/values/Value;
@ -268,68 +293,16 @@ public final class hep/dataforge/meta/MetaItem$ValueItem : hep/dataforge/meta/Me
public fun toString ()Ljava/lang/String;
}
public final class hep/dataforge/meta/MetaItem$ValueItem$Companion {
public final class hep/dataforge/meta/MetaItemValue$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
public final class hep/dataforge/meta/MetaItemSerializer : kotlinx/serialization/KSerializer {
public static final field INSTANCE Lhep/dataforge/meta/MetaItemSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lhep/dataforge/meta/MetaItem;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lhep/dataforge/meta/MetaItem;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
}
public final class hep/dataforge/meta/MetaKt {
public static final fun asMetaItem (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/MetaItem$NodeItem;
public static final fun asMetaItem (Lhep/dataforge/values/Value;)Lhep/dataforge/meta/MetaItem$ValueItem;
public static final fun get (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/Meta;Ljava/lang/String;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/MetaNode;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/MetaNode;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/MetaItem;
public static final fun get (Lhep/dataforge/meta/MetaNode;Ljava/lang/String;)Lhep/dataforge/meta/MetaItem;
public static final fun getBoolean (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Boolean;
public static final fun getDouble (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Double;
public static final fun getFloat (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Float;
public static final fun getInt (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Integer;
public static final fun getLong (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Long;
public static final fun getNode (Lhep/dataforge/meta/MetaItem;)Lhep/dataforge/meta/Meta;
public static final fun getNumber (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Number;
public static final fun getShort (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Short;
public static final fun getString (Lhep/dataforge/meta/MetaItem;)Ljava/lang/String;
public static final fun getStringList (Lhep/dataforge/meta/MetaItem;)Ljava/util/List;
public static final fun getValue (Lhep/dataforge/meta/MetaItem;)Lhep/dataforge/values/Value;
public static final fun get (Lhep/dataforge/meta/Meta;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun isEmpty (Lhep/dataforge/meta/Meta;)Z
public static final fun itemSequence (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public static final fun iterator (Lhep/dataforge/meta/Meta;)Ljava/util/Iterator;
public static final fun seal (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/SealedMeta;
public static final fun seal (Lhep/dataforge/meta/MetaItem;)Lhep/dataforge/meta/MetaItem;
public static final fun sequence (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public static final fun values (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
}
public final class hep/dataforge/meta/MetaListener {
public fun <init> (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)V
public synthetic fun <init> (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Lkotlin/jvm/functions/Function3;
public final fun copy (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)Lhep/dataforge/meta/MetaListener;
public static synthetic fun copy$default (Lhep/dataforge/meta/MetaListener;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;ILjava/lang/Object;)Lhep/dataforge/meta/MetaListener;
public fun equals (Ljava/lang/Object;)Z
public final fun getAction ()Lkotlin/jvm/functions/Function3;
public final fun getOwner ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public abstract interface class hep/dataforge/meta/MetaNode : hep/dataforge/meta/Meta {
public abstract fun getItems ()Ljava/util/Map;
}
public final class hep/dataforge/meta/MetaNode$DefaultImpls {
public static fun getItem (Lhep/dataforge/meta/MetaNode;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static fun toMeta (Lhep/dataforge/meta/MetaNode;)Lhep/dataforge/meta/Meta;
public static final fun valueSequence (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
}
public abstract interface class hep/dataforge/meta/MetaRepr {
@ -345,18 +318,6 @@ public final class hep/dataforge/meta/MetaSerializer : kotlinx/serialization/KSe
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
}
public final class hep/dataforge/meta/MetaWithDefault : hep/dataforge/meta/MetaBase {
public fun <init> (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)V
public final fun getDefault ()Lhep/dataforge/meta/ItemProvider;
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public fun getItems ()Ljava/util/Map;
public final fun getMeta ()Lhep/dataforge/meta/Meta;
}
public final class hep/dataforge/meta/MetaWithDefaultKt {
public static final fun withDefault (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MetaWithDefault;
}
public final class hep/dataforge/meta/MutableItemDelegateKt {
public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun boolean (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;
@ -389,6 +350,8 @@ public final class hep/dataforge/meta/MutableItemDelegateKt {
public static final fun long (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun long$default (Lhep/dataforge/meta/MutableItemProvider;JLhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun long$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun node (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun node$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function0;)Lkotlin/properties/ReadWriteProperty;
public static final fun number (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/Number;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
@ -414,18 +377,23 @@ public final class hep/dataforge/meta/MutableItemDelegateKt {
}
public abstract interface class hep/dataforge/meta/MutableItemProvider : hep/dataforge/meta/ItemProvider {
public abstract fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)V
public abstract fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)V
}
public final class hep/dataforge/meta/MutableItemProviderKt {
public static final fun getItem (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;)Lhep/dataforge/meta/MetaItem;
public static final fun node (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun node$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun editChild (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun getChild (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun getChild (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun remove (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;)V
public static final fun remove (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lhep/dataforge/values/Value;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Iterable;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Object;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/NameToken;Ljava/lang/Object;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Lhep/dataforge/meta/Meta;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Lhep/dataforge/meta/TypedMetaItem;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Ljava/lang/Iterable;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun set (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V
@ -433,108 +401,126 @@ public final class hep/dataforge/meta/MutableItemProviderKt {
public static synthetic fun setIndexed$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
public static final fun setIndexedItems (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)V
public static synthetic fun setIndexedItems$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)V
public static final fun setItem (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Lhep/dataforge/meta/MetaItem;)V
public static final fun setNode (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lhep/dataforge/meta/Meta;)V
public static final fun setNode (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Lhep/dataforge/meta/Meta;)V
public static final fun setValue (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Lhep/dataforge/values/Value;)V
public static final fun setValue (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Lhep/dataforge/values/Value;)V
public static final fun update (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Meta;)V
public static final fun withDefault (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
}
public abstract interface class hep/dataforge/meta/MutableMeta : hep/dataforge/meta/MetaNode, hep/dataforge/meta/MutableItemProvider {
public abstract interface class hep/dataforge/meta/MutableMeta : hep/dataforge/meta/MutableItemProvider, hep/dataforge/meta/TypedMeta {
public abstract fun getItems ()Ljava/util/Map;
}
public final class hep/dataforge/meta/MutableMeta$DefaultImpls {
public static fun getItem (Lhep/dataforge/meta/MutableMeta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static fun getItem (Lhep/dataforge/meta/MutableMeta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static fun toMeta (Lhep/dataforge/meta/MutableMeta;)Lhep/dataforge/meta/Meta;
}
public final class hep/dataforge/meta/MutableMetaKt {
public static final fun append (Lhep/dataforge/meta/MutableMeta;Lhep/dataforge/names/Name;Ljava/lang/Object;)V
public static final fun append (Lhep/dataforge/meta/MutableMeta;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun append (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/names/Name;Ljava/lang/Object;)V
public static final fun append (Lhep/dataforge/meta/MutableItemProvider;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun edit (Lhep/dataforge/meta/AbstractMutableMeta;Lhep/dataforge/names/Name;Lkotlin/jvm/functions/Function1;)V
public static final fun update (Lhep/dataforge/meta/MutableMeta;Lhep/dataforge/meta/Meta;)V
}
public abstract interface class hep/dataforge/meta/ObservableMeta : hep/dataforge/meta/Meta {
public abstract interface class hep/dataforge/meta/ObservableItemProvider : hep/dataforge/meta/ItemProvider {
public abstract fun onChange (Ljava/lang/Object;Lkotlin/jvm/functions/Function3;)V
public abstract fun removeListener (Ljava/lang/Object;)V
}
public final class hep/dataforge/meta/ObservableMeta$DefaultImpls {
public static fun getItem (Lhep/dataforge/meta/ObservableMeta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public static fun toMeta (Lhep/dataforge/meta/ObservableMeta;)Lhep/dataforge/meta/Meta;
public abstract interface class hep/dataforge/meta/ReadOnlySpecification {
public abstract fun empty ()Lhep/dataforge/meta/ItemProvider;
public abstract fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/ItemProvider;
public abstract fun read (Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/ItemProvider;
}
public class hep/dataforge/meta/Scheme : hep/dataforge/meta/Configurable, hep/dataforge/meta/MetaRepr, hep/dataforge/meta/MutableItemProvider, hep/dataforge/meta/descriptors/Described {
public final class hep/dataforge/meta/ReadOnlySpecification$DefaultImpls {
public static fun invoke (Lhep/dataforge/meta/ReadOnlySpecification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/ItemProvider;
}
public class hep/dataforge/meta/Scheme : hep/dataforge/meta/MetaRepr, hep/dataforge/meta/MutableItemProvider, hep/dataforge/meta/descriptors/Described {
public fun <init> ()V
public fun <init> (Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
public synthetic fun <init> (Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getConfig ()Lhep/dataforge/meta/Config;
public final fun getDefaultItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public fun getDefaultLayer ()Lhep/dataforge/meta/Meta;
public synthetic fun getDescriptor ()Lhep/dataforge/meta/descriptors/ItemDescriptor;
public fun getDescriptor ()Lhep/dataforge/meta/descriptors/NodeDescriptor;
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/MetaItem;
public final fun isEmpty ()Z
public fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)V
public final fun getDescriptor ()Lhep/dataforge/meta/descriptors/NodeDescriptor;
public fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public final fun setDescriptor (Lhep/dataforge/meta/descriptors/NodeDescriptor;)V
public fun setItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)V
public fun toMeta ()Lhep/dataforge/meta/Laminate;
public synthetic fun toMeta ()Lhep/dataforge/meta/Meta;
public final fun validateItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)Z
public fun validateItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)Z
}
public final class hep/dataforge/meta/SchemeKt {
public static final fun asScheme (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Scheme;
public static final fun invoke (Lhep/dataforge/meta/Scheme;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/Scheme;
public static final fun toScheme (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public static synthetic fun toScheme$default (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun isEmpty (Lhep/dataforge/meta/Scheme;)Z
public static final fun retarget (Lhep/dataforge/meta/Scheme;Lhep/dataforge/meta/MutableItemProvider;)Lhep/dataforge/meta/Scheme;
public static final fun wrap (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Scheme;
public static synthetic fun wrap$default (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;Lhep/dataforge/meta/descriptors/NodeDescriptor;ILjava/lang/Object;)Lhep/dataforge/meta/Scheme;
}
public class hep/dataforge/meta/SchemeSpec : hep/dataforge/meta/Specification, hep/dataforge/meta/descriptors/Described {
public fun <init> (Lkotlin/jvm/functions/Function0;)V
public fun <init> (Lkotlin/jvm/functions/Function3;)V
public synthetic fun empty ()Lhep/dataforge/meta/MutableItemProvider;
public synthetic fun empty ()Lhep/dataforge/meta/ItemProvider;
public fun empty ()Lhep/dataforge/meta/Scheme;
public synthetic fun getDescriptor ()Lhep/dataforge/meta/descriptors/ItemDescriptor;
public fun getDescriptor ()Lhep/dataforge/meta/descriptors/NodeDescriptor;
public synthetic fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public synthetic fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/ItemProvider;
public final fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/Scheme;
public synthetic fun read (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public fun read (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/Scheme;
public synthetic fun wrap (Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public fun wrap (Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/Scheme;
public synthetic fun read (Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/ItemProvider;
public fun read (Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/Scheme;
public synthetic fun write (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public fun write (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/Scheme;
}
public final class hep/dataforge/meta/SealedMeta : hep/dataforge/meta/AbstractMetaNode {
public final class hep/dataforge/meta/SealedMeta : hep/dataforge/meta/AbstractTypedMeta {
public fun getItems ()Ljava/util/Map;
}
public abstract interface class hep/dataforge/meta/Specification {
public abstract fun empty ()Lhep/dataforge/meta/MutableItemProvider;
public abstract fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public abstract fun read (Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public abstract fun wrap (Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public final class hep/dataforge/meta/SealedMetaKt {
public static final fun seal (Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/SealedMeta;
public static final fun seal (Lhep/dataforge/meta/TypedMetaItem;)Lhep/dataforge/meta/TypedMetaItem;
}
public abstract interface class hep/dataforge/meta/Specification : hep/dataforge/meta/ReadOnlySpecification {
public abstract fun write (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
}
public final class hep/dataforge/meta/Specification$DefaultImpls {
public static fun empty (Lhep/dataforge/meta/Specification;)Lhep/dataforge/meta/MutableItemProvider;
public static fun invoke (Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public static synthetic fun read$default (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Meta;Lhep/dataforge/meta/ItemProvider;ILjava/lang/Object;)Lhep/dataforge/meta/MutableItemProvider;
public static fun wrap (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;)Lhep/dataforge/meta/MutableItemProvider;
public static synthetic fun wrap$default (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Config;Lhep/dataforge/meta/ItemProvider;ILjava/lang/Object;)Lhep/dataforge/meta/MutableItemProvider;
public static synthetic fun write$default (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/ItemProvider;ILjava/lang/Object;)Lhep/dataforge/meta/MutableItemProvider;
}
public final class hep/dataforge/meta/SpecificationKt {
public static final fun configSpec (Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/Specification;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun configure (Lhep/dataforge/meta/MetaRepr;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MetaRepr;
public static final fun createStyle (Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/Meta;
public static final fun spec (Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/Specification;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun spec (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Scheme;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static final fun spec (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Specification;Lhep/dataforge/names/Name;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun spec$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Scheme;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static synthetic fun spec$default (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Specification;Lhep/dataforge/names/Name;ILjava/lang/Object;)Lkotlin/properties/ReadWriteProperty;
public static final fun update (Lhep/dataforge/meta/Configurable;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/Configurable;
public static final fun update (Lhep/dataforge/meta/Specification;Lhep/dataforge/meta/Meta;Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/MutableItemProvider;
public static final fun update (Lhep/dataforge/meta/Configurable;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)V
public static final fun update (Lhep/dataforge/meta/MutableItemProvider;Lhep/dataforge/meta/Specification;Lkotlin/jvm/functions/Function1;)V
public static final fun withSpec (Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/Specification;)Lhep/dataforge/meta/MutableItemProvider;
}
public abstract interface class hep/dataforge/meta/TypedMeta : hep/dataforge/meta/Meta {
public abstract fun getItem (Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public abstract fun getItems ()Ljava/util/Map;
}
public final class hep/dataforge/meta/TypedMeta$DefaultImpls {
public static fun getItem (Lhep/dataforge/meta/TypedMeta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static fun toMeta (Lhep/dataforge/meta/TypedMeta;)Lhep/dataforge/meta/Meta;
}
public abstract class hep/dataforge/meta/TypedMetaItem {
public static final field Companion Lhep/dataforge/meta/TypedMetaItem$Companion;
public abstract fun equals (Ljava/lang/Object;)Z
public abstract fun hashCode ()I
}
public final class hep/dataforge/meta/TypedMetaItem$Companion {
public final fun of (Ljava/lang/Object;)Lhep/dataforge/meta/TypedMetaItem;
public final fun serializer (Lkotlinx/serialization/KSerializer;)Lkotlinx/serialization/KSerializer;
}
public final class hep/dataforge/meta/TypedMetaKt {
public static final fun get (Lhep/dataforge/meta/TypedMeta;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun get (Lhep/dataforge/meta/TypedMeta;Lhep/dataforge/names/NameToken;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun get (Lhep/dataforge/meta/TypedMeta;Ljava/lang/String;)Lhep/dataforge/meta/TypedMetaItem;
}
public abstract interface class hep/dataforge/meta/descriptors/Described {
@ -546,14 +532,15 @@ public final class hep/dataforge/meta/descriptors/Described$Companion {
}
public final class hep/dataforge/meta/descriptors/DescriptorMetaKt {
public static final fun defaultItem (Lhep/dataforge/meta/descriptors/ItemDescriptor;)Lhep/dataforge/meta/MetaItem;
public static final fun defaultItem (Lhep/dataforge/meta/descriptors/ItemDescriptor;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun defaultMeta (Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/Laminate;
}
public abstract class hep/dataforge/meta/descriptors/ItemDescriptor {
public abstract class hep/dataforge/meta/descriptors/ItemDescriptor : hep/dataforge/meta/Configurable {
public static final field Companion Lhep/dataforge/meta/descriptors/ItemDescriptor$Companion;
public static final field DEFAULT_INDEX_KEY Ljava/lang/String;
public synthetic fun <init> (Lhep/dataforge/meta/Config;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public abstract fun copy ()Lhep/dataforge/meta/descriptors/ItemDescriptor;
public final fun getAttributes ()Lhep/dataforge/meta/Config;
public final fun getConfig ()Lhep/dataforge/meta/Config;
public final fun getIndexKey ()Ljava/lang/String;
@ -571,11 +558,12 @@ public final class hep/dataforge/meta/descriptors/ItemDescriptor$Companion {
}
public final class hep/dataforge/meta/descriptors/ItemDescriptorKt {
public static final fun NodeDescriptor (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/descriptors/NodeDescriptor;
public static final fun attributes (Lhep/dataforge/meta/descriptors/ItemDescriptor;Lkotlin/jvm/functions/Function1;)V
public static final fun get (Lhep/dataforge/meta/descriptors/ItemDescriptor;Lhep/dataforge/names/Name;)Lhep/dataforge/meta/descriptors/ItemDescriptor;
public static final fun get (Lhep/dataforge/meta/descriptors/ItemDescriptor;Ljava/lang/String;)Lhep/dataforge/meta/descriptors/ItemDescriptor;
public static final fun plus (Lhep/dataforge/meta/descriptors/NodeDescriptor;Lhep/dataforge/meta/descriptors/NodeDescriptor;)Lhep/dataforge/meta/descriptors/NodeDescriptor;
public static final fun validateItem (Lhep/dataforge/meta/descriptors/ItemDescriptor;Lhep/dataforge/meta/MetaItem;)Z
public static final fun validateItem (Lhep/dataforge/meta/descriptors/ItemDescriptor;Lhep/dataforge/meta/TypedMetaItem;)Z
}
public final class hep/dataforge/meta/descriptors/NodeDescriptor : hep/dataforge/meta/descriptors/ItemDescriptor {
@ -583,6 +571,8 @@ public final class hep/dataforge/meta/descriptors/NodeDescriptor : hep/dataforge
public fun <init> ()V
public fun <init> (Lhep/dataforge/meta/Config;)V
public synthetic fun <init> (Lhep/dataforge/meta/Config;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun copy ()Lhep/dataforge/meta/descriptors/ItemDescriptor;
public fun copy ()Lhep/dataforge/meta/descriptors/NodeDescriptor;
public final fun getDefault ()Lhep/dataforge/meta/Config;
public final fun getItems ()Ljava/util/Map;
public final fun getNodes ()Ljava/util/Map;
@ -599,7 +589,6 @@ public final class hep/dataforge/meta/descriptors/NodeDescriptor : hep/dataforge
}
public final class hep/dataforge/meta/descriptors/NodeDescriptor$Companion {
public final fun invoke (Lkotlin/jvm/functions/Function1;)Lhep/dataforge/meta/descriptors/NodeDescriptor;
}
public final class hep/dataforge/meta/descriptors/ValueDescriptor : hep/dataforge/meta/descriptors/ItemDescriptor {
@ -607,6 +596,8 @@ public final class hep/dataforge/meta/descriptors/ValueDescriptor : hep/dataforg
public fun <init> (Lhep/dataforge/meta/Config;)V
public synthetic fun <init> (Lhep/dataforge/meta/Config;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun allow ([Ljava/lang/Object;)V
public synthetic fun copy ()Lhep/dataforge/meta/descriptors/ItemDescriptor;
public fun copy ()Lhep/dataforge/meta/descriptors/ValueDescriptor;
public final fun default (Ljava/lang/Object;)V
public final fun getAllowedValues ()Ljava/util/List;
public final fun getDefault ()Lhep/dataforge/values/Value;
@ -628,16 +619,16 @@ public final class hep/dataforge/meta/transformations/KeepTransformationRule : h
public fun equals (Ljava/lang/Object;)Z
public final fun getSelector ()Lkotlin/jvm/functions/Function1;
public fun hashCode ()I
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)Z
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)Z
public fun selectItems (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/MutableMeta;)V
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/MutableMeta;)V
}
public abstract interface class hep/dataforge/meta/transformations/MetaConverter {
public static final field Companion Lhep/dataforge/meta/transformations/MetaConverter$Companion;
public abstract fun itemToObject (Lhep/dataforge/meta/MetaItem;)Ljava/lang/Object;
public abstract fun objectToMetaItem (Ljava/lang/Object;)Lhep/dataforge/meta/MetaItem;
public abstract fun itemToObject (Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Object;
public abstract fun objectToMetaItem (Ljava/lang/Object;)Lhep/dataforge/meta/TypedMetaItem;
}
public final class hep/dataforge/meta/transformations/MetaConverter$Companion {
@ -657,8 +648,8 @@ public final class hep/dataforge/meta/transformations/MetaConverter$Companion {
public final class hep/dataforge/meta/transformations/MetaConverterKt {
public static final fun metaToObject (Lhep/dataforge/meta/transformations/MetaConverter;Lhep/dataforge/meta/Meta;)Ljava/lang/Object;
public static final fun nullableItemToObject (Lhep/dataforge/meta/transformations/MetaConverter;Lhep/dataforge/meta/MetaItem;)Ljava/lang/Object;
public static final fun nullableObjectToMetaItem (Lhep/dataforge/meta/transformations/MetaConverter;Ljava/lang/Object;)Lhep/dataforge/meta/MetaItem;
public static final fun nullableItemToObject (Lhep/dataforge/meta/transformations/MetaConverter;Lhep/dataforge/meta/TypedMetaItem;)Ljava/lang/Object;
public static final fun nullableObjectToMetaItem (Lhep/dataforge/meta/transformations/MetaConverter;Ljava/lang/Object;)Lhep/dataforge/meta/TypedMetaItem;
public static final fun valueToObject (Lhep/dataforge/meta/transformations/MetaConverter;Lhep/dataforge/values/Value;)Ljava/lang/Object;
}
@ -671,7 +662,7 @@ public final class hep/dataforge/meta/transformations/MetaTransformation {
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;Lhep/dataforge/meta/Config;)Lhep/dataforge/meta/ObservableMeta;
public static final fun generate-impl (Ljava/util/Collection;Lhep/dataforge/meta/Config;)Lhep/dataforge/meta/ObservableItemProvider;
public static final fun generate-impl (Ljava/util/Collection;Lhep/dataforge/meta/Meta;)Lhep/dataforge/meta/Meta;
public final fun getTransformations ()Ljava/util/Collection;
public fun hashCode ()I
@ -682,7 +673,7 @@ public final class hep/dataforge/meta/transformations/MetaTransformation {
}
public final class hep/dataforge/meta/transformations/MetaTransformation$Companion {
public final fun make-S5KKvQA (Lkotlin/jvm/functions/Function1;)Ljava/util/Collection;
public final fun make-edBMxVg (Lkotlin/jvm/functions/Function1;)Ljava/util/Collection;
}
public final class hep/dataforge/meta/transformations/MetaTransformationBuilder {
@ -705,10 +696,10 @@ public final class hep/dataforge/meta/transformations/RegexItemTransformationRul
public final fun getFrom ()Lkotlin/text/Regex;
public final fun getTransform ()Lkotlin/jvm/functions/Function4;
public fun hashCode ()I
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)Z
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)Z
public fun selectItems (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/MutableMeta;)V
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/MutableMeta;)V
}
public final class hep/dataforge/meta/transformations/SingleItemTransformationRule : hep/dataforge/meta/transformations/TransformationRule {
@ -721,22 +712,48 @@ public final class hep/dataforge/meta/transformations/SingleItemTransformationRu
public final fun getFrom ()Lhep/dataforge/names/Name;
public final fun getTransform ()Lkotlin/jvm/functions/Function3;
public fun hashCode ()I
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)Z
public fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)Z
public fun selectItems (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public fun toString ()Ljava/lang/String;
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/MutableMeta;)V
public fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/MutableMeta;)V
}
public abstract interface class hep/dataforge/meta/transformations/TransformationRule {
public abstract fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;)Z
public abstract fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;)Z
public abstract fun selectItems (Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
public abstract fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/MetaItem;Lhep/dataforge/meta/MutableMeta;)V
public abstract fun transformItem (Lhep/dataforge/names/Name;Lhep/dataforge/meta/TypedMetaItem;Lhep/dataforge/meta/MutableMeta;)V
}
public final class hep/dataforge/meta/transformations/TransformationRule$DefaultImpls {
public static fun selectItems (Lhep/dataforge/meta/transformations/TransformationRule;Lhep/dataforge/meta/Meta;)Lkotlin/sequences/Sequence;
}
public abstract interface annotation class hep/dataforge/misc/DFBuilder : java/lang/annotation/Annotation {
}
public abstract interface annotation class hep/dataforge/misc/DFExperimental : java/lang/annotation/Annotation {
}
public abstract interface annotation class hep/dataforge/misc/DFInternal : java/lang/annotation/Annotation {
}
public abstract interface class hep/dataforge/misc/Named {
public static final field Companion Lhep/dataforge/misc/Named$Companion;
public abstract fun getName ()Lhep/dataforge/names/Name;
}
public final class hep/dataforge/misc/Named$Companion {
public final fun nameOf (Ljava/lang/Object;)Lhep/dataforge/names/Name;
}
public final class hep/dataforge/misc/NamedKt {
public static final fun isAnonymous (Lhep/dataforge/misc/Named;)Z
}
public abstract interface annotation class hep/dataforge/misc/Type : java/lang/annotation/Annotation {
public abstract fun id ()Ljava/lang/String;
}
public final class hep/dataforge/names/Name {
public static final field Companion Lhep/dataforge/names/Name$Companion;
public static final field NAME_SEPARATOR Ljava/lang/String;
@ -752,6 +769,8 @@ public final class hep/dataforge/names/Name$Companion : kotlinx/serialization/KS
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun getEMPTY ()Lhep/dataforge/names/Name;
public final fun getMATCH_ALL_TOKEN ()Lhep/dataforge/names/NameToken;
public final fun getMATCH_ANY_TOKEN ()Lhep/dataforge/names/NameToken;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lhep/dataforge/names/Name;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public final fun serializer ()Lkotlinx/serialization/KSerializer;
@ -777,6 +796,7 @@ public final class hep/dataforge/names/NameKt {
public static final fun plus (Lhep/dataforge/names/Name;Lhep/dataforge/names/NameToken;)Lhep/dataforge/names/Name;
public static final fun plus (Lhep/dataforge/names/Name;Ljava/lang/String;)Lhep/dataforge/names/Name;
public static final fun plus (Lhep/dataforge/names/NameToken;Lhep/dataforge/names/Name;)Lhep/dataforge/names/Name;
public static final fun removeHeadOrNull (Lhep/dataforge/names/Name;Lhep/dataforge/names/Name;)Lhep/dataforge/names/Name;
public static final fun set (Ljava/util/Map;Ljava/lang/String;Ljava/lang/Object;)V
public static final fun startsWith (Lhep/dataforge/names/Name;Lhep/dataforge/names/Name;)Z
public static final fun startsWith (Lhep/dataforge/names/Name;Lhep/dataforge/names/NameToken;)Z
@ -784,6 +804,12 @@ public final class hep/dataforge/names/NameKt {
public static final fun withIndex (Lhep/dataforge/names/Name;Ljava/lang/String;)Lhep/dataforge/names/Name;
}
public final class hep/dataforge/names/NameMatcherKt {
public static final fun matches (Lhep/dataforge/names/Name;Lhep/dataforge/names/Name;)Z
public static final fun matches (Lhep/dataforge/names/Name;Ljava/lang/String;)Z
public static final fun matches (Lhep/dataforge/names/NameToken;Lhep/dataforge/names/NameToken;)Z
}
public final class hep/dataforge/names/NameToken {
public static final field Companion Lhep/dataforge/names/NameToken$Companion;
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
@ -813,17 +839,15 @@ public final class hep/dataforge/names/NameTokenKt {
public static final fun withIndex (Lhep/dataforge/names/NameToken;Ljava/lang/String;)Lhep/dataforge/names/NameToken;
}
public final class hep/dataforge/values/DoubleArrayValue : hep/dataforge/values/Value {
public final class hep/dataforge/values/DoubleArrayValue : hep/dataforge/values/Value, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
public fun <init> ([D)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Double;
public synthetic fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()[D
public fun hashCode ()I
public fun iterator ()Ljava/util/Iterator;
public fun toString ()Ljava/lang/String;
}
@ -831,8 +855,6 @@ public final class hep/dataforge/values/EnumValue : hep/dataforge/values/Value {
public fun <init> (Ljava/lang/Enum;)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Enum;
public synthetic fun getValue ()Ljava/lang/Object;
@ -849,8 +871,6 @@ public final class hep/dataforge/values/False : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/False;
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
@ -861,33 +881,34 @@ public final class hep/dataforge/values/LazyParsedValue : hep/dataforge/values/V
public fun <init> (Ljava/lang/String;)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public final fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public final class hep/dataforge/values/ListValue : hep/dataforge/values/Value {
public final class hep/dataforge/values/ListValue : hep/dataforge/values/Value, java/lang/Iterable, kotlin/jvm/internal/markers/KMappedMarker {
public static final field Companion Lhep/dataforge/values/ListValue$Companion;
public fun <init> (Ljava/util/List;)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public synthetic fun getValue ()Ljava/lang/Object;
public fun getValue ()Ljava/util/List;
public fun hashCode ()I
public fun iterator ()Ljava/util/Iterator;
public fun toString ()Ljava/lang/String;
}
public final class hep/dataforge/values/ListValue$Companion {
public final fun getEMPTY ()Lhep/dataforge/values/ListValue;
}
public final class hep/dataforge/values/Null : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/Null;
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
@ -898,8 +919,7 @@ public final class hep/dataforge/values/NumberValue : hep/dataforge/values/Value
public fun <init> (Ljava/lang/Number;)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public final fun getNumber ()Ljava/lang/Number;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
@ -910,8 +930,7 @@ public final class hep/dataforge/values/StringValue : hep/dataforge/values/Value
public fun <init> (Ljava/lang/String;)V
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public final fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
@ -922,8 +941,6 @@ public final class hep/dataforge/values/True : hep/dataforge/values/Value {
public static final field INSTANCE Lhep/dataforge/values/True;
public fun equals (Ljava/lang/Object;)Z
public fun getList ()Ljava/util/List;
public fun getNumber ()Ljava/lang/Number;
public fun getString ()Ljava/lang/String;
public fun getType ()Lhep/dataforge/values/ValueType;
public fun getValue ()Ljava/lang/Object;
public fun hashCode ()I
@ -932,18 +949,17 @@ public final class hep/dataforge/values/True : hep/dataforge/values/Value {
public abstract interface class hep/dataforge/values/Value {
public static final field Companion Lhep/dataforge/values/Value$Companion;
public static final field TARGET Ljava/lang/String;
public static final field TYPE Ljava/lang/String;
public abstract fun equals (Ljava/lang/Object;)Z
public abstract fun getList ()Ljava/util/List;
public abstract fun getNumber ()Ljava/lang/Number;
public abstract fun getString ()Ljava/lang/String;
public abstract fun getType ()Lhep/dataforge/values/ValueType;
public abstract fun getValue ()Ljava/lang/Object;
public abstract fun hashCode ()I
public abstract fun toString ()Ljava/lang/String;
}
public final class hep/dataforge/values/Value$Companion {
public static final field TARGET Ljava/lang/String;
public static final field TYPE Ljava/lang/String;
public final fun of (Ljava/lang/Object;)Lhep/dataforge/values/Value;
}
@ -976,6 +992,9 @@ public final class hep/dataforge/values/ValueKt {
public static final fun asValue ([I)Lhep/dataforge/values/Value;
public static final fun asValue ([J)Lhep/dataforge/values/Value;
public static final fun asValue ([S)Lhep/dataforge/values/Value;
public static final fun getNumber (Lhep/dataforge/values/Value;)Ljava/lang/Number;
public static final fun getNumberOrNull (Lhep/dataforge/values/Value;)Ljava/lang/Number;
public static final fun getString (Lhep/dataforge/values/Value;)Ljava/lang/String;
public static final fun parseValue (Ljava/lang/String;)Lhep/dataforge/values/Value;
}
@ -991,6 +1010,7 @@ public final class hep/dataforge/values/ValueSerializer : kotlinx/serialization/
public final class hep/dataforge/values/ValueType : java/lang/Enum {
public static final field BOOLEAN Lhep/dataforge/values/ValueType;
public static final field Companion Lhep/dataforge/values/ValueType$Companion;
public static final field LIST Lhep/dataforge/values/ValueType;
public static final field NULL Lhep/dataforge/values/ValueType;
public static final field NUMBER Lhep/dataforge/values/ValueType;
public static final field STRING Lhep/dataforge/values/ValueType;
@ -1000,6 +1020,7 @@ public final class hep/dataforge/values/ValueType : java/lang/Enum {
public final class hep/dataforge/values/ValueType$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lhep/dataforge/values/ValueType$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lhep/dataforge/values/ValueType;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;

View File

@ -9,4 +9,8 @@ kscience {
}
}
description = "Meta definition and basic operations on meta"
description = "Meta definition and basic operations on meta"
readme{
maturity = ru.mipt.npm.gradle.Maturity.DEVELOPMENT
}

View File

@ -10,16 +10,17 @@ import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.collections.set
import kotlin.jvm.Synchronized
//TODO add validator to configuration
public data class MetaListener(
public data class ItemListener(
val owner: Any? = null,
val action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit
val action: (name: Name, oldItem: MetaItem?, newItem: MetaItem?) -> Unit
)
public interface ObservableMeta : Meta {
public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
public interface ObservableItemProvider : ItemProvider {
public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem?, newItem: MetaItem?) -> Unit)
public fun removeListener(owner: Any?)
}
@ -27,37 +28,40 @@ public interface ObservableMeta : Meta {
* Mutable meta representing object state
*/
@Serializable(Config.Companion::class)
public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
public class Config() : AbstractMutableMeta<Config>(), ObservableItemProvider {
private val listeners = HashSet<MetaListener>()
private val listeners = HashSet<ItemListener>()
private fun itemChanged(name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) {
@Synchronized
private fun itemChanged(name: Name, oldItem: MetaItem?, newItem: MetaItem?) {
listeners.forEach { it.action(name, oldItem, newItem) }
}
/**
* Add change listener to this meta. Owner is declared to be able to remove listeners later. Listener without owner could not be removed
*/
override fun onChange(owner: Any?, action: (Name, MetaItem<*>?, MetaItem<*>?) -> Unit) {
listeners.add(MetaListener(owner, action))
@Synchronized
override fun onChange(owner: Any?, action: (Name, MetaItem?, MetaItem?) -> Unit) {
listeners.add(ItemListener(owner, action))
}
/**
* Remove all listeners belonging to given owner
*/
@Synchronized
override fun removeListener(owner: Any?) {
listeners.removeAll { it.owner === owner }
}
override fun replaceItem(key: NameToken, oldItem: MetaItem<Config>?, newItem: MetaItem<Config>?) {
override fun replaceItem(key: NameToken, oldItem: TypedMetaItem<Config>?, newItem: TypedMetaItem<Config>?) {
if (newItem == null) {
children.remove(key)
if (oldItem != null && oldItem is MetaItem.NodeItem<Config>) {
if (oldItem != null && oldItem is MetaItemNode<Config>) {
oldItem.node.removeListener(this)
}
} else {
children[key] = newItem
if (newItem is MetaItem.NodeItem) {
if (newItem is MetaItemNode) {
newItem.node.onChange(this) { name, oldChild, newChild ->
itemChanged(key + name, oldChild, newChild)
}
@ -88,14 +92,23 @@ public class Config() : AbstractMutableMeta<Config>(), ObservableMeta {
}
}
public operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token]
public operator fun Config.get(token: NameToken): TypedMetaItem<Config>? = items[token]
public fun Meta.asConfig(): Config = this as? Config ?: Config().also { builder ->
/**
* Create a mutable copy of this [Meta]. The copy is created event if initial [Meta] is a [Config].
* Listeners are not preserved
*/
public fun Meta.toConfig(): Config = Config().also { builder ->
this.items.mapValues { entry ->
val item = entry.value
builder[entry.key.asName()] = when (item) {
is MetaItem.ValueItem -> item.value
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.asConfig())
is MetaItemValue -> item.value
is MetaItemNode -> MetaItemNode(item.node.asConfig())
}
}
}
}
/**
* Return this [Meta] as [Config] if it is [Config] and create a new copy otherwise
*/
public fun Meta.asConfig(): Config = this as? Config ?: toConfig()

View File

@ -1,5 +1,6 @@
package hep.dataforge.meta
import hep.dataforge.misc.DFBuilder
import hep.dataforge.names.Name
import kotlin.properties.ReadWriteProperty

View File

@ -8,10 +8,10 @@ import kotlin.properties.ReadOnlyProperty
/* Meta delegates */
public typealias ItemDelegate = ReadOnlyProperty<Any?, MetaItem<*>?>
public typealias ItemDelegate = ReadOnlyProperty<Any?, MetaItem?>
public fun ItemProvider.item(key: Name? = null): ItemDelegate = ReadOnlyProperty { _, property ->
getItem(key ?: property.name.asName())
get(key ?: property.name.asName())
}
//TODO add caching for sealed nodes
@ -40,7 +40,7 @@ public fun <R : Any> ItemDelegate.convert(
* A converter with a custom reader transformation
*/
public fun <R> ItemDelegate.convert(
reader: (MetaItem<*>?) -> R,
reader: (MetaItem?) -> R,
): ReadOnlyProperty<Any?, R> = ReadOnlyProperty<Any?, R> { thisRef, property ->
this@convert.getValue(thisRef, property).let(reader)
}

View File

@ -0,0 +1,88 @@
package hep.dataforge.meta
import hep.dataforge.names.*
public fun interface ItemProvider {
//getItem used instead of get in order to provide extension freedom
public fun getItem(name: Name): MetaItem?
public companion object {
public val EMPTY: ItemProvider = ItemProvider { null }
}
}
/* Get operations*/
/**
* Perform recursive item search using given [name]. Each [NameToken] is treated as a name in [Meta.items] of a parent node.
*
* If [name] is empty return current [Meta] as a [MetaItemNode]
*/
public operator fun ItemProvider?.get(name: Name): MetaItem? = this?.getItem(name)
/**
* Root item of this provider
*/
public val ItemProvider.rootItem: MetaItem? get() = get(Name.EMPTY)
/**
* The root node of this item provider if it is present
*/
public val ItemProvider.rootNode: Meta? get() = rootItem.node
/**
* Parse [Name] from [key] using full name notation and pass it to [Meta.get]
*/
public operator fun ItemProvider?.get(key: String): MetaItem? = this?.get(key.toName())
/**
* Create a provider that uses given provider for default values if those are not found in this provider
*/
public fun ItemProvider.withDefault(default: ItemProvider?): ItemProvider = if (default == null) {
this
} else {
ItemProvider {
this[it] ?: default[it]
}
}
/**
* Get all items matching given name. The index of the last element, if present is used as a [Regex],
* against which indexes of elements are matched.
*/
public fun ItemProvider.getIndexed(name: Name): Map<String?, MetaItem> {
val root: Meta = when (name.length) {
0 -> error("Can't use empty name for 'getIndexed'")
1 -> this.rootNode ?: return emptyMap()
else -> this[name.cutLast()].node ?: return emptyMap()
}
val (body, index) = name.lastOrNull()!!
return if (index == null) {
root.items.filter { it.key.body == body }.mapKeys { it.key.index }
} else {
val regex = index.toRegex()
root.items.filter { it.key.body == body && (regex.matches(it.key.index ?: "")) }
.mapKeys { it.key.index }
}
}
public fun ItemProvider.getIndexed(name: String): Map<String?, MetaItem> = this@getIndexed.getIndexed(name.toName())
/**
* Return a provider referencing a child node
*/
public fun ItemProvider.getChild(childName: Name): ItemProvider = get(childName).node ?: ItemProvider.EMPTY
public fun ItemProvider.getChild(childName: String): ItemProvider = getChild(childName.toName())
///**
// * Get all items matching given name.
// */
//@Suppress("UNCHECKED_CAST")
//public fun <M : TypedMeta<M>> M.getIndexed(name: Name): Map<String?, MetaItem<M>> =
// (this as Meta).getIndexed(name) as Map<String?, MetaItem<M>>
//
//public fun <M : TypedMeta<M>> M.getIndexed(name: String): Map<String?, MetaItem<M>> =
// getIndexed(name.toName())

View File

@ -16,21 +16,17 @@ import kotlinx.serialization.json.*
/**
* @param descriptor reserved for custom serialization in future
*/
public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
return if (isList()) {
JsonArray(list.map { it.toJson() })
} else {
when (type) {
ValueType.NUMBER -> JsonPrimitive(number)
ValueType.STRING -> JsonPrimitive(string)
ValueType.BOOLEAN -> JsonPrimitive(boolean)
ValueType.NULL -> JsonNull
}
}
public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement = when (type) {
ValueType.NUMBER -> JsonPrimitive(numberOrNull)
ValueType.STRING -> JsonPrimitive(string)
ValueType.BOOLEAN -> JsonPrimitive(boolean)
ValueType.LIST -> JsonArray(list.map { it.toJson() })
ValueType.NULL -> JsonNull
}
//Use these methods to customize JSON key mapping
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes["jsonName"].string ?: toString()
@Suppress("NULLABLE_EXTENSION_OPERATOR_WITH_SAFE_CALL_RECEIVER")
private fun String.toJsonKey(descriptor: ItemDescriptor?) = descriptor?.attributes?.get("jsonName").string ?: toString()
//private fun NodeDescriptor?.getDescriptor(key: String) = this?.items?.get(key)
@ -41,11 +37,11 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
val elementMap = HashMap<String, JsonElement>()
fun MetaItem<*>.toJsonElement(itemDescriptor: ItemDescriptor?, index: String?): JsonElement = when (this) {
is MetaItem.ValueItem -> {
fun MetaItem.toJsonElement(itemDescriptor: ItemDescriptor?, index: String?): JsonElement = when (this) {
is MetaItemValue -> {
value.toJson(itemDescriptor as? ValueDescriptor)
}
is MetaItem.NodeItem -> {
is MetaItemNode -> {
node.toJsonWithIndex(itemDescriptor as? NodeDescriptor, index)
}
}
@ -53,7 +49,7 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
fun addElement(key: String) {
val itemDescriptor = descriptor?.items?.get(key)
val jsonKey = key.toJsonKey(itemDescriptor)
val items: Map<String?, MetaItem<*>> = getIndexed(key)
val items: Map<String?, MetaItem> = getIndexed(key)
when (items.size) {
0 -> {
//do nothing
@ -100,14 +96,14 @@ public fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
}
}
public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): TypedMetaItem<JsonMeta> = when (this) {
is JsonPrimitive -> {
val value = this.toValue(descriptor as? ValueDescriptor)
MetaItem.ValueItem(value)
MetaItemValue(value)
}
is JsonObject -> {
val meta = JsonMeta(this, descriptor as? NodeDescriptor)
MetaItem.NodeItem(meta)
MetaItemNode(meta)
}
is JsonArray -> {
if (this.all { it is JsonPrimitive }) {
@ -119,7 +115,7 @@ public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<
(it as JsonPrimitive).toValue(descriptor as? ValueDescriptor)
}.asValue()
}
MetaItem.ValueItem(value)
MetaItemValue(value)
} else {
//We can't return multiple items therefore we create top level node
buildJsonObject { put(JSON_ARRAY_KEY, this@toMetaItem) }.toMetaItem(descriptor)
@ -132,18 +128,18 @@ public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<
*/
public class JsonMeta(private val json: JsonObject, private val descriptor: NodeDescriptor? = null) : MetaBase() {
private fun buildItems(): Map<NameToken, MetaItem<JsonMeta>> {
val map = LinkedHashMap<NameToken, MetaItem<JsonMeta>>()
private fun buildItems(): Map<NameToken, TypedMetaItem<JsonMeta>> {
val map = LinkedHashMap<NameToken, TypedMetaItem<JsonMeta>>()
json.forEach { (jsonKey, value) ->
val key = NameToken(jsonKey)
val itemDescriptor = descriptor?.items?.get(jsonKey)
when (value) {
is JsonPrimitive -> {
map[key] = MetaItem.ValueItem(value.toValue(itemDescriptor as? ValueDescriptor))
map[key] = MetaItemValue(value.toValue(itemDescriptor as? ValueDescriptor))
}
is JsonObject -> {
map[key] = MetaItem.NodeItem(
map[key] = MetaItemNode(
JsonMeta(
value,
itemDescriptor as? NodeDescriptor
@ -157,7 +153,7 @@ public class JsonMeta(private val json: JsonObject, private val descriptor: Node
(it as JsonPrimitive).toValue(itemDescriptor as? ValueDescriptor)
}
)
map[key] = MetaItem.ValueItem(listValue)
map[key] = MetaItemValue(listValue)
} else value.forEachIndexed { index, jsonElement ->
val indexKey = (itemDescriptor as? NodeDescriptor)?.indexKey ?: DEFAULT_INDEX_KEY
val indexValue: String = (jsonElement as? JsonObject)
@ -172,7 +168,7 @@ public class JsonMeta(private val json: JsonObject, private val descriptor: Node
return map
}
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy(::buildItems)
override val items: Map<NameToken, TypedMetaItem<JsonMeta>> by lazy(::buildItems)
public companion object {
/**

View File

@ -17,7 +17,7 @@ public class Laminate(layers: List<Meta>) : MetaBase() {
}
}
override val items: Map<NameToken, MetaItem<Meta>> by lazy {
override val items: Map<NameToken, TypedMetaItem<Meta>> by lazy {
layers.map { it.items.keys }.flatten().associateWith { key ->
layers.asSequence().map { it.items[key] }.filterNotNull().let(replaceRule)
}
@ -40,15 +40,15 @@ public class Laminate(layers: List<Meta>) : MetaBase() {
*
* TODO add picture
*/
public val replaceRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.first().seal() }
public val replaceRule: (Sequence<MetaItem>) -> TypedMetaItem<SealedMeta> = { it.first().seal() }
private fun Sequence<MetaItem<*>>.merge(): MetaItem<SealedMeta> {
private fun Sequence<MetaItem>.merge(): TypedMetaItem<SealedMeta> {
return when {
all { it is MetaItem.ValueItem } -> //If all items are values, take first
all { it is MetaItemValue } -> //If all items are values, take first
first().seal()
all { it is MetaItem.NodeItem } -> {
all { it is MetaItemNode } -> {
//list nodes in item
val nodes = map { (it as MetaItem.NodeItem).node }
val nodes = map { (it as MetaItemNode).node }
//represent as key->value entries
val entries = nodes.flatMap { it.items.entries.asSequence() }
//group by keys
@ -57,13 +57,13 @@ public class Laminate(layers: List<Meta>) : MetaBase() {
val items = groups.mapValues { entry ->
entry.value.asSequence().map { it.value }.merge()
}
MetaItem.NodeItem(SealedMeta(items))
MetaItemNode(SealedMeta(items))
}
else -> map {
when (it) {
is MetaItem.ValueItem -> MetaItem.NodeItem(Meta { Meta.VALUE_KEY put it.value })
is MetaItem.NodeItem -> it
is MetaItemValue -> MetaItemNode(Meta { Meta.VALUE_KEY put it.value })
is MetaItemNode -> it
}
}.merge()
}
@ -74,7 +74,7 @@ public class Laminate(layers: List<Meta>) : MetaBase() {
* The values a replaced but meta children are joined
* TODO add picture
*/
public val mergeRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.merge() }
public val mergeRule: (Sequence<MetaItem>) -> TypedMetaItem<SealedMeta> = { it.merge() }
}
}
@ -84,7 +84,7 @@ public fun Laminate(vararg layers: Meta?): Laminate = Laminate(layers.filterNotN
/**
* Performance optimized version of get method
*/
public fun Laminate.getFirst(name: Name): MetaItem<*>? {
public fun Laminate.getFirst(name: Name): MetaItem? {
layers.forEach { layer ->
layer[name]?.let { return it }
}

View File

@ -1,67 +1,10 @@
package hep.dataforge.meta
import hep.dataforge.meta.Meta.Companion.VALUE_KEY
import hep.dataforge.meta.MetaItem.NodeItem
import hep.dataforge.meta.MetaItem.ValueItem
import hep.dataforge.names.*
import hep.dataforge.values.EnumValue
import hep.dataforge.values.Null
import hep.dataforge.values.Value
import hep.dataforge.values.boolean
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
/**
* A member of the meta tree. Could be represented as one of following:
* * a [ValueItem] (leaf)
* * a [NodeItem] (node)
*/
@Serializable(MetaItemSerializer::class)
public sealed class MetaItem<out M : Meta>() {
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
@Serializable(MetaItemSerializer::class)
public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean {
return this.value == (other as? ValueItem)?.value
}
override fun hashCode(): Int {
return value.hashCode()
}
}
@Serializable(MetaItemSerializer::class)
public class NodeItem<M : Meta>(public val node: M) : MetaItem<M>() {
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable
override fun toString(): String = node.toString()
override fun equals(other: Any?): Boolean = node == (other as? NodeItem<*>)?.node
override fun hashCode(): Int = node.hashCode()
}
public companion object {
public fun of(arg: Any?): MetaItem<*> {
return when (arg) {
null -> ValueItem(Null)
is MetaItem<*> -> arg
is Meta -> NodeItem(arg)
else -> ValueItem(Value.of(arg))
}
}
}
}
public fun Value.asMetaItem(): ValueItem = ValueItem(this)
public fun <M : Meta> M.asMetaItem(): NodeItem<M> = NodeItem(this)
/**
* The object that could be represented as [Meta]. Meta provided by [toMeta] method should fully represent object state.
* Meaning that two states with the same meta are equal.
@ -71,18 +14,10 @@ public interface MetaRepr {
public fun toMeta(): Meta
}
public fun interface ItemProvider {
public fun getItem(name: Name): MetaItem<*>?
public companion object {
public val EMPTY: ItemProvider = ItemProvider { null }
}
}
/**
* Generic meta tree representation. Elements are [MetaItem] objects that could be represented by three different entities:
* * [MetaItem.ValueItem] (leaf)
* * [MetaItem.NodeItem] single node
* Generic meta tree representation. Elements are [TypedMetaItem] objects that could be represented by three different entities:
* * [MetaItemValue] (leaf)
* * [MetaItemNode] single node
*
* * Same name siblings are supported via elements with the same [Name] but different queries
*/
@ -90,10 +25,10 @@ public interface Meta : MetaRepr, ItemProvider {
/**
* Top level items of meta tree
*/
public val items: Map<NameToken, MetaItem<*>>
public val items: Map<NameToken, MetaItem>
override fun getItem(name: Name): MetaItem<*>? {
if (name.isEmpty()) return NodeItem(this)
override fun getItem(name: Name): MetaItem? {
if (name.isEmpty()) return MetaItemNode(this)
return name.firstOrNull()?.let { token ->
val tail = name.cutFirst()
when (tail.length) {
@ -103,7 +38,7 @@ public interface Meta : MetaRepr, ItemProvider {
}
}
override fun toMeta(): Meta = seal()
override fun toMeta(): Meta = this
override fun equals(other: Any?): Boolean
@ -120,151 +55,39 @@ public interface Meta : MetaRepr, ItemProvider {
public const val VALUE_KEY: String = "@value"
public val EMPTY: Meta = object : MetaBase() {
override val items: Map<NameToken, MetaItem<*>> = emptyMap()
override val items: Map<NameToken, MetaItem> = emptyMap()
}
}
}
/* Get operations*/
/**
* Perform recursive item search using given [name]. Each [NameToken] is treated as a name in [Meta.items] of a parent node.
*
* If [name] is empty return current [Meta] as a [NodeItem]
*/
public operator fun Meta?.get(name: Name): MetaItem<*>? = this?.getItem(name)
public operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token)
/**
* Parse [Name] from [key] using full name notation and pass it to [Meta.get]
*/
public operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
public operator fun Meta.get(token: NameToken): MetaItem? = items.get(token)
/**
* Get a sequence of [Name]-[Value] pairs
*/
public fun Meta.values(): Sequence<Pair<Name, Value>> {
public fun Meta.valueSequence(): Sequence<Pair<Name, Value>> {
return items.asSequence().flatMap { (key, item) ->
when (item) {
is ValueItem -> sequenceOf(key.asName() to item.value)
is NodeItem -> item.node.values().map { pair -> (key.asName() + pair.first) to pair.second }
is MetaItemValue -> sequenceOf(key.asName() to item.value)
is MetaItemNode -> item.node.valueSequence().map { pair -> (key.asName() + pair.first) to pair.second }
}
}
}
/**
* Get a sequence of all [Name]-[MetaItem] pairs for all items including nodes
* Get a sequence of all [Name]-[TypedMetaItem] pairs for all items including nodes
*/
public fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
return sequence {
items.forEach { (key, item) ->
yield(key.asName() to item)
if (item is NodeItem<*>) {
yieldAll(item.node.sequence().map { (innerKey, innerItem) ->
(key + innerKey) to innerItem
})
}
public fun Meta.itemSequence(): Sequence<Pair<Name, MetaItem>> = sequence {
items.forEach { (key, item) ->
yield(key.asName() to item)
if (item is MetaItemNode) {
yieldAll(item.node.itemSequence().map { (innerKey, innerItem) ->
(key + innerKey) to innerItem
})
}
}
}
public operator fun Meta.iterator(): Iterator<Pair<Name, MetaItem<*>>> = sequence().iterator()
/**
* A meta node that ensures that all of its descendants has at least the same type
*/
public interface MetaNode<out M : MetaNode<M>> : Meta {
override val items: Map<NameToken, MetaItem<M>>
}
/**
* The same as [Meta.get], but with specific node type
*/
public operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if (this == null) {
null
} else {
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
(this as Meta).get(name) as MetaItem<M>? // Do not change
}
public operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
public operator fun <M : MetaNode<M>> M?.get(key: NameToken): MetaItem<M>? = this[key.asName()]
/**
* Equals, hashcode and to string for any meta
*/
public abstract class MetaBase : Meta {
override fun equals(other: Any?): Boolean = if (other is Meta) {
this.items == other.items
} else {
false
}
override fun hashCode(): Int = items.hashCode()
override fun toString(): String = Json {
prettyPrint = true
useArrayPolymorphism = true
}.encodeToString(MetaSerializer, this)
}
/**
* Equals and hash code implementation for meta node
*/
public abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase()
/**
* The meta implementation which is guaranteed to be immutable.
*
* If the argument is possibly mutable node, it is copied on creation
*/
public class SealedMeta internal constructor(
override val items: Map<NameToken, MetaItem<SealedMeta>>,
) : AbstractMetaNode<SealedMeta>()
/**
* Generate sealed node from [this]. If it is already sealed return it as is
*/
public fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
@Suppress("UNCHECKED_CAST")
public fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
is ValueItem -> this
is NodeItem -> NodeItem(node.seal())
}
/**
* Unsafe methods to access values and nodes directly from [MetaItem]
*/
public val MetaItem<*>?.value: Value?
get() = (this as? ValueItem)?.value
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
public val MetaItem<*>?.string: String? get() = value?.string
public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean
public val MetaItem<*>?.number: Number? get() = value?.number
public val MetaItem<*>?.double: Double? get() = number?.toDouble()
public val MetaItem<*>?.float: Float? get() = number?.toFloat()
public val MetaItem<*>?.int: Int? get() = number?.toInt()
public val MetaItem<*>?.long: Long? get() = number?.toLong()
public val MetaItem<*>?.short: Short? get() = number?.toShort()
public inline fun <reified E : Enum<E>> MetaItem<*>?.enum(): E? = if (this is ValueItem && this.value is EnumValue<*>) {
this.value.value as E
} else {
string?.let { enumValueOf<E>(it) }
}
public val MetaItem<*>.stringList: List<String>? get() = value?.list?.map { it.string }
public val <M : Meta> MetaItem<M>?.node: M?
get() = when (this) {
null -> null
is ValueItem -> null//error("Trying to interpret value meta item as node item")
is NodeItem -> node
}
public operator fun Meta.iterator(): Iterator<Pair<Name, MetaItem>> = itemSequence().iterator()
public fun Meta.isEmpty(): Boolean = this === Meta.EMPTY || this.items.isEmpty()

View File

@ -1,5 +1,6 @@
package hep.dataforge.meta
import hep.dataforge.misc.DFBuilder
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.values.EnumValue
@ -12,10 +13,10 @@ import kotlin.jvm.JvmName
*/
@DFBuilder
public class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
override fun wrapNode(meta: Meta): MetaBuilder = if (meta is MetaBuilder) meta else meta.builder()
override fun wrapNode(meta: Meta): MetaBuilder = if (meta is MetaBuilder) meta else meta.toMutableMeta()
override fun empty(): MetaBuilder = MetaBuilder()
public infix fun String.put(item: MetaItem<*>?) {
public infix fun String.put(item: MetaItem?) {
set(this, item)
}
@ -71,7 +72,7 @@ public class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
set(this,value.toList())
}
public infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) {
public inline infix fun String.put(metaBuilder: MetaBuilder.() -> Unit) {
this@MetaBuilder[this] = MetaBuilder().apply(metaBuilder)
}
@ -121,25 +122,20 @@ public class MetaBuilder : AbstractMutableMeta<MetaBuilder>() {
/**
* For safety, builder always copies the initial meta even if it is builder itself
*/
public fun Meta.builder(): MetaBuilder {
public fun Meta.toMutableMeta(): MetaBuilder {
return MetaBuilder().also { builder ->
items.mapValues { entry ->
val item = entry.value
builder[entry.key.asName()] = when (item) {
is MetaItem.ValueItem -> item.value
is MetaItem.NodeItem -> MetaItem.NodeItem(item.node.builder())
is MetaItemValue -> item.value
is MetaItemNode -> MetaItemNode(item.node.toMutableMeta())
}
}
}
}
/**
* Create a deep copy of this meta and apply builder to it
*/
public fun Meta.edit(builder: MetaBuilder.() -> Unit): MetaBuilder = builder().apply(builder)
/**
* Build a [MetaBuilder] using given transformation
*/
@Suppress("FunctionName")
public fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)
public inline fun Meta(builder: MetaBuilder.() -> Unit): MetaBuilder = MetaBuilder().apply(builder)

View File

@ -0,0 +1,90 @@
package hep.dataforge.meta
import hep.dataforge.values.*
import kotlinx.serialization.Serializable
/**
* A member of the meta tree. Could be represented as one of following:
* * a [MetaItemValue] (leaf)
* * a [MetaItemNode] (node)
*/
@Serializable(MetaItemSerializer::class)
public sealed class TypedMetaItem<out M : Meta>() {
abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int
public companion object {
public fun of(arg: Any?): MetaItem {
return when (arg) {
null -> Null.asMetaItem()
is MetaItem -> arg
is Meta -> arg.asMetaItem()
is ItemProvider -> arg.rootItem ?: Null.asMetaItem()
else -> Value.of(arg).asMetaItem()
}
}
}
}
public typealias MetaItem = TypedMetaItem<*>
@Serializable(MetaItemSerializer::class)
public class MetaItemValue(public val value: Value) : TypedMetaItem<Nothing>() {
override fun toString(): String = value.toString()
override fun equals(other: Any?): Boolean {
return this.value == (other as? MetaItemValue)?.value
}
override fun hashCode(): Int {
return value.hashCode()
}
}
@Serializable(MetaItemSerializer::class)
public class MetaItemNode<M : Meta>(public val node: M) : TypedMetaItem<M>() {
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializable
override fun toString(): String = node.toString()
override fun equals(other: Any?): Boolean = node == (other as? MetaItemNode<*>)?.node
override fun hashCode(): Int = node.hashCode()
}
public fun Value.asMetaItem(): MetaItemValue = MetaItemValue(this)
public fun <M : Meta> M.asMetaItem(): MetaItemNode<M> = MetaItemNode(this)
/**
* Unsafe methods to access values and nodes directly from [TypedMetaItem]
*/
public val MetaItem?.value: Value?
get() = (this as? MetaItemValue)?.value
?: (this?.node?.get(Meta.VALUE_KEY) as? MetaItemValue)?.value
public val MetaItem?.string: String? get() = value?.string
public val MetaItem?.boolean: Boolean? get() = value?.boolean
public val MetaItem?.number: Number? get() = value?.numberOrNull
public val MetaItem?.double: Double? get() = number?.toDouble()
public val MetaItem?.float: Float? get() = number?.toFloat()
public val MetaItem?.int: Int? get() = number?.toInt()
public val MetaItem?.long: Long? get() = number?.toLong()
public val MetaItem?.short: Short? get() = number?.toShort()
public inline fun <reified E : Enum<E>> MetaItem?.enum(): E? =
if (this is MetaItemValue && this.value is EnumValue<*>) {
this.value.value as E
} else {
string?.let { enumValueOf<E>(it) }
}
public val MetaItem.stringList: List<String>? get() = value?.list?.map { it.string }
public val <M : Meta> TypedMetaItem<M>?.node: M?
get() = when (this) {
null -> null
is MetaItemValue -> null//error("Trying to interpret value meta item as node item")
is MetaItemNode -> node
}

View File

@ -12,16 +12,15 @@ import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.JsonObject
@OptIn(ExperimentalSerializationApi::class)
public object MetaItemSerializer : KSerializer<MetaItem<*>> {
public object MetaItemSerializer : KSerializer<MetaItem> {
@OptIn(InternalSerializationApi::class)
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("hep.dataforge.meta.MetaItem") {
@OptIn(InternalSerializationApi::class, ExperimentalSerializationApi::class)
override val descriptor: SerialDescriptor = buildSerialDescriptor("MetaItem", PolymorphicKind.SEALED) {
element<Boolean>("isNode")
element("content", buildSerialDescriptor("MetaItem.content", PolymorphicKind.SEALED))
element("value", buildSerialDescriptor("MetaItem.value", SerialKind.CONTEXTUAL))
}
override fun deserialize(decoder: Decoder): MetaItem<*> {
override fun deserialize(decoder: Decoder): MetaItem {
decoder.decodeStructure(descriptor) {
//Force strict serialization order
require(decodeElementIndex(descriptor) == 0) { "Node flag must be first item serialized" }
@ -37,12 +36,12 @@ public object MetaItemSerializer : KSerializer<MetaItem<*>> {
}
}
override fun serialize(encoder: Encoder, value: MetaItem<*>) {
override fun serialize(encoder: Encoder, value: MetaItem) {
encoder.encodeStructure(descriptor) {
encodeBooleanElement(descriptor, 0, value is MetaItem.NodeItem)
encodeBooleanElement(descriptor, 0, value is MetaItemNode)
when (value) {
is MetaItem.ValueItem -> encodeSerializableElement(descriptor, 1, ValueSerializer, value.value)
is MetaItem.NodeItem -> encodeSerializableElement(descriptor, 1, MetaSerializer, value.node)
is MetaItemValue -> encodeSerializableElement(descriptor, 1, ValueSerializer, value.value)
is MetaItemNode -> encodeSerializableElement(descriptor, 1, MetaSerializer, value.node)
}
}
}
@ -53,19 +52,19 @@ public object MetaItemSerializer : KSerializer<MetaItem<*>> {
*/
public object MetaSerializer : KSerializer<Meta> {
private val mapSerializer: KSerializer<Map<NameToken, MetaItem<Meta>>> = MapSerializer(
private val mapSerializer: KSerializer<Map<NameToken, TypedMetaItem<Meta>>> = MapSerializer(
NameToken,
MetaItemSerializer//MetaItem.serializer(MetaSerializer)
)
override val descriptor: SerialDescriptor get() = mapSerializer.descriptor
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Meta")
override fun deserialize(decoder: Decoder): Meta {
return if (decoder is JsonDecoder) {
JsonObject.serializer().deserialize(decoder).toMeta()
} else {
object : MetaBase() {
override val items: Map<NameToken, MetaItem<*>> = mapSerializer.deserialize(decoder)
override val items: Map<NameToken, MetaItem> = mapSerializer.deserialize(decoder)
}
}
}

View File

@ -1,18 +0,0 @@
package hep.dataforge.meta
import hep.dataforge.names.Name
import hep.dataforge.names.NameToken
/**
* Meta object with default provider for items not present in the initial meta.
*/
public class MetaWithDefault(public val meta: Meta, public val default: ItemProvider) : MetaBase() {
override val items: Map<NameToken, MetaItem<*>>
get() = meta.items
override fun getItem(name: Name): MetaItem<*>? {
return meta[name] ?: default.getItem(name)
}
}
public fun Meta.withDefault(default: ItemProvider): MetaWithDefault = MetaWithDefault(this, default)

View File

@ -3,32 +3,29 @@ package hep.dataforge.meta
import hep.dataforge.meta.transformations.MetaConverter
import hep.dataforge.names.Name
import hep.dataforge.names.asName
import hep.dataforge.values.DoubleArrayValue
import hep.dataforge.values.Value
import hep.dataforge.values.asValue
import hep.dataforge.values.doubleArray
import hep.dataforge.values.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
/* Read-write delegates */
public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem<*>?>
public typealias MutableItemDelegate = ReadWriteProperty<Any?, MetaItem?>
public fun MutableItemProvider.item(key: Name? = null): MutableItemDelegate = object : MutableItemDelegate {
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem<*>? {
return getItem(key ?: property.name.asName())
override fun getValue(thisRef: Any?, property: KProperty<*>): MetaItem? {
return get(key ?: property.name.asName())
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem<*>?) {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: MetaItem?) {
val name = key ?: property.name.asName()
setItem(name, value)
set(name, value)
}
}
/* Mutable converters */
/**
* A type converter for a mutable [MetaItem] delegate
* A type converter for a mutable [TypedMetaItem] delegate
*/
public fun <R : Any> MutableItemDelegate.convert(
converter: MetaConverter<R>,
@ -58,8 +55,8 @@ public fun <R : Any> MutableItemDelegate.convert(
}
public fun <R> MutableItemDelegate.convert(
reader: (MetaItem<*>?) -> R,
writer: (R) -> MetaItem<*>?,
reader: (MetaItem?) -> R,
writer: (R) -> MetaItem?,
): ReadWriteProperty<Any?, R> = object : ReadWriteProperty<Any?, R> {
override fun getValue(thisRef: Any?, property: KProperty<*>): R =
@ -72,7 +69,6 @@ public fun <R> MutableItemDelegate.convert(
}
/* Read-write delegates for [MutableItemProvider] */
/**
@ -117,8 +113,13 @@ public inline fun <reified E : Enum<E>> MutableItemProvider.enum(
): ReadWriteProperty<Any?, E> =
item(key).convert(MetaConverter.enum()) { default }
public fun MutableItemProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).convert(
reader = { it.node },
writer = { it?.asMetaItem() }
)
public inline fun <reified M : MutableMeta<M>> M.node(key: Name? = null): ReadWriteProperty<Any?, M?> =
item(key).convert(reader = { it?.let { it.node as M } }, writer = { it?.let { MetaItem.NodeItem(it) } })
item(key).convert(reader = { it?.let { it.node as M } }, writer = { it?.let { MetaItemNode(it) } })
/* Number delegates */
@ -171,7 +172,7 @@ public fun MutableItemProvider.numberList(
vararg default: Number,
key: Name? = null,
): ReadWriteProperty<Any?, List<Number>> = item(key).convert(
reader = { it?.value?.list?.map { value -> value.number } ?: listOf(*default) },
reader = { it?.value?.list?.map { value -> value.numberOrNull ?: Double.NaN } ?: listOf(*default) },
writer = { it.map { num -> num.asValue() }.asValue().asMetaItem() }
)

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